<commit_before>/*************************************************************************/
/*  dir_access_unix.cpp                                                  */
/*************************************************************************/
/*                       This file is part of:                           */
/*                           GODOT ENGINE                                */
/*                      https://godotengine.org                          */
/*************************************************************************/
/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur.                 */
/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md)    */
/*                                                                       */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the       */
/* "Software"), to deal in the Software without restriction, including   */
/* without limitation the rights to use, copy, modify, merge, publish,   */
/* distribute, sublicense, and/or sell copies of the Software, and to    */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions:                                             */
/*                                                                       */
/* The above copyright notice and this permission notice shall be        */
/* included in all copies or substantial portions of the Software.       */
/*                                                                       */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
/*************************************************************************/

#include "dir_access_unix.h"

#if defined(UNIX_ENABLED) || defined(LIBC_FILEIO_ENABLED)

#include "core/list.h"
#include "core/os/memory.h"
#include "core/print_string.h"

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifndef ANDROID_ENABLED
#include <sys/statvfs.h>
#endif

#ifdef HAVE_MNTENT
#include <mntent.h>
#endif

DirAccess *DirAccessUnix::create_fs() {

	return memnew(DirAccessUnix);
}

Error DirAccessUnix::list_dir_begin() {

	list_dir_end(); //close any previous dir opening!

	//char real_current_dir_name[2048]; //is this enough?!
	//getcwd(real_current_dir_name,2048);
	//chdir(current_path.utf8().get_data());
	dir_stream = opendir(current_dir.utf8().get_data());
	//chdir(real_current_dir_name);
	if (!dir_stream)
		return ERR_CANT_OPEN; //error!

	return OK;
}

bool DirAccessUnix::file_exists(String p_file) {

	GLOBAL_LOCK_FUNCTION

	if (p_file.is_rel_path())
		p_file = current_dir.plus_file(p_file);

	p_file = fix_path(p_file);

	struct stat flags;
	bool success = (stat(p_file.utf8().get_data(), &flags) == 0);

	if (success && S_ISDIR(flags.st_mode)) {
		success = false;
	}

	return success;
}

bool DirAccessUnix::dir_exists(String p_dir) {

	GLOBAL_LOCK_FUNCTION

	if (p_dir.is_rel_path())
		p_dir = get_current_dir().plus_file(p_dir);

	p_dir = fix_path(p_dir);

	struct stat flags;
	bool success = (stat(p_dir.utf8().get_data(), &flags) == 0);

	return (success && S_ISDIR(flags.st_mode));
}

uint64_t DirAccessUnix::get_modified_time(String p_file) {

	if (p_file.is_rel_path())
		p_file = current_dir.plus_file(p_file);

	p_file = fix_path(p_file);

	struct stat flags;
	bool success = (stat(p_file.utf8().get_data(), &flags) == 0);

	if (success) {
		return flags.st_mtime;
	} else {

		ERR_FAIL_V(0);
	};
	return 0;
};

String DirAccessUnix::get_next() {

	if (!dir_stream)
		return "";
	dirent *entry;

	entry = readdir(dir_stream);

	if (entry == NULL) {

		list_dir_end();
		return "";
	}

	//typedef struct stat Stat;
	struct stat flags;

	String fname = fix_unicode_name(entry->d_name);

	String f = current_dir.plus_file(fname);

	if (stat(f.utf8().get_data(), &flags) == 0) {

		if (S_ISDIR(flags.st_mode)) {

			_cisdir = true;

		} else {

			_cisdir = false;
		}

	} else {

		_cisdir = false;
	}

	_cishidden = (fname != "." && fname != ".." && fname.begins_with("."));

	return fname;
}

bool DirAccessUnix::current_is_dir() const {

	return _cisdir;
}

bool DirAccessUnix::current_is_hidden() const {

	return _cishidden;
}

void DirAccessUnix::list_dir_end() {

	if (dir_stream)
		closedir(dir_stream);
	dir_stream = 0;
	_cisdir = false;
}

#if defined(HAVE_MNTENT) && defined(X11_ENABLED)
static bool _filter_drive(struct mntent *mnt) {
	// Ignore devices that don't point to /dev
	if (strncmp(mnt->mnt_fsname, "/dev", 4) != 0) {
		return false;
	}

	// Accept devices mounted at common locations
	if (strncmp(mnt->mnt_dir, "/media", 6) == 0 ||
			strncmp(mnt->mnt_dir, "/mnt", 4) == 0 ||
			strncmp(mnt->mnt_dir, "/home", 5) == 0 ||
			strncmp(mnt->mnt_dir, "/run/media", 10) == 0) {
		return true;
	}

	// Ignore everything else
	return false;
}
#endif

static void _get_drives(List<String> *list) {

#if defined(HAVE_MNTENT) && defined(X11_ENABLED)
	// Check /etc/mtab for the list of mounted partitions
	FILE *mtab = setmntent("/etc/mtab", "r");
	if (mtab) {
		struct mntent mnt;
		char strings[4096];

		while (getmntent_r(mtab, &mnt, strings, sizeof(strings))) {
			if (mnt.mnt_dir != NULL && _filter_drive(&mnt)) {
				// Avoid duplicates
				if (!list->find(mnt.mnt_dir)) {
					list->push_back(mnt.mnt_dir);
				}
			}
		}

		endmntent(mtab);
	}
#endif

	// Add $HOME
	const char *home = getenv("HOME");
	if (home) {
		// Only add if it's not a duplicate
		if (!list->find(home)) {
			list->push_back(home);
		}

		// Check $HOME/.config/gtk-3.0/bookmarks
		char path[1024];
		snprintf(path, 1024, "%s/.config/gtk-3.0/bookmarks", home);
		FILE *fd = fopen(path, "r");
		if (fd) {
			char string[1024];
			while (fgets(string, 1024, fd)) {
				// Parse only file:// links
				if (strncmp(string, "file://", 7) == 0) {
					// Strip any unwanted edges on the strings and push_back if it's not a duplicate
					String fpath = String(string + 7).strip_edges().split_spaces()[0].percent_decode();
					if (!list->find(fpath)) {
						list->push_back(fpath);
					}
				}
			}

			fclose(fd);
		}
	}

	list->sort();
}

int DirAccessUnix::get_drive_count() {

	List<String> list;
	_get_drives(&list);

	return list.size();
}

String DirAccessUnix::get_drive(int p_drive) {

	List<String> list;
	_get_drives(&list);

	ERR_FAIL_INDEX_V(p_drive, list.size(), "");

	return list[p_drive];
}

Error DirAccessUnix::make_dir(String p_dir) {

	GLOBAL_LOCK_FUNCTION

	if (p_dir.is_rel_path())
		p_dir = get_current_dir().plus_file(p_dir);

	p_dir = fix_path(p_dir);

	bool success = (mkdir(p_dir.utf8().get_data(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) == 0);
	int err = errno;

	if (success) {
		return OK;
	};

	if (err == EEXIST) {
		return ERR_ALREADY_EXISTS;
	};

	return ERR_CANT_CREATE;
}

Error DirAccessUnix::change_dir(String p_dir) {

	GLOBAL_LOCK_FUNCTION

	p_dir = fix_path(p_dir);

	// prev_dir is the directory we are changing out of
	String prev_dir;
	char real_current_dir_name[2048];
	ERR_FAIL_COND_V(getcwd(real_current_dir_name, 2048) == NULL, ERR_BUG);
	if (prev_dir.parse_utf8(real_current_dir_name))
		prev_dir = real_current_dir_name; //no utf8, maybe latin?

	// try_dir is the directory we are trying to change into
	String try_dir = "";
	if (p_dir.is_rel_path()) {
		String next_dir = current_dir.plus_file(p_dir);
		next_dir = next_dir.simplify_path();
		try_dir = next_dir;
	} else {
		try_dir = p_dir;
	}

	bool worked = (chdir(try_dir.utf8().get_data()) == 0); // we can only give this utf8
	if (!worked) {
		return ERR_INVALID_PARAMETER;
	}

	String base = _get_root_path();
	if (base != String() && !try_dir.begins_with(base)) {
		ERR_FAIL_COND_V(getcwd(real_current_dir_name, 2048) == NULL, ERR_BUG);
		String new_dir;
		new_dir.parse_utf8(real_current_dir_name);

		if (!new_dir.begins_with(base)) {
			try_dir = current_dir; //revert
		}
	}

	// the directory exists, so set current_dir to try_dir
	current_dir = try_dir;
	ERR_FAIL_COND_V(chdir(prev_dir.utf8().get_data()) != 0, ERR_BUG);
	return OK;
}

String DirAccessUnix::get_current_dir() {

	String base = _get_root_path();
	if (base != "") {

		String bd = current_dir.replace_first(base, "");
		if (bd.begins_with("/"))
			return _get_root_string() + bd.substr(1, bd.length());
		else
			return _get_root_string() + bd;
	}
	return current_dir;
}

Error DirAccessUnix::rename(String p_path, String p_new_path) {

	if (p_path.is_rel_path())
		p_path = get_current_dir().plus_file(p_path);

	p_path = fix_path(p_path);

	if (p_new_path.is_rel_path())
		p_new_path = get_current_dir().plus_file(p_new_path);

	p_new_path = fix_path(p_new_path);

	return ::rename(p_path.utf8().get_data(), p_new_path.utf8().get_data()) == 0 ? OK : FAILED;
}

Error DirAccessUnix::remove(String p_path) {

	if (p_path.is_rel_path())
		p_path = get_current_dir().plus_file(p_path);

	p_path = fix_path(p_path);

	struct stat flags;
	if ((stat(p_path.utf8().get_data(), &flags) != 0))
		return FAILED;

	if (S_ISDIR(flags.st_mode))
		return ::rmdir(p_path.utf8().get_data()) == 0 ? OK : FAILED;
	else
		return ::unlink(p_path.utf8().get_data()) == 0 ? OK : FAILED;
}

size_t DirAccessUnix::get_space_left() {

#ifndef NO_STATVFS
	struct statvfs vfs;
	if (statvfs(current_dir.utf8().get_data(), &vfs) != 0) {

		return 0;
	};

	return vfs.f_bfree * vfs.f_bsize;
#else
	// FIXME: Implement this.
	return 0;
#endif
};

String DirAccessUnix::get_filesystem_type() const {
	return ""; //TODO this should be implemented
}

DirAccessUnix::DirAccessUnix() {

	dir_stream = 0;
	_cisdir = false;

	/* determine drive count */

	// set current directory to an absolute path of the current directory
	char real_current_dir_name[2048];
	ERR_FAIL_COND(getcwd(real_current_dir_name, 2048) == NULL);
	if (current_dir.parse_utf8(real_current_dir_name))
		current_dir = real_current_dir_name;

	change_dir(current_dir);
}

DirAccessUnix::~DirAccessUnix() {

	list_dir_end();
}

#endif //posix_enabled
<commit_msg>Optimize DirAccessUnix::get_next() for some file systems<commit_after>/*************************************************************************/
/*  dir_access_unix.cpp                                                  */
/*************************************************************************/
/*                       This file is part of:                           */
/*                           GODOT ENGINE                                */
/*                      https://godotengine.org                          */
/*************************************************************************/
/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur.                 */
/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md)    */
/*                                                                       */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the       */
/* "Software"), to deal in the Software without restriction, including   */
/* without limitation the rights to use, copy, modify, merge, publish,   */
/* distribute, sublicense, and/or sell copies of the Software, and to    */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions:                                             */
/*                                                                       */
/* The above copyright notice and this permission notice shall be        */
/* included in all copies or substantial portions of the Software.       */
/*                                                                       */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
/*************************************************************************/

#include "dir_access_unix.h"

#if defined(UNIX_ENABLED) || defined(LIBC_FILEIO_ENABLED)

#include "core/list.h"
#include "core/os/memory.h"
#include "core/print_string.h"

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifndef ANDROID_ENABLED
#include <sys/statvfs.h>
#endif

#ifdef HAVE_MNTENT
#include <mntent.h>
#endif

DirAccess *DirAccessUnix::create_fs() {

	return memnew(DirAccessUnix);
}

Error DirAccessUnix::list_dir_begin() {

	list_dir_end(); //close any previous dir opening!

	//char real_current_dir_name[2048]; //is this enough?!
	//getcwd(real_current_dir_name,2048);
	//chdir(current_path.utf8().get_data());
	dir_stream = opendir(current_dir.utf8().get_data());
	//chdir(real_current_dir_name);
	if (!dir_stream)
		return ERR_CANT_OPEN; //error!

	return OK;
}

bool DirAccessUnix::file_exists(String p_file) {

	GLOBAL_LOCK_FUNCTION

	if (p_file.is_rel_path())
		p_file = current_dir.plus_file(p_file);

	p_file = fix_path(p_file);

	struct stat flags;
	bool success = (stat(p_file.utf8().get_data(), &flags) == 0);

	if (success && S_ISDIR(flags.st_mode)) {
		success = false;
	}

	return success;
}

bool DirAccessUnix::dir_exists(String p_dir) {

	GLOBAL_LOCK_FUNCTION

	if (p_dir.is_rel_path())
		p_dir = get_current_dir().plus_file(p_dir);

	p_dir = fix_path(p_dir);

	struct stat flags;
	bool success = (stat(p_dir.utf8().get_data(), &flags) == 0);

	return (success && S_ISDIR(flags.st_mode));
}

uint64_t DirAccessUnix::get_modified_time(String p_file) {

	if (p_file.is_rel_path())
		p_file = current_dir.plus_file(p_file);

	p_file = fix_path(p_file);

	struct stat flags;
	bool success = (stat(p_file.utf8().get_data(), &flags) == 0);

	if (success) {
		return flags.st_mtime;
	} else {

		ERR_FAIL_V(0);
	};
	return 0;
};

String DirAccessUnix::get_next() {

	if (!dir_stream)
		return "";
	dirent *entry;

	entry = readdir(dir_stream);

	if (entry == NULL) {

		list_dir_end();
		return "";
	}

	String fname = fix_unicode_name(entry->d_name);

	if (entry->d_type == DT_UNKNOWN) {
		//typedef struct stat Stat;
		struct stat flags;

		String f = current_dir.plus_file(fname);

		if (stat(f.utf8().get_data(), &flags) == 0) {

			if (S_ISDIR(flags.st_mode)) {

				_cisdir = true;

			} else {

				_cisdir = false;
			}

		} else {

			_cisdir = false;
		}
	} else {
		_cisdir = (entry->d_type == DT_DIR);
	}

	_cishidden = (fname != "." && fname != ".." && fname.begins_with("."));

	return fname;
}

bool DirAccessUnix::current_is_dir() const {

	return _cisdir;
}

bool DirAccessUnix::current_is_hidden() const {

	return _cishidden;
}

void DirAccessUnix::list_dir_end() {

	if (dir_stream)
		closedir(dir_stream);
	dir_stream = 0;
	_cisdir = false;
}

#if defined(HAVE_MNTENT) && defined(X11_ENABLED)
static bool _filter_drive(struct mntent *mnt) {
	// Ignore devices that don't point to /dev
	if (strncmp(mnt->mnt_fsname, "/dev", 4) != 0) {
		return false;
	}

	// Accept devices mounted at common locations
	if (strncmp(mnt->mnt_dir, "/media", 6) == 0 ||
			strncmp(mnt->mnt_dir, "/mnt", 4) == 0 ||
			strncmp(mnt->mnt_dir, "/home", 5) == 0 ||
			strncmp(mnt->mnt_dir, "/run/media", 10) == 0) {
		return true;
	}

	// Ignore everything else
	return false;
}
#endif

static void _get_drives(List<String> *list) {

#if defined(HAVE_MNTENT) && defined(X11_ENABLED)
	// Check /etc/mtab for the list of mounted partitions
	FILE *mtab = setmntent("/etc/mtab", "r");
	if (mtab) {
		struct mntent mnt;
		char strings[4096];

		while (getmntent_r(mtab, &mnt, strings, sizeof(strings))) {
			if (mnt.mnt_dir != NULL && _filter_drive(&mnt)) {
				// Avoid duplicates
				if (!list->find(mnt.mnt_dir)) {
					list->push_back(mnt.mnt_dir);
				}
			}
		}

		endmntent(mtab);
	}
#endif

	// Add $HOME
	const char *home = getenv("HOME");
	if (home) {
		// Only add if it's not a duplicate
		if (!list->find(home)) {
			list->push_back(home);
		}

		// Check $HOME/.config/gtk-3.0/bookmarks
		char path[1024];
		snprintf(path, 1024, "%s/.config/gtk-3.0/bookmarks", home);
		FILE *fd = fopen(path, "r");
		if (fd) {
			char string[1024];
			while (fgets(string, 1024, fd)) {
				// Parse only file:// links
				if (strncmp(string, "file://", 7) == 0) {
					// Strip any unwanted edges on the strings and push_back if it's not a duplicate
					String fpath = String(string + 7).strip_edges().split_spaces()[0].percent_decode();
					if (!list->find(fpath)) {
						list->push_back(fpath);
					}
				}
			}

			fclose(fd);
		}
	}

	list->sort();
}

int DirAccessUnix::get_drive_count() {

	List<String> list;
	_get_drives(&list);

	return list.size();
}

String DirAccessUnix::get_drive(int p_drive) {

	List<String> list;
	_get_drives(&list);

	ERR_FAIL_INDEX_V(p_drive, list.size(), "");

	return list[p_drive];
}

Error DirAccessUnix::make_dir(String p_dir) {

	GLOBAL_LOCK_FUNCTION

	if (p_dir.is_rel_path())
		p_dir = get_current_dir().plus_file(p_dir);

	p_dir = fix_path(p_dir);

	bool success = (mkdir(p_dir.utf8().get_data(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) == 0);
	int err = errno;

	if (success) {
		return OK;
	};

	if (err == EEXIST) {
		return ERR_ALREADY_EXISTS;
	};

	return ERR_CANT_CREATE;
}

Error DirAccessUnix::change_dir(String p_dir) {

	GLOBAL_LOCK_FUNCTION

	p_dir = fix_path(p_dir);

	// prev_dir is the directory we are changing out of
	String prev_dir;
	char real_current_dir_name[2048];
	ERR_FAIL_COND_V(getcwd(real_current_dir_name, 2048) == NULL, ERR_BUG);
	if (prev_dir.parse_utf8(real_current_dir_name))
		prev_dir = real_current_dir_name; //no utf8, maybe latin?

	// try_dir is the directory we are trying to change into
	String try_dir = "";
	if (p_dir.is_rel_path()) {
		String next_dir = current_dir.plus_file(p_dir);
		next_dir = next_dir.simplify_path();
		try_dir = next_dir;
	} else {
		try_dir = p_dir;
	}

	bool worked = (chdir(try_dir.utf8().get_data()) == 0); // we can only give this utf8
	if (!worked) {
		return ERR_INVALID_PARAMETER;
	}

	String base = _get_root_path();
	if (base != String() && !try_dir.begins_with(base)) {
		ERR_FAIL_COND_V(getcwd(real_current_dir_name, 2048) == NULL, ERR_BUG);
		String new_dir;
		new_dir.parse_utf8(real_current_dir_name);

		if (!new_dir.begins_with(base)) {
			try_dir = current_dir; //revert
		}
	}

	// the directory exists, so set current_dir to try_dir
	current_dir = try_dir;
	ERR_FAIL_COND_V(chdir(prev_dir.utf8().get_data()) != 0, ERR_BUG);
	return OK;
}

String DirAccessUnix::get_current_dir() {

	String base = _get_root_path();
	if (base != "") {

		String bd = current_dir.replace_first(base, "");
		if (bd.begins_with("/"))
			return _get_root_string() + bd.substr(1, bd.length());
		else
			return _get_root_string() + bd;
	}
	return current_dir;
}

Error DirAccessUnix::rename(String p_path, String p_new_path) {

	if (p_path.is_rel_path())
		p_path = get_current_dir().plus_file(p_path);

	p_path = fix_path(p_path);

	if (p_new_path.is_rel_path())
		p_new_path = get_current_dir().plus_file(p_new_path);

	p_new_path = fix_path(p_new_path);

	return ::rename(p_path.utf8().get_data(), p_new_path.utf8().get_data()) == 0 ? OK : FAILED;
}

Error DirAccessUnix::remove(String p_path) {

	if (p_path.is_rel_path())
		p_path = get_current_dir().plus_file(p_path);

	p_path = fix_path(p_path);

	struct stat flags;
	if ((stat(p_path.utf8().get_data(), &flags) != 0))
		return FAILED;

	if (S_ISDIR(flags.st_mode))
		return ::rmdir(p_path.utf8().get_data()) == 0 ? OK : FAILED;
	else
		return ::unlink(p_path.utf8().get_data()) == 0 ? OK : FAILED;
}

size_t DirAccessUnix::get_space_left() {

#ifndef NO_STATVFS
	struct statvfs vfs;
	if (statvfs(current_dir.utf8().get_data(), &vfs) != 0) {

		return 0;
	};

	return vfs.f_bfree * vfs.f_bsize;
#else
	// FIXME: Implement this.
	return 0;
#endif
};

String DirAccessUnix::get_filesystem_type() const {
	return ""; //TODO this should be implemented
}

DirAccessUnix::DirAccessUnix() {

	dir_stream = 0;
	_cisdir = false;

	/* determine drive count */

	// set current directory to an absolute path of the current directory
	char real_current_dir_name[2048];
	ERR_FAIL_COND(getcwd(real_current_dir_name, 2048) == NULL);
	if (current_dir.parse_utf8(real_current_dir_name))
		current_dir = real_current_dir_name;

	change_dir(current_dir);
}

DirAccessUnix::~DirAccessUnix() {

	list_dir_end();
}

#endif //posix_enabled
<|endoftext|>


<commit_before>#line 2 "togo/traits.hpp"
/**
@copyright MIT license; see @ref index or the accompanying LICENSE file.

@file
@brief Type traits.
@ingroup utility
*/

#pragma once

#include <togo/config.hpp>

namespace togo {

/**
	@addtogroup utility
	@{
*/

/** @name Type traits */ /// @{

/// Type with static constexpr value equal to false.
struct false_type {
	static constexpr bool const value = false;
};

/// Type with static constexpr value equal to true.
struct true_type {
	static constexpr bool const value = true;
};

/** @cond INTERNAL */
namespace {
	template<bool, class>
	struct enable_if_impl;

	template<class T>
	struct enable_if_impl<false, T> {};

	template<class T>
	struct enable_if_impl<true, T> {
		using type = T;
	};
} // anonymous namespace
/** @endcond */ // INTERNAL

/// SFINAE enabler type alias.
template<bool C, class T = void>
using enable_if = typename enable_if_impl<C, T>::type;

namespace {

template<class T>
struct remove_ref_impl {
	using type = T;
};

template<class T>
struct remove_ref_impl<T&> {
	using type = T;
};

} // anonymous namespace

/// Remove reference qualification from type.
template<class T>
using remove_ref = typename remove_ref_impl<T>::type;

namespace {

template<class T>
struct remove_cv_impl {
	using type = T;
};

template<class T>
struct remove_cv_impl<T const> {
	using type = T;
};

template<class T>
struct remove_cv_impl<T volatile> {
	using type = T;
};

template<class T>
struct remove_cv_impl<T const volatile> {
	using type = T;
};

} // anonymous namespace

/// Remove const, volatile, and reference qualifications from type.
template<class T>
using remove_cv = typename remove_cv_impl<T>::type;

/// Remove const, volatile, and reference qualifications from type.
template<class T>
using remove_cvr = typename remove_cv<remove_ref<T>>::type;

namespace {

template<class T>
struct is_signed_impl : false_type {};

template<> struct is_signed_impl<signed char> : true_type {};
template<> struct is_signed_impl<signed short> : true_type {};
template<> struct is_signed_impl<signed int> : true_type {};
template<> struct is_signed_impl<signed long> : true_type {};
template<> struct is_signed_impl<signed long long> : true_type {};

} // anonymous namespace

/// Type with static constexpr value equal to true if T is
/// a signed integral.
template<class T>
using is_signed = is_signed_impl<remove_cvr<T>>;

namespace {

template<class T>
struct is_unsigned_impl : false_type {};

template<> struct is_unsigned_impl<unsigned char> : true_type {};
template<> struct is_unsigned_impl<unsigned short> : true_type {};
template<> struct is_unsigned_impl<unsigned int> : true_type {};
template<> struct is_unsigned_impl<unsigned long> : true_type {};
template<> struct is_unsigned_impl<unsigned long long> : true_type {};

} // anonymous namespace

/// Type with static constexpr value equal to true if T is
/// an unsigned integral.
template<class T>
using is_unsigned = is_unsigned_impl<remove_cvr<T>>;

namespace {

template<class T, class U>
struct is_same_impl : false_type {};

template<class T>
struct is_same_impl<T, T> : true_type {};

} // anonymous namespace

/// Type with static constexpr value equal to true if T is
/// the same as U.
template<class T, class U>
using is_same = is_same_impl<T, U>;

/// @}

/// Enum-class bitwise operator enabler.
///
/// Specialize this class deriving from true_type to enable bit-wise
/// operators for an enum-class.
template<class>
struct enable_enum_bitwise_ops : false_type {};

/** @} */ // end of doc-group utility

} // namespace togo
<commit_msg>traits: added integral_constant<T, V>.<commit_after>#line 2 "togo/traits.hpp"
/**
@copyright MIT license; see @ref index or the accompanying LICENSE file.

@file
@brief Type traits.
@ingroup utility
*/

#pragma once

#include <togo/config.hpp>

namespace togo {

/**
	@addtogroup utility
	@{
*/

/** @name Type traits */ /// @{

/// Typed static constexpr integral value.
///
/// T must be an integral type.
template<class T, T V>
struct integral_constant {
	static constexpr T const value = V;
};

/// Type with static constexpr value equal to false.
struct false_type {
	static constexpr bool const value = false;
};

/// Type with static constexpr value equal to true.
struct true_type {
	static constexpr bool const value = true;
};

/** @cond INTERNAL */
namespace {
	template<bool, class>
	struct enable_if_impl;

	template<class T>
	struct enable_if_impl<false, T> {};

	template<class T>
	struct enable_if_impl<true, T> {
		using type = T;
	};
} // anonymous namespace
/** @endcond */ // INTERNAL

/// SFINAE enabler type alias.
template<bool C, class T = void>
using enable_if = typename enable_if_impl<C, T>::type;

namespace {

template<class T>
struct remove_ref_impl {
	using type = T;
};

template<class T>
struct remove_ref_impl<T&> {
	using type = T;
};

} // anonymous namespace

/// Remove reference qualification from type.
template<class T>
using remove_ref = typename remove_ref_impl<T>::type;

namespace {

template<class T>
struct remove_cv_impl {
	using type = T;
};

template<class T>
struct remove_cv_impl<T const> {
	using type = T;
};

template<class T>
struct remove_cv_impl<T volatile> {
	using type = T;
};

template<class T>
struct remove_cv_impl<T const volatile> {
	using type = T;
};

} // anonymous namespace

/// Remove const, volatile, and reference qualifications from type.
template<class T>
using remove_cv = typename remove_cv_impl<T>::type;

/// Remove const, volatile, and reference qualifications from type.
template<class T>
using remove_cvr = typename remove_cv<remove_ref<T>>::type;

namespace {

template<class T>
struct is_signed_impl : false_type {};

template<> struct is_signed_impl<signed char> : true_type {};
template<> struct is_signed_impl<signed short> : true_type {};
template<> struct is_signed_impl<signed int> : true_type {};
template<> struct is_signed_impl<signed long> : true_type {};
template<> struct is_signed_impl<signed long long> : true_type {};

} // anonymous namespace

/// Type with static constexpr value equal to true if T is
/// a signed integral.
template<class T>
using is_signed = is_signed_impl<remove_cvr<T>>;

namespace {

template<class T>
struct is_unsigned_impl : false_type {};

template<> struct is_unsigned_impl<unsigned char> : true_type {};
template<> struct is_unsigned_impl<unsigned short> : true_type {};
template<> struct is_unsigned_impl<unsigned int> : true_type {};
template<> struct is_unsigned_impl<unsigned long> : true_type {};
template<> struct is_unsigned_impl<unsigned long long> : true_type {};

} // anonymous namespace

/// Type with static constexpr value equal to true if T is
/// an unsigned integral.
template<class T>
using is_unsigned = is_unsigned_impl<remove_cvr<T>>;

namespace {

template<class T, class U>
struct is_same_impl : false_type {};

template<class T>
struct is_same_impl<T, T> : true_type {};

} // anonymous namespace

/// Type with static constexpr value equal to true if T is
/// the same as U.
template<class T, class U>
using is_same = is_same_impl<T, U>;

/// @}

/// Enum-class bitwise operator enabler.
///
/// Specialize this class deriving from true_type to enable bit-wise
/// operators for an enum-class.
template<class>
struct enable_enum_bitwise_ops : false_type {};

/** @} */ // end of doc-group utility

} // namespace togo
<|endoftext|>


<commit_before>// SwiftShader Software Renderer
//
// Copyright(c) 2005-2011 TransGaming Inc.
//
// All rights reserved. No part of this software may be copied, distributed, transmitted,
// transcribed, stored in a retrieval system, translated into any human or computer
// language by any means, or disclosed to third parties without the explicit written
// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
// or implied, including but not limited to any patent rights, are granted to you.
//

#ifndef sw_Config_hpp
#define sw_Config_hpp

#include "Common/Types.hpp"

#define PERF_HUD 0       // Display time spent on vertex, setup and pixel processing for each thread
#define PERF_PROFILE 0   // Profile various pipeline stages and display the timing in SwiftConfig
#define S3TC_SUPPORT 0

#if PERF_PROFILE
enum
{
	PERF_PIXEL,
	PERF_PIPE,
	PERF_INTERP,
	PERF_SHADER,
	PERF_TEX,
	PERF_ROP,

	PERF_TIMERS
};

struct Profiler
{
	Profiler();

	void reset();
	void nextFrame();

	int framesSec;
	int framesTotal;
	double FPS;
	double cycles[PERF_TIMERS];

	int64_t ropOperations;
	int64_t ropOperationsTotal;
	int64_t ropOperationsFrame;

	int64_t texOperations;
	int64_t texOperationsTotal;
	int64_t texOperationsFrame;

	int64_t compressedTex;
	int64_t compressedTexTotal;
	int64_t compressedTexFrame;
};

extern Profiler profiler;
#endif

enum
{
	OUTLINE_RESOLUTION = 4096,   // Maximum vertical resolution of the render target
	MIPMAP_LEVELS = 14
};

#endif   // sw_Config_hpp
<commit_msg>Enable S3TC texture formats on Windows.<commit_after>// SwiftShader Software Renderer
//
// Copyright(c) 2005-2011 TransGaming Inc.
//
// All rights reserved. No part of this software may be copied, distributed, transmitted,
// transcribed, stored in a retrieval system, translated into any human or computer
// language by any means, or disclosed to third parties without the explicit written
// agreement of TransGaming Inc. Without such an agreement, no rights or licenses, express
// or implied, including but not limited to any patent rights, are granted to you.
//

#ifndef sw_Config_hpp
#define sw_Config_hpp

#include "Common/Types.hpp"

#define PERF_HUD 0       // Display time spent on vertex, setup and pixel processing for each thread
#define PERF_PROFILE 0   // Profile various pipeline stages and display the timing in SwiftConfig
#define S3TC_SUPPORT (_WIN32)

#if PERF_PROFILE
enum
{
	PERF_PIXEL,
	PERF_PIPE,
	PERF_INTERP,
	PERF_SHADER,
	PERF_TEX,
	PERF_ROP,

	PERF_TIMERS
};

struct Profiler
{
	Profiler();

	void reset();
	void nextFrame();

	int framesSec;
	int framesTotal;
	double FPS;
	double cycles[PERF_TIMERS];

	int64_t ropOperations;
	int64_t ropOperationsTotal;
	int64_t ropOperationsFrame;

	int64_t texOperations;
	int64_t texOperationsTotal;
	int64_t texOperationsFrame;

	int64_t compressedTex;
	int64_t compressedTexTotal;
	int64_t compressedTexFrame;
};

extern Profiler profiler;
#endif

enum
{
	OUTLINE_RESOLUTION = 4096,   // Maximum vertical resolution of the render target
	MIPMAP_LEVELS = 14
};

#endif   // sw_Config_hpp
<|endoftext|>


<commit_before>
#include "Globals.h"  // NOTE: MSVC stupidness requires this to be the same across all modules

#include "Spider.h"

#include "../World.h"
#include "../Entities/Player.h"
#include "../Chunk.h"

cSpider::cSpider(void) :
	super("Spider", mtSpider, "entity.spider.hurt", "entity.spider.death", 1.4, 0.9)
{
}

void cSpider::GetDrops(cItems & a_Drops, cEntity * a_Killer)
{
	unsigned int LootingLevel = 0;
	if (a_Killer != nullptr)
	{
		LootingLevel = a_Killer->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchLooting);
	}
	AddRandomDropItem(a_Drops, 0, 2 + LootingLevel, E_ITEM_STRING);
	if ((a_Killer != nullptr) && (a_Killer->IsPlayer() || a_Killer->IsA("cWolf")))
	{
		AddRandomUncommonDropItem(a_Drops, 33.0f, E_ITEM_SPIDER_EYE);
	}
}

void cSpider::EventSeePlayer(cPlayer * a_Player, cChunk & a_Chunk)
{
	if (!GetWorld()->IsChunkLighted(GetChunkX(), GetChunkZ()))
	{
		return;
	}

	PREPARE_REL_AND_CHUNK(GetPosition(), a_Chunk);
	if (!RelSuccess)
	{
		return;
	}

	if (a_Player->CanMobsTarget() && (Chunk->GetSkyLightAltered(Rel.x, Rel.y, Rel.z) <= 9))
	{
		super::EventSeePlayer(a_Player, a_Chunk);
	}
}

bool cSpider::DoTakeDamage(TakeDamageInfo & a_TDI)
{
	if (!super::DoTakeDamage(a_TDI))
	{
		return false;
	}

	// If the source of the damage is not from an pawn entity, switch to idle
	if ((a_TDI.Attacker == nullptr) || !a_TDI.Attacker->IsPawn())
	{
		m_EMState = IDLE;
	}
	else
	{
		// If the source of the damage is from a pawn entity, chase that entity
		m_EMState = CHASING;
	}

	return true;
}
<commit_msg>Spider should attack only when the light level is lower than 11 (#3815)<commit_after>
#include "Globals.h"  // NOTE: MSVC stupidness requires this to be the same across all modules

#include "Spider.h"

#include "../World.h"
#include "../Entities/Player.h"
#include "../Chunk.h"

cSpider::cSpider(void) :
	super("Spider", mtSpider, "entity.spider.hurt", "entity.spider.death", 1.4, 0.9)
{
}

void cSpider::GetDrops(cItems & a_Drops, cEntity * a_Killer)
{
	unsigned int LootingLevel = 0;
	if (a_Killer != nullptr)
	{
		LootingLevel = a_Killer->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchLooting);
	}
	AddRandomDropItem(a_Drops, 0, 2 + LootingLevel, E_ITEM_STRING);
	if ((a_Killer != nullptr) && (a_Killer->IsPlayer() || a_Killer->IsA("cWolf")))
	{
		AddRandomUncommonDropItem(a_Drops, 33.0f, E_ITEM_SPIDER_EYE);
	}
}

void cSpider::EventSeePlayer(cPlayer * a_Player, cChunk & a_Chunk)
{
	if (!GetWorld()->IsChunkLighted(GetChunkX(), GetChunkZ()))
	{
		return;
	}

	PREPARE_REL_AND_CHUNK(GetPosition(), a_Chunk);
	if (!RelSuccess)
	{
		return;
	}

	if (
		a_Player->CanMobsTarget() &&
		!((Chunk->GetSkyLightAltered(Rel.x, Rel.y, Rel.z) > 11) || (Chunk->GetBlockLight(Rel.x, Rel.y, Rel.z) > 11))
	)
	{
		super::EventSeePlayer(a_Player, a_Chunk);
	}
}

bool cSpider::DoTakeDamage(TakeDamageInfo & a_TDI)
{
	if (!super::DoTakeDamage(a_TDI))
	{
		return false;
	}

	// If the source of the damage is not from an pawn entity, switch to idle
	if ((a_TDI.Attacker == nullptr) || !a_TDI.Attacker->IsPawn())
	{
		m_EMState = IDLE;
	}
	else
	{
		// If the source of the damage is from a pawn entity, chase that entity
		m_EMState = CHASING;
	}

	return true;
}
<|endoftext|>


<commit_before>/*
 *  Project:    moba-common
 *
 *  Copyright (C) 2016 Stefan Paproth <pappi-@gmx.de>
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program. If not, see <http://www.gnu.org/licenses/agpl.txt>.
 *
 */

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <fcntl.h>
#include <cerrno>
#include <cstring>
#include <string>

#include <boost/algorithm/string.hpp>

#include "helper.h"
#include "ipc.h"
#include "log.h"

namespace moba {

    IPC::IPC(key_t key, Type type) {
        int flags = S_IRWXU | S_IWGRP | S_IWOTH;;
        if(type == TYPE_SERVER) {
            flags |= IPC_CREAT | IPC_EXCL;
        }
        this->mID = msgget(key, flags);
        this->type = type;
        if(this->mID == -1) {
             throw IPCException(getErrno("msgget failed"));
        }
    }

    IPC::~IPC() {
        if(this->type == TYPE_CLIENT) {
            return;
        }
        if(msgctl(this->mID, IPC_RMID, NULL) == -1) {
            LOG(ERROR) << getErrno("unable to delete msg-queue! ") << std::endl;
        }
    }

    bool IPC::receive(long msgtyp, bool except) {
        Message msg;
        return this->receive(msg, msgtyp, except);
    }

    bool IPC::receive(Message &msg, long msgtyp, bool except) {
        memset(msg.mtext, '\0', moba::IPC::MSG_LEN);
        int msgflg = IPC_NOWAIT;
        if(except) {
            msgflg |= MSG_EXCEPT;
        }
        if(msgrcv(this->mID, &msg, IPC::MSG_LEN, msgtyp, msgflg) > 0) {
            return true;
        }
        if(errno == ENOMSG) {
            return false;
        }
        throw IPCException(getErrno("msgrcv failed"));
    }

    bool IPC::send(const std::string &data, long type) {
        Message msg;
        msg.mtype = type;
        memset(msg.mtext, '\0', moba::IPC::MSG_LEN);
        strncpy(msg.mtext, data.c_str(), moba::IPC::MSG_LEN);
        this->send(msg);
    }

    bool IPC::send(const Message &msg) {
        if(msgsnd(this->mID, &msg, IPC::MSG_LEN, IPC_NOWAIT) == 0) {
            return true;
        }

        if(errno == EAGAIN) {
            return false;
        }

        throw IPCException(getErrno("msgsnd failed"));
    }

    IPC::Command IPC::getCMDFromString(const std::string &cmd) {
        if(boost::iequals(cmd, "EMERGENCY_STOP")) {
            return CMD_EMERGENCY_STOP;
        }
        if(boost::iequals(cmd, "EMERGENCY_RELEASE")) {
            return CMD_EMERGENCY_RELEASE;
        }
        if(boost::iequals(cmd, "TEST")) {
            return CMD_TEST;
        }
        if(boost::iequals(cmd, "RUN")) {
            return CMD_RUN;
        }
        if(boost::iequals(cmd, "HALT")) {
            return CMD_HALT;
        }
        if(boost::iequals(cmd, "CONTINUE")) {
            return CMD_CONTINUE;
        }
        if(boost::iequals(cmd, "RESET")) {
            return CMD_RESET;
        }
        if(boost::iequals(cmd, "TERMINATE")) {
            return CMD_TERMINATE;
        }
        throw IPCException(std::string("unknown command <" + cmd + ">"));
    }
}
<commit_msg>new commands added<commit_after>/*
 *  Project:    moba-common
 *
 *  Copyright (C) 2016 Stefan Paproth <pappi-@gmx.de>
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program. If not, see <http://www.gnu.org/licenses/agpl.txt>.
 *
 */

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <fcntl.h>
#include <cerrno>
#include <cstring>
#include <string>

#include <boost/algorithm/string.hpp>

#include "helper.h"
#include "ipc.h"
#include "log.h"

namespace moba {

    IPC::IPC(key_t key, Type type) {
        int flags = S_IRWXU | S_IWGRP | S_IWOTH;;
        if(type == TYPE_SERVER) {
            flags |= IPC_CREAT | IPC_EXCL;
        }
        this->mID = msgget(key, flags);
        this->type = type;
        if(this->mID == -1) {
             throw IPCException(getErrno("msgget failed"));
        }
    }

    IPC::~IPC() {
        if(this->type == TYPE_CLIENT) {
            return;
        }
        if(msgctl(this->mID, IPC_RMID, NULL) == -1) {
            LOG(ERROR) << getErrno("unable to delete msg-queue! ") << std::endl;
        }
    }

    bool IPC::receive(long msgtyp, bool except) {
        Message msg;
        return this->receive(msg, msgtyp, except);
    }

    bool IPC::receive(Message &msg, long msgtyp, bool except) {
        memset(msg.mtext, '\0', moba::IPC::MSG_LEN);
        int msgflg = IPC_NOWAIT;
        if(except) {
            msgflg |= MSG_EXCEPT;
        }
        if(msgrcv(this->mID, &msg, IPC::MSG_LEN, msgtyp, msgflg) > 0) {
            return true;
        }
        if(errno == ENOMSG) {
            return false;
        }
        throw IPCException(getErrno("msgrcv failed"));
    }

    bool IPC::send(const std::string &data, long type) {
        Message msg;
        msg.mtype = type;
        memset(msg.mtext, '\0', moba::IPC::MSG_LEN);
        strncpy(msg.mtext, data.c_str(), moba::IPC::MSG_LEN);
        this->send(msg);
    }

    bool IPC::send(const Message &msg) {
        if(msgsnd(this->mID, &msg, IPC::MSG_LEN, IPC_NOWAIT) == 0) {
            return true;
        }

        if(errno == EAGAIN) {
            return false;
        }

        throw IPCException(getErrno("msgsnd failed"));
    }

    IPC::Command IPC::getCMDFromString(const std::string &cmd) {
        if(boost::iequals(cmd, "EMERGENCY_STOP")) {
            return CMD_EMERGENCY_STOP;
        }
        if(boost::iequals(cmd, "EMERGENCY_RELEASE")) {
            return CMD_EMERGENCY_RELEASE;
        }
        if(boost::iequals(cmd, "TEST")) {
            return CMD_TEST;
        }
        if(boost::iequals(cmd, "RUN")) {
            return CMD_RUN;
        }
        if(boost::iequals(cmd, "HALT")) {
            return CMD_HALT;
        }
        if(boost::iequals(cmd, "CONTINUE")) {
            return CMD_CONTINUE;
        }
        if(boost::iequals(cmd, "RESET")) {
            return CMD_RESET;
        }
        if(boost::iequals(cmd, "TERMINATE")) {
            return CMD_TERMINATE;
        }
        if(boost::iequals(cmd, "INTERRUPT")) {
            return CMD_INTERRUPT;
        }
        if(boost::iequals(cmd, "RESUME")) {
            return CMD_RESUME;
        }
        if(boost::iequals(cmd, "SET_DURATION")) {
            return CMD_SET_DURATION;
        }
        if(boost::iequals(cmd, "SHUTDOWN")) {
            return CMD_SHUTDOWN;
        }
        throw IPCException(std::string("unknown command <" + cmd + ">"));
    }
}
<|endoftext|>


<commit_before>/*
    Copyright (C) 2009-2010  George Kiagiadakis <kiagiadakis.george@gmail.com>
    Copyright (C) 2010 Collabora Ltd.
      @author George Kiagiadakis <george.kiagiadakis@collabora.co.uk>

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

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

    You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#include "value.h"
#include "string.h"
#include <cstring>
#include <boost/type_traits.hpp>
#include <glib-object.h>
#include <QtCore/QDebug>
#include <QtCore/QReadWriteLock>

namespace QGlib {
namespace Private {

class Dispatcher
{
public:
    Dispatcher();

    ValueVTable getVTable(Type t) const;
    void setVTable(Type t, const ValueVTable & vtable);

private:
    mutable QReadWriteLock lock;
    QHash<Type, ValueVTable> dispatchTable;
};

Dispatcher::Dispatcher()
{
#define DECLARE_VTABLE(T, NICK, GTYPE) \
    struct ValueVTable_##NICK \
    { \
        static void get(const Value & value, void *data) \
        { \
            *reinterpret_cast<T*>(data) = g_value_get_##NICK(value); \
        }; \
        \
        static void set(Value & value, const void *data) \
        { \
            g_value_set_##NICK(value, *reinterpret_cast<T const *>(data)); \
        }; \
    }; \
    setVTable(GTYPE, ValueVTable(ValueVTable_##NICK::set, ValueVTable_##NICK::get));

    DECLARE_VTABLE(char, char, Type::Char)
    DECLARE_VTABLE(unsigned char, uchar, Type::Uchar)
    DECLARE_VTABLE(bool, boolean, Type::Boolean)
    DECLARE_VTABLE(int, int, Type::Int)
    DECLARE_VTABLE(unsigned int, uint, Type::Uint)
    DECLARE_VTABLE(long, long, Type::Long)
    DECLARE_VTABLE(unsigned long, ulong, Type::Ulong)
    DECLARE_VTABLE(qint64, int64, Type::Int64)
    DECLARE_VTABLE(quint64, uint64, Type::Uint64)
    DECLARE_VTABLE(int, enum, Type::Enum);
    DECLARE_VTABLE(uint, flags, Type::Flags)
    DECLARE_VTABLE(float, float, Type::Float)
    DECLARE_VTABLE(double, double, Type::Double)
    DECLARE_VTABLE(QByteArray, string, Type::String)
    DECLARE_VTABLE(void*, pointer, Type::Pointer)
    DECLARE_VTABLE(void*, boxed, Type::Boxed)
    DECLARE_VTABLE(GParamSpec*, param, Type::Param)
    DECLARE_VTABLE(void*, object, Type::Object)
    DECLARE_VTABLE(QGlib::Type, gtype, GetType<QGlib::Type>())

#undef DECLARE_VTABLE
}

ValueVTable Dispatcher::getVTable(Type t) const
{
    //if the type is an interface, try to find its
    //instantiatable prerequisite and get the vtable
    //of this instantiatable type instead.
    if (t.isInterface()) {
        QList<Type> prerequisites = t.interfacePrerequisites();
        Q_FOREACH(Type prereq, prerequisites) {
            if (prereq.isInstantiatable()) {
                t = prereq;
            }
        }

        //Check if the prerequisite was found and
        //bail out if not, since such interfaces
        //are not compatible with GValue.
        if (!t.isInstantiatable()) {
            return ValueVTable();
        }
    }

    QReadLocker l(&lock);

    if (dispatchTable.contains(t)) {
        return dispatchTable[t];
    }

    while (t.isDerived()) {
        t = t.parent();
        if (dispatchTable.contains(t)) {
            return dispatchTable[t];
        }
    }

    return ValueVTable();
}

void Dispatcher::setVTable(Type t, const ValueVTable & vtable)
{
    QWriteLocker l(&lock);
    dispatchTable[t] = vtable;
}

} //namespace Private

Q_GLOBAL_STATIC(Private::Dispatcher, s_dispatcher);

#ifndef DOXYGEN_RUN

// -- Value::Data --

struct QTGLIB_NO_EXPORT Value::Data : public QSharedData
{
    Data();
    Data(const Data & other);
    ~Data();

    inline Type type() const { return G_VALUE_TYPE(&m_value); }
    inline GValue *value() { return &m_value; }
    inline const GValue *value() const { return &m_value; }

    GValue m_value;
};

Value::Data::Data()
    : QSharedData()
{
    std::memset(&m_value, 0, sizeof(GValue));
}

Value::Data::Data(const Value::Data & other)
    : QSharedData(other)
{
    std::memset(&m_value, 0, sizeof(GValue));

    if (other.type() != Type::Invalid) {
        g_value_init(value(), other.type());
        g_value_copy(other.value(), value());
    }
}

Value::Data::~Data()
{
    if (type() != Type::Invalid) {
        g_value_unset(value());
    }
}

#endif //DOXYGEN_RUN

// -- Value --

Value::Value()
    : d(new Data)
{
}

Value::Value(const GValue *gvalue)
    : d(new Data)
{
    if (gvalue && G_IS_VALUE(gvalue)) {
        init(G_VALUE_TYPE(gvalue));
        g_value_copy(gvalue, d->value());
    }
}

Value::Value(Type type)
    : d(new Data)
{
    init(type);
}

#define VALUE_CONSTRUCTOR(T) \
    Value::Value(T val) \
        : d(new Data) \
    { \
        init< \
            boost::remove_const< \
                boost::remove_reference<T>::type \
            >::type \
        >(); \
        set(val); \
    }

VALUE_CONSTRUCTOR(bool)
VALUE_CONSTRUCTOR(char)
VALUE_CONSTRUCTOR(uchar)
VALUE_CONSTRUCTOR(int)
VALUE_CONSTRUCTOR(uint)
VALUE_CONSTRUCTOR(long)
VALUE_CONSTRUCTOR(ulong)
VALUE_CONSTRUCTOR(qint64)
VALUE_CONSTRUCTOR(quint64)
VALUE_CONSTRUCTOR(float)
VALUE_CONSTRUCTOR(double)
VALUE_CONSTRUCTOR(const char *)
VALUE_CONSTRUCTOR(const QByteArray &)
VALUE_CONSTRUCTOR(const QString &)

#undef VALUE_CONSTRUCTOR

Value::Value(const Value & other)
    : d(other.d)
{
}

Value & Value::operator=(const Value & other)
{
    d = other.d;
    return *this;
}

Value::~Value()
{
}

void Value::init(Type type)
{
    if (isValid()) {
        g_value_unset(d->value());
    }
    g_value_init(d->value(), type);
}

bool Value::isValid() const
{
    return d->type() != Type::Invalid;
}

Type Value::type() const
{
    return d->type();
}

bool Value::canTransformTo(Type t) const
{
    return isValid() ? g_value_type_transformable(type(), t) : false;
}

Value Value::transformTo(Type t) const
{
    Value dest;
    dest.init(t);
    if (isValid()) {
        g_value_transform(d->value(), dest.d->value());
    }
    return dest;
}

void Value::clear()
{
    if (isValid()) {
        g_value_reset(d->value());
    }
}

Value::operator GValue* ()
{
    return d->value();
}

Value::operator const GValue * () const
{
    return d->value();
}

//static
void Value::registerValueVTable(Type type, const ValueVTable & vtable)
{
    s_dispatcher()->setVTable(type, vtable);
}

void Value::getData(Type dataType, void *data) const
{
    if (!isValid()) {
        throw Private::InvalidValueException();
    } else if (g_value_type_compatible(type(), dataType)) {
        ValueVTable vtable = s_dispatcher()->getVTable(dataType);
        if (vtable.get != NULL) {
            vtable.get(*this, data);
        } else {
            throw Private::UnregisteredTypeException(dataType.name().toStdString());
        }
    } else if (dataType.isValueType() && g_value_type_transformable(type(), dataType)) {
        Value v;
        v.init(dataType);

        if (!g_value_transform(d->value(), v.d->value())) {
            throw Private::TransformationFailedException(type().name().toStdString(),
                                                         dataType.name().toStdString());
        }

        v.getData(dataType, data);
    } else {
        throw Private::InvalidTypeException(dataType.name().toStdString(),
                                            type().name().toStdString());
    }
}

void Value::setData(Type dataType, const void *data)
{
    if (!isValid()) {
        throw Private::InvalidValueException();
    } else if (g_value_type_compatible(dataType, type())) {
        ValueVTable vtable = s_dispatcher()->getVTable(dataType);
        if (vtable.set != NULL) {
            vtable.set(*this, data);
        } else {
            throw Private::UnregisteredTypeException(dataType.name().toStdString());
        }
    } else if (dataType.isValueType() && g_value_type_transformable(dataType, type())) {
        Value v;
        v.init(dataType);
        v.setData(dataType, data);

        if (!g_value_transform(v.d->value(), d->value())) {
            throw Private::TransformationFailedException(dataType.name().toStdString(),
                                                         type().name().toStdString());
        }
    } else {
        throw Private::InvalidTypeException(dataType.name().toStdString(),
                                            type().name().toStdString());
    }
}

QDebug operator<<(QDebug debug, const Value & value)
{
    debug.nospace() << "QGlib::Value";
    if(!value.isValid()) {
        debug << "(<invalid>)";
        return debug.space();
    } else {
        QString str = value.toString();
        if (str.isEmpty()) {
            if (g_value_fits_pointer(value)) {
                quintptr ptr = reinterpret_cast<quintptr>(g_value_peek_pointer(value));
                str = QString(QLatin1String("0x%1")).arg(ptr, sizeof(quintptr)*2,
                                                         16, QLatin1Char('0'));
            } else {
                str = QLatin1String("<unknown value>");
            }
        }

        debug << "(" << value.type().name() << ", " << str << ")";
        return debug.space();
    }
}

} //namespace QGlib
<commit_msg>Fix compilation with QT_NO_STL.<commit_after>/*
    Copyright (C) 2009-2010  George Kiagiadakis <kiagiadakis.george@gmail.com>
    Copyright (C) 2010 Collabora Ltd.
      @author George Kiagiadakis <george.kiagiadakis@collabora.co.uk>

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

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

    You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#include "value.h"
#include "string.h"
#include <cstring>
#include <boost/type_traits.hpp>
#include <glib-object.h>
#include <QtCore/QDebug>
#include <QtCore/QReadWriteLock>

namespace QGlib {
namespace Private {

class Dispatcher
{
public:
    Dispatcher();

    ValueVTable getVTable(Type t) const;
    void setVTable(Type t, const ValueVTable & vtable);

private:
    mutable QReadWriteLock lock;
    QHash<Type, ValueVTable> dispatchTable;
};

Dispatcher::Dispatcher()
{
#define DECLARE_VTABLE(T, NICK, GTYPE) \
    struct ValueVTable_##NICK \
    { \
        static void get(const Value & value, void *data) \
        { \
            *reinterpret_cast<T*>(data) = g_value_get_##NICK(value); \
        }; \
        \
        static void set(Value & value, const void *data) \
        { \
            g_value_set_##NICK(value, *reinterpret_cast<T const *>(data)); \
        }; \
    }; \
    setVTable(GTYPE, ValueVTable(ValueVTable_##NICK::set, ValueVTable_##NICK::get));

    DECLARE_VTABLE(char, char, Type::Char)
    DECLARE_VTABLE(unsigned char, uchar, Type::Uchar)
    DECLARE_VTABLE(bool, boolean, Type::Boolean)
    DECLARE_VTABLE(int, int, Type::Int)
    DECLARE_VTABLE(unsigned int, uint, Type::Uint)
    DECLARE_VTABLE(long, long, Type::Long)
    DECLARE_VTABLE(unsigned long, ulong, Type::Ulong)
    DECLARE_VTABLE(qint64, int64, Type::Int64)
    DECLARE_VTABLE(quint64, uint64, Type::Uint64)
    DECLARE_VTABLE(int, enum, Type::Enum);
    DECLARE_VTABLE(uint, flags, Type::Flags)
    DECLARE_VTABLE(float, float, Type::Float)
    DECLARE_VTABLE(double, double, Type::Double)
    DECLARE_VTABLE(QByteArray, string, Type::String)
    DECLARE_VTABLE(void*, pointer, Type::Pointer)
    DECLARE_VTABLE(void*, boxed, Type::Boxed)
    DECLARE_VTABLE(GParamSpec*, param, Type::Param)
    DECLARE_VTABLE(void*, object, Type::Object)
    DECLARE_VTABLE(QGlib::Type, gtype, GetType<QGlib::Type>())

#undef DECLARE_VTABLE
}

ValueVTable Dispatcher::getVTable(Type t) const
{
    //if the type is an interface, try to find its
    //instantiatable prerequisite and get the vtable
    //of this instantiatable type instead.
    if (t.isInterface()) {
        QList<Type> prerequisites = t.interfacePrerequisites();
        Q_FOREACH(Type prereq, prerequisites) {
            if (prereq.isInstantiatable()) {
                t = prereq;
            }
        }

        //Check if the prerequisite was found and
        //bail out if not, since such interfaces
        //are not compatible with GValue.
        if (!t.isInstantiatable()) {
            return ValueVTable();
        }
    }

    QReadLocker l(&lock);

    if (dispatchTable.contains(t)) {
        return dispatchTable[t];
    }

    while (t.isDerived()) {
        t = t.parent();
        if (dispatchTable.contains(t)) {
            return dispatchTable[t];
        }
    }

    return ValueVTable();
}

void Dispatcher::setVTable(Type t, const ValueVTable & vtable)
{
    QWriteLocker l(&lock);
    dispatchTable[t] = vtable;
}

} //namespace Private

Q_GLOBAL_STATIC(Private::Dispatcher, s_dispatcher);

#ifndef DOXYGEN_RUN

// -- Value::Data --

struct QTGLIB_NO_EXPORT Value::Data : public QSharedData
{
    Data();
    Data(const Data & other);
    ~Data();

    inline Type type() const { return G_VALUE_TYPE(&m_value); }
    inline GValue *value() { return &m_value; }
    inline const GValue *value() const { return &m_value; }

    GValue m_value;
};

Value::Data::Data()
    : QSharedData()
{
    std::memset(&m_value, 0, sizeof(GValue));
}

Value::Data::Data(const Value::Data & other)
    : QSharedData(other)
{
    std::memset(&m_value, 0, sizeof(GValue));

    if (other.type() != Type::Invalid) {
        g_value_init(value(), other.type());
        g_value_copy(other.value(), value());
    }
}

Value::Data::~Data()
{
    if (type() != Type::Invalid) {
        g_value_unset(value());
    }
}

#endif //DOXYGEN_RUN

// -- Value --

Value::Value()
    : d(new Data)
{
}

Value::Value(const GValue *gvalue)
    : d(new Data)
{
    if (gvalue && G_IS_VALUE(gvalue)) {
        init(G_VALUE_TYPE(gvalue));
        g_value_copy(gvalue, d->value());
    }
}

Value::Value(Type type)
    : d(new Data)
{
    init(type);
}

#define VALUE_CONSTRUCTOR(T) \
    Value::Value(T val) \
        : d(new Data) \
    { \
        init< \
            boost::remove_const< \
                boost::remove_reference<T>::type \
            >::type \
        >(); \
        set(val); \
    }

VALUE_CONSTRUCTOR(bool)
VALUE_CONSTRUCTOR(char)
VALUE_CONSTRUCTOR(uchar)
VALUE_CONSTRUCTOR(int)
VALUE_CONSTRUCTOR(uint)
VALUE_CONSTRUCTOR(long)
VALUE_CONSTRUCTOR(ulong)
VALUE_CONSTRUCTOR(qint64)
VALUE_CONSTRUCTOR(quint64)
VALUE_CONSTRUCTOR(float)
VALUE_CONSTRUCTOR(double)
VALUE_CONSTRUCTOR(const char *)
VALUE_CONSTRUCTOR(const QByteArray &)
VALUE_CONSTRUCTOR(const QString &)

#undef VALUE_CONSTRUCTOR

Value::Value(const Value & other)
    : d(other.d)
{
}

Value & Value::operator=(const Value & other)
{
    d = other.d;
    return *this;
}

Value::~Value()
{
}

void Value::init(Type type)
{
    if (isValid()) {
        g_value_unset(d->value());
    }
    g_value_init(d->value(), type);
}

bool Value::isValid() const
{
    return d->type() != Type::Invalid;
}

Type Value::type() const
{
    return d->type();
}

bool Value::canTransformTo(Type t) const
{
    return isValid() ? g_value_type_transformable(type(), t) : false;
}

Value Value::transformTo(Type t) const
{
    Value dest;
    dest.init(t);
    if (isValid()) {
        g_value_transform(d->value(), dest.d->value());
    }
    return dest;
}

void Value::clear()
{
    if (isValid()) {
        g_value_reset(d->value());
    }
}

Value::operator GValue* ()
{
    return d->value();
}

Value::operator const GValue * () const
{
    return d->value();
}

//static
void Value::registerValueVTable(Type type, const ValueVTable & vtable)
{
    s_dispatcher()->setVTable(type, vtable);
}

static inline std::string toStdStringHelper(const QString & str)
{
#ifndef QT_NO_STL
    return str.toStdString();
#else
    const QByteArray asc = str.toAscii();
    return std::string(asc.constData(), asc.length());
#endif
}

void Value::getData(Type dataType, void *data) const
{
    if (!isValid()) {
        throw Private::InvalidValueException();
    } else if (g_value_type_compatible(type(), dataType)) {
        ValueVTable vtable = s_dispatcher()->getVTable(dataType);
        if (vtable.get != NULL) {
            vtable.get(*this, data);
        } else {
            throw Private::UnregisteredTypeException(toStdStringHelper(dataType.name()));
        }
    } else if (dataType.isValueType() && g_value_type_transformable(type(), dataType)) {
        Value v;
        v.init(dataType);

        if (!g_value_transform(d->value(), v.d->value())) {
            throw Private::TransformationFailedException(toStdStringHelper(type().name()),
                                                         toStdStringHelper(dataType.name()));
        }

        v.getData(dataType, data);
    } else {
        throw Private::InvalidTypeException(toStdStringHelper(dataType.name()),
                                            toStdStringHelper(type().name()));
    }
}

void Value::setData(Type dataType, const void *data)
{
    if (!isValid()) {
        throw Private::InvalidValueException();
    } else if (g_value_type_compatible(dataType, type())) {
        ValueVTable vtable = s_dispatcher()->getVTable(dataType);
        if (vtable.set != NULL) {
            vtable.set(*this, data);
        } else {
            throw Private::UnregisteredTypeException(toStdStringHelper(dataType.name()));
        }
    } else if (dataType.isValueType() && g_value_type_transformable(dataType, type())) {
        Value v;
        v.init(dataType);
        v.setData(dataType, data);

        if (!g_value_transform(v.d->value(), d->value())) {
            throw Private::TransformationFailedException(toStdStringHelper(dataType.name()),
                                                         toStdStringHelper(type().name()));
        }
    } else {
        throw Private::InvalidTypeException(toStdStringHelper(dataType.name()),
                                            toStdStringHelper(type().name()));
    }
}

QDebug operator<<(QDebug debug, const Value & value)
{
    debug.nospace() << "QGlib::Value";
    if(!value.isValid()) {
        debug << "(<invalid>)";
        return debug.space();
    } else {
        QString str = value.toString();
        if (str.isEmpty()) {
            if (g_value_fits_pointer(value)) {
                quintptr ptr = reinterpret_cast<quintptr>(g_value_peek_pointer(value));
                str = QString(QLatin1String("0x%1")).arg(ptr, sizeof(quintptr)*2,
                                                         16, QLatin1Char('0'));
            } else {
                str = QLatin1String("<unknown value>");
            }
        }

        debug << "(" << value.type().name() << ", " << str << ")";
        return debug.space();
    }
}

} //namespace QGlib
<|endoftext|>


<commit_before>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2011 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file license.txt or http://www.opensource.org/licenses/mit-license.php.

#include "headers.h"
#include "irc.h"
#include "net.h"
#include "strlcpy.h"

using namespace std;
using namespace boost;

int nGotIRCAddresses = 0;
bool fGotExternalIP = false;

void ThreadIRCSeed2(void* parg);

#pragma pack(push, 1)
struct ircaddr
{
    int ip;
    short port;
};
#pragma pack(pop)

string EncodeAddress(const CAddress& addr)
{
    struct ircaddr tmp;
    tmp.ip    = addr.ip;
    tmp.port  = addr.port;

    vector<unsigned char> vch(UBEGIN(tmp), UEND(tmp));
    return string("u") + EncodeBase58Check(vch);
}

bool DecodeAddress(string str, CAddress& addr)
{
    vector<unsigned char> vch;
    if (!DecodeBase58Check(str.substr(1), vch))
        return false;

    struct ircaddr tmp;
    if (vch.size() != sizeof(tmp))
        return false;
    memcpy(&tmp, &vch[0], sizeof(tmp));

    addr = CAddress(tmp.ip, ntohs(tmp.port), NODE_NETWORK);
    return true;
}

static bool Send(SOCKET hSocket, const char* pszSend)
{
    if (strstr(pszSend, "PONG") != pszSend)
        printf("IRC SENDING: %s\n", pszSend);
    const char* psz = pszSend;
    const char* pszEnd = psz + strlen(psz);
    while (psz < pszEnd)
    {
        int ret = send(hSocket, psz, pszEnd - psz, MSG_NOSIGNAL);
        if (ret < 0)
            return false;
        psz += ret;
    }
    return true;
}

bool RecvLine(SOCKET hSocket, string& strLine)
{
    strLine = "";
    loop
    {
        char c;
        int nBytes = recv(hSocket, &c, 1, 0);
        if (nBytes > 0)
        {
            if (c == '\n')
                continue;
            if (c == '\r')
                return true;
            strLine += c;
            if (strLine.size() >= 9000)
                return true;
        }
        else if (nBytes <= 0)
        {
            if (fShutdown)
                return false;
            if (nBytes < 0)
            {
                int nErr = WSAGetLastError();
                if (nErr == WSAEMSGSIZE)
                    continue;
                if (nErr == WSAEWOULDBLOCK || nErr == WSAEINTR || nErr == WSAEINPROGRESS)
                {
                    Sleep(10);
                    continue;
                }
            }
            if (!strLine.empty())
                return true;
            if (nBytes == 0)
            {
                // socket closed
                printf("IRC socket closed\n");
                return false;
            }
            else
            {
                // socket error
                int nErr = WSAGetLastError();
                printf("IRC recv failed: %d\n", nErr);
                return false;
            }
        }
    }
}

bool RecvLineIRC(SOCKET hSocket, string& strLine)
{
    loop
    {
        bool fRet = RecvLine(hSocket, strLine);
        if (fRet)
        {
            if (fShutdown)
                return false;
            vector<string> vWords;
            ParseString(strLine, ' ', vWords);
            if (vWords.size() >= 1 && vWords[0] == "PING")
            {
                strLine[1] = 'O';
                strLine += '\r';
                Send(hSocket, strLine.c_str());
                continue;
            }
        }
        return fRet;
    }
}

int RecvUntil(SOCKET hSocket, const char* psz1, const char* psz2=NULL, const char* psz3=NULL, const char* psz4=NULL)
{
    loop
    {
        string strLine;
        strLine.reserve(10000);
        if (!RecvLineIRC(hSocket, strLine))
            return 0;
        printf("IRC %s\n", strLine.c_str());
        if (psz1 && strLine.find(psz1) != -1)
            return 1;
        if (psz2 && strLine.find(psz2) != -1)
            return 2;
        if (psz3 && strLine.find(psz3) != -1)
            return 3;
        if (psz4 && strLine.find(psz4) != -1)
            return 4;
    }
}

bool Wait(int nSeconds)
{
    if (fShutdown)
        return false;
    printf("IRC waiting %d seconds to reconnect\n", nSeconds);
    for (int i = 0; i < nSeconds; i++)
    {
        if (fShutdown)
            return false;
        Sleep(1000);
    }
    return true;
}

bool RecvCodeLine(SOCKET hSocket, const char* psz1, string& strRet)
{
    strRet.clear();
    loop
    {
        string strLine;
        if (!RecvLineIRC(hSocket, strLine))
            return false;

        vector<string> vWords;
        ParseString(strLine, ' ', vWords);
        if (vWords.size() < 2)
            continue;

        if (vWords[1] == psz1)
        {
            printf("IRC %s\n", strLine.c_str());
            strRet = strLine;
            return true;
        }
    }
}

bool GetIPFromIRC(SOCKET hSocket, string strMyName, unsigned int& ipRet)
{
    Send(hSocket, strprintf("USERHOST %s\r", strMyName.c_str()).c_str());

    string strLine;
    if (!RecvCodeLine(hSocket, "302", strLine))
        return false;

    vector<string> vWords;
    ParseString(strLine, ' ', vWords);
    if (vWords.size() < 4)
        return false;

    string str = vWords[3];
    if (str.rfind("@") == string::npos)
        return false;
    string strHost = str.substr(str.rfind("@")+1);

    // Hybrid IRC used by lfnet always returns IP when you userhost yourself,
    // but in case another IRC is ever used this should work.
    printf("GetIPFromIRC() got userhost %s\n", strHost.c_str());
    if (fUseProxy)
        return false;
    CAddress addr(strHost, 0, true);
    if (!addr.IsValid())
        return false;
    ipRet = addr.ip;

    return true;
}

void ThreadIRCSeed(void* parg)
{
    IMPLEMENT_RANDOMIZE_STACK(ThreadIRCSeed(parg));
    try
    {
        ThreadIRCSeed2(parg);
    }
    catch (std::exception& e) {
        PrintExceptionContinue(&e, "ThreadIRCSeed()");
    } catch (...) {
        PrintExceptionContinue(NULL, "ThreadIRCSeed()");
    }
    printf("ThreadIRCSeed exiting\n");
}

void ThreadIRCSeed2(void* parg)
{
    /* Dont advertise on IRC if we don't allow incoming connections */
    if (mapArgs.count("-connect") || fNoListen)
        return;

    if (GetBoolArg("-noirc"))
        return;
    printf("ThreadIRCSeed started\n");
    int nErrorWait = 10;
    int nRetryWait = 10;
    bool fNameInUse = false;

    while (!fShutdown)
    {
        CAddress addrConnect("94.125.182.252", 6667); // chat.freenode.net

        CAddress addrIRC("chat.freenode.net", 6667, true);
        if (addrIRC.IsValid())
            addrConnect = addrIRC;

        SOCKET hSocket;
        if (!ConnectSocket(addrConnect, hSocket))
        {
            printf("IRC connect failed\n");
            nErrorWait = nErrorWait * 11 / 10;
            if (Wait(nErrorWait += 60))
                continue;
            else
                return;
        }

        if (!RecvUntil(hSocket, "Found your hostname", "using your IP address instead", "Couldn't look up your hostname", "ignoring hostname"))
        {
            closesocket(hSocket);
            hSocket = INVALID_SOCKET;
            nErrorWait = nErrorWait * 11 / 10;
            if (Wait(nErrorWait += 60))
                continue;
            else
                return;
        }

        string strMyName;
        if (addrLocalHost.IsRoutable() && !fUseProxy && !fNameInUse)
            strMyName = EncodeAddress(addrLocalHost);
        else
            strMyName = strprintf("x%u", GetRand(1000000000));

        Send(hSocket, strprintf("NICK %s\r", strMyName.c_str()).c_str());
        Send(hSocket, strprintf("USER %s 8 * : %s\r", strMyName.c_str(), strMyName.c_str()).c_str());

        int nRet = RecvUntil(hSocket, " 004 ", " 433 ");
        if (nRet != 1)
        {
            closesocket(hSocket);
            hSocket = INVALID_SOCKET;
            if (nRet == 2)
            {
                printf("IRC name already in use\n");
                fNameInUse = true;
                Wait(10);
                continue;
            }
            nErrorWait = nErrorWait * 11 / 10;
            if (Wait(nErrorWait += 60))
                continue;
            else
                return;
        }
        Sleep(500);

        // Get our external IP from the IRC server and re-nick before joining the channel
        CAddress addrFromIRC;
        if (GetIPFromIRC(hSocket, strMyName, addrFromIRC.ip))
        {
            printf("GetIPFromIRC() returned %s\n", addrFromIRC.ToStringIP().c_str());
            if (!fUseProxy && addrFromIRC.IsRoutable())
            {
                // IRC lets you to re-nick
                fGotExternalIP = true;
                addrLocalHost.ip = addrFromIRC.ip;
                strMyName = EncodeAddress(addrLocalHost);
                Send(hSocket, strprintf("NICK %s\r", strMyName.c_str()).c_str());
            }
        }

        if (fTestNet) {
            Send(hSocket, "JOIN #diannaTEST\r");
            Send(hSocket, "WHO #diannaTEST\r");
        } else {
            // randomly join #bitcoin00-#bitcoin99
            int channel_number = GetRandInt(100);
            Send(hSocket, strprintf("JOIN #dianna%02d\r", channel_number).c_str());
            Send(hSocket, strprintf("WHO #dianna%02d\r", channel_number).c_str());
        }

        int64 nStart = GetTime();
        string strLine;
        strLine.reserve(10000);
        while (!fShutdown && RecvLineIRC(hSocket, strLine))
        {
            if (strLine.empty() || strLine.size() > 900 || strLine[0] != ':')
                continue;

            vector<string> vWords;
            ParseString(strLine, ' ', vWords);
            if (vWords.size() < 2)
                continue;

            char pszName[10000];
            pszName[0] = '\0';

            if (vWords[1] == "352" && vWords.size() >= 8)
            {
                // index 7 is limited to 16 characters
                // could get full length name at index 10, but would be different from join messages
                strlcpy(pszName, vWords[7].c_str(), sizeof(pszName));
                printf("IRC got who\n");
            }

            if (vWords[1] == "JOIN" && vWords[0].size() > 1)
            {
                // :username!username@50000007.F000000B.90000002.IP JOIN :#channelname
                strlcpy(pszName, vWords[0].c_str() + 1, sizeof(pszName));
                if (strchr(pszName, '!'))
                    *strchr(pszName, '!') = '\0';
                printf("IRC got join\n");
            }

            if (pszName[0] == 'u')
            {
                CAddress addr;
                if (DecodeAddress(pszName, addr))
                {
                    addr.nTime = GetAdjustedTime();
                    if (AddAddress(addr, 51 * 60))
                        printf("IRC got new address: %s\n", addr.ToString().c_str());
                    nGotIRCAddresses++;
                }
                else
                {
                    printf("IRC decode failed\n");
                }
            }
        }
        closesocket(hSocket);
        hSocket = INVALID_SOCKET;

        if (GetTime() - nStart > 20 * 60)
        {
            nErrorWait /= 3;
            nRetryWait /= 3;
        }

        nRetryWait = nRetryWait * 11 / 10;
        if (!Wait(nRetryWait += 60))
            return;
    }
}

#ifdef TEST
int main(int argc, char *argv[])
{
    WSADATA wsadata;
    if (WSAStartup(MAKEWORD(2,2), &wsadata) != NO_ERROR)
    {
        printf("Error at WSAStartup()\n");
        return false;
    }

    ThreadIRCSeed(NULL);

    WSACleanup();
    return 0;
}
#endif
<commit_msg>Reduce IRC channels to 2<commit_after>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2011 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file license.txt or http://www.opensource.org/licenses/mit-license.php.

#include "headers.h"
#include "irc.h"
#include "net.h"
#include "strlcpy.h"

using namespace std;
using namespace boost;

int nGotIRCAddresses = 0;
bool fGotExternalIP = false;

void ThreadIRCSeed2(void* parg);

#pragma pack(push, 1)
struct ircaddr
{
    int ip;
    short port;
};
#pragma pack(pop)

string EncodeAddress(const CAddress& addr)
{
    struct ircaddr tmp;
    tmp.ip    = addr.ip;
    tmp.port  = addr.port;

    vector<unsigned char> vch(UBEGIN(tmp), UEND(tmp));
    return string("u") + EncodeBase58Check(vch);
}

bool DecodeAddress(string str, CAddress& addr)
{
    vector<unsigned char> vch;
    if (!DecodeBase58Check(str.substr(1), vch))
        return false;

    struct ircaddr tmp;
    if (vch.size() != sizeof(tmp))
        return false;
    memcpy(&tmp, &vch[0], sizeof(tmp));

    addr = CAddress(tmp.ip, ntohs(tmp.port), NODE_NETWORK);
    return true;
}

static bool Send(SOCKET hSocket, const char* pszSend)
{
    if (strstr(pszSend, "PONG") != pszSend)
        printf("IRC SENDING: %s\n", pszSend);
    const char* psz = pszSend;
    const char* pszEnd = psz + strlen(psz);
    while (psz < pszEnd)
    {
        int ret = send(hSocket, psz, pszEnd - psz, MSG_NOSIGNAL);
        if (ret < 0)
            return false;
        psz += ret;
    }
    return true;
}

bool RecvLine(SOCKET hSocket, string& strLine)
{
    strLine = "";
    loop
    {
        char c;
        int nBytes = recv(hSocket, &c, 1, 0);
        if (nBytes > 0)
        {
            if (c == '\n')
                continue;
            if (c == '\r')
                return true;
            strLine += c;
            if (strLine.size() >= 9000)
                return true;
        }
        else if (nBytes <= 0)
        {
            if (fShutdown)
                return false;
            if (nBytes < 0)
            {
                int nErr = WSAGetLastError();
                if (nErr == WSAEMSGSIZE)
                    continue;
                if (nErr == WSAEWOULDBLOCK || nErr == WSAEINTR || nErr == WSAEINPROGRESS)
                {
                    Sleep(10);
                    continue;
                }
            }
            if (!strLine.empty())
                return true;
            if (nBytes == 0)
            {
                // socket closed
                printf("IRC socket closed\n");
                return false;
            }
            else
            {
                // socket error
                int nErr = WSAGetLastError();
                printf("IRC recv failed: %d\n", nErr);
                return false;
            }
        }
    }
}

bool RecvLineIRC(SOCKET hSocket, string& strLine)
{
    loop
    {
        bool fRet = RecvLine(hSocket, strLine);
        if (fRet)
        {
            if (fShutdown)
                return false;
            vector<string> vWords;
            ParseString(strLine, ' ', vWords);
            if (vWords.size() >= 1 && vWords[0] == "PING")
            {
                strLine[1] = 'O';
                strLine += '\r';
                Send(hSocket, strLine.c_str());
                continue;
            }
        }
        return fRet;
    }
}

int RecvUntil(SOCKET hSocket, const char* psz1, const char* psz2=NULL, const char* psz3=NULL, const char* psz4=NULL)
{
    loop
    {
        string strLine;
        strLine.reserve(10000);
        if (!RecvLineIRC(hSocket, strLine))
            return 0;
        printf("IRC %s\n", strLine.c_str());
        if (psz1 && strLine.find(psz1) != -1)
            return 1;
        if (psz2 && strLine.find(psz2) != -1)
            return 2;
        if (psz3 && strLine.find(psz3) != -1)
            return 3;
        if (psz4 && strLine.find(psz4) != -1)
            return 4;
    }
}

bool Wait(int nSeconds)
{
    if (fShutdown)
        return false;
    printf("IRC waiting %d seconds to reconnect\n", nSeconds);
    for (int i = 0; i < nSeconds; i++)
    {
        if (fShutdown)
            return false;
        Sleep(1000);
    }
    return true;
}

bool RecvCodeLine(SOCKET hSocket, const char* psz1, string& strRet)
{
    strRet.clear();
    loop
    {
        string strLine;
        if (!RecvLineIRC(hSocket, strLine))
            return false;

        vector<string> vWords;
        ParseString(strLine, ' ', vWords);
        if (vWords.size() < 2)
            continue;

        if (vWords[1] == psz1)
        {
            printf("IRC %s\n", strLine.c_str());
            strRet = strLine;
            return true;
        }
    }
}

bool GetIPFromIRC(SOCKET hSocket, string strMyName, unsigned int& ipRet)
{
    Send(hSocket, strprintf("USERHOST %s\r", strMyName.c_str()).c_str());

    string strLine;
    if (!RecvCodeLine(hSocket, "302", strLine))
        return false;

    vector<string> vWords;
    ParseString(strLine, ' ', vWords);
    if (vWords.size() < 4)
        return false;

    string str = vWords[3];
    if (str.rfind("@") == string::npos)
        return false;
    string strHost = str.substr(str.rfind("@")+1);

    // Hybrid IRC used by lfnet always returns IP when you userhost yourself,
    // but in case another IRC is ever used this should work.
    printf("GetIPFromIRC() got userhost %s\n", strHost.c_str());
    if (fUseProxy)
        return false;
    CAddress addr(strHost, 0, true);
    if (!addr.IsValid())
        return false;
    ipRet = addr.ip;

    return true;
}

void ThreadIRCSeed(void* parg)
{
    IMPLEMENT_RANDOMIZE_STACK(ThreadIRCSeed(parg));
    try
    {
        ThreadIRCSeed2(parg);
    }
    catch (std::exception& e) {
        PrintExceptionContinue(&e, "ThreadIRCSeed()");
    } catch (...) {
        PrintExceptionContinue(NULL, "ThreadIRCSeed()");
    }
    printf("ThreadIRCSeed exiting\n");
}

void ThreadIRCSeed2(void* parg)
{
    /* Dont advertise on IRC if we don't allow incoming connections */
    if (mapArgs.count("-connect") || fNoListen)
        return;

    if (GetBoolArg("-noirc"))
        return;
    printf("ThreadIRCSeed started\n");
    int nErrorWait = 10;
    int nRetryWait = 10;
    bool fNameInUse = false;

    while (!fShutdown)
    {
        CAddress addrConnect("94.125.182.252", 6667); // chat.freenode.net

        CAddress addrIRC("chat.freenode.net", 6667, true);
        if (addrIRC.IsValid())
            addrConnect = addrIRC;

        SOCKET hSocket;
        if (!ConnectSocket(addrConnect, hSocket))
        {
            printf("IRC connect failed\n");
            nErrorWait = nErrorWait * 11 / 10;
            if (Wait(nErrorWait += 60))
                continue;
            else
                return;
        }

        if (!RecvUntil(hSocket, "Found your hostname", "using your IP address instead", "Couldn't look up your hostname", "ignoring hostname"))
        {
            closesocket(hSocket);
            hSocket = INVALID_SOCKET;
            nErrorWait = nErrorWait * 11 / 10;
            if (Wait(nErrorWait += 60))
                continue;
            else
                return;
        }

        string strMyName;
        if (addrLocalHost.IsRoutable() && !fUseProxy && !fNameInUse)
            strMyName = EncodeAddress(addrLocalHost);
        else
            strMyName = strprintf("x%u", GetRand(1000000000));

        Send(hSocket, strprintf("NICK %s\r", strMyName.c_str()).c_str());
        Send(hSocket, strprintf("USER %s 8 * : %s\r", strMyName.c_str(), strMyName.c_str()).c_str());

        int nRet = RecvUntil(hSocket, " 004 ", " 433 ");
        if (nRet != 1)
        {
            closesocket(hSocket);
            hSocket = INVALID_SOCKET;
            if (nRet == 2)
            {
                printf("IRC name already in use\n");
                fNameInUse = true;
                Wait(10);
                continue;
            }
            nErrorWait = nErrorWait * 11 / 10;
            if (Wait(nErrorWait += 60))
                continue;
            else
                return;
        }
        Sleep(500);

        // Get our external IP from the IRC server and re-nick before joining the channel
        CAddress addrFromIRC;
        if (GetIPFromIRC(hSocket, strMyName, addrFromIRC.ip))
        {
            printf("GetIPFromIRC() returned %s\n", addrFromIRC.ToStringIP().c_str());
            if (!fUseProxy && addrFromIRC.IsRoutable())
            {
                // IRC lets you to re-nick
                fGotExternalIP = true;
                addrLocalHost.ip = addrFromIRC.ip;
                strMyName = EncodeAddress(addrLocalHost);
                Send(hSocket, strprintf("NICK %s\r", strMyName.c_str()).c_str());
            }
        }

        if (fTestNet) {
            Send(hSocket, "JOIN #diannaTEST\r");
            Send(hSocket, "WHO #diannaTEST\r");
        } else {
            // randomly join #dianna00-#dianna01
            int channel_number = GetRandInt(2);
            Send(hSocket, strprintf("JOIN #dianna%02d\r", channel_number).c_str());
            Send(hSocket, strprintf("WHO #dianna%02d\r", channel_number).c_str());
        }

        int64 nStart = GetTime();
        string strLine;
        strLine.reserve(10000);
        while (!fShutdown && RecvLineIRC(hSocket, strLine))
        {
            if (strLine.empty() || strLine.size() > 900 || strLine[0] != ':')
                continue;

            vector<string> vWords;
            ParseString(strLine, ' ', vWords);
            if (vWords.size() < 2)
                continue;

            char pszName[10000];
            pszName[0] = '\0';

            if (vWords[1] == "352" && vWords.size() >= 8)
            {
                // index 7 is limited to 16 characters
                // could get full length name at index 10, but would be different from join messages
                strlcpy(pszName, vWords[7].c_str(), sizeof(pszName));
                printf("IRC got who\n");
            }

            if (vWords[1] == "JOIN" && vWords[0].size() > 1)
            {
                // :username!username@50000007.F000000B.90000002.IP JOIN :#channelname
                strlcpy(pszName, vWords[0].c_str() + 1, sizeof(pszName));
                if (strchr(pszName, '!'))
                    *strchr(pszName, '!') = '\0';
                printf("IRC got join\n");
            }

            if (pszName[0] == 'u')
            {
                CAddress addr;
                if (DecodeAddress(pszName, addr))
                {
                    addr.nTime = GetAdjustedTime();
                    if (AddAddress(addr, 51 * 60))
                        printf("IRC got new address: %s\n", addr.ToString().c_str());
                    nGotIRCAddresses++;
                }
                else
                {
                    printf("IRC decode failed\n");
                }
            }
        }
        closesocket(hSocket);
        hSocket = INVALID_SOCKET;

        if (GetTime() - nStart > 20 * 60)
        {
            nErrorWait /= 3;
            nRetryWait /= 3;
        }

        nRetryWait = nRetryWait * 11 / 10;
        if (!Wait(nRetryWait += 60))
            return;
    }
}

#ifdef TEST
int main(int argc, char *argv[])
{
    WSADATA wsadata;
    if (WSAStartup(MAKEWORD(2,2), &wsadata) != NO_ERROR)
    {
        printf("Error at WSAStartup()\n");
        return false;
    }

    ThreadIRCSeed(NULL);

    WSACleanup();
    return 0;
}
#endif
<|endoftext|>


<commit_before>/*
Copyright (c) 2013 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.

Author: Leonardo de Moura
*/
#include <new>
#include <cstdlib>
#include <iostream>
#include "util/exception.h"
#include "util/memory.h"

namespace lean {
void set_max_memory_megabyte(unsigned max) {
    size_t m = max;
    m *= 1024 * 1024;
    set_max_memory(m);
}
}

#if !defined(LEAN_TRACK_MEMORY)
namespace lean {
size_t     get_allocated_memory() {
    return 0;
}

void set_max_memory(size_t) {
    throw exception("Lean was compiled without memory consumption tracking "
                    "(possible solution: compile using LEAN_TRACK_MEMORY)");
}

void check_memory(char const * component_name) {
    // do nothing when LEAN_TRACK_MEMORY is not defined
}

void * malloc(size_t sz, bool use_ex)  {
    void * r = ::malloc(sz);
    if (r || sz == 0)
        return r;
    else if (use_ex)
        throw std::bad_alloc();
    else
        return nullptr;
}

void * malloc(size_t sz) {
    return malloc(sz, true);
}

void * realloc(void * ptr, size_t sz) {
    void * r = ::realloc(ptr, sz);
    if (r || sz == 0)
        return r;
    else
        throw std::bad_alloc();
}

void free(void * ptr) {
    ::free(ptr);
}
}

#else
#include "util/thread.h"

#if defined(HAS_MALLOC_USABLE_SIZE)
#include <malloc.h> // NOLINT
namespace lean {
inline size_t malloc_size(void * ptr)             { return malloc_usable_size(ptr); }
inline void * malloc_core(size_t sz)              { return ::malloc(sz); }
inline void * realloc_core(void * ptr, size_t sz) { return ::realloc(ptr, sz); }
inline void   free_core(void * ptr)               { ::free(ptr); }
}
// REMARK: We commented the following piece of code because tc_malloc_size is hanging

// #elif defined(HAS_TCMALLOC)
// #include <gperftools/tcmalloc.h>
// namespace lean {
// inline size_t malloc_size(void * ptr)             { return tc_malloc_size(ptr); }
// inline void * malloc_core(size_t sz)              { return tc_malloc(sz); }
// inline void * realloc_core(void * ptr, size_t sz) { return tc_realloc(ptr, sz); }
// inline void   free_core(void * ptr)               { tc_free(ptr); }
// }
#elif defined(HAS_MALLOCSIZE)
#include <malloc/malloc.h> // NOLINT
namespace lean {
inline size_t malloc_size(void * ptr)             { return ::malloc_size(ptr); }
inline void * malloc_core(size_t sz)              { return ::malloc(sz); }
inline void * realloc_core(void * ptr, size_t sz) { return ::realloc(ptr, sz); }
inline void   free_core(void * ptr)               { ::free(ptr); }
}
#elif defined(HAS_MSIZE)
#include <malloc.h> // NOLINT
namespace lean {
inline size_t malloc_size(void * ptr)             { return _msize(ptr); }
inline void * malloc_core(size_t sz)              { return ::malloc(sz); }
inline void * realloc_core(void * ptr, size_t sz) { return ::realloc(ptr, sz); }
inline void   free_core(void * ptr)               { ::free(ptr); }
}
#else
namespace lean {
void * save_alloc_size(void * ptr, size_t sz) {
    if (ptr) {
        size_t * r = static_cast<size_t*>(ptr);
        *r = sz;
        return r + 1;
    } else {
        return ptr;
    }
}
inline size_t malloc_size(void * ptr)             { return static_cast<size_t*>(ptr)[-1]; }
inline void * malloc_core(size_t sz)              { return save_alloc_size(::malloc(sz + sizeof(sz)), sz); }
inline void * realloc_core(void * ptr, size_t sz) { return save_alloc_size(::realloc(static_cast<size_t*>(ptr) - 1, sz + sizeof(sz)), sz); }
inline void   free_core(void * ptr)               { ::free(static_cast<size_t*>(ptr) - 1); }
}
#endif

namespace lean {
class alloc_info {
    atomic<size_t> m_size;
public:
    alloc_info():m_size(0) {}
    ~alloc_info() {}
    void inc(size_t sz) { m_size += sz; }
    void dec(size_t sz) { m_size -= sz; }
    size_t size() const { return m_size; }
};

// TODO(Leo): use explicit initialization?
static alloc_info g_global_memory;
static size_t     g_max_memory = 0;

void set_max_memory(size_t max) {
    g_max_memory = max;
}

size_t get_allocated_memory() {
    return g_global_memory.size();
}

void check_memory(char const * component_name) {
    if (g_max_memory != 0 && get_allocated_memory() > g_max_memory)
        throw memory_exception(component_name);
}

void * malloc(size_t sz, bool use_ex)  {
    void * r = malloc_core(sz);
    if (r || sz == 0) {
        size_t rsz = malloc_size(r);
        g_global_memory.inc(rsz);
        return r;
    } else if (use_ex) {
        throw std::bad_alloc();
    } else {
        return nullptr;
    }
}

void * malloc(size_t sz) {
    return malloc(sz, true);
}

void * realloc(void * ptr, size_t sz) {
    if (ptr == nullptr)
        return malloc(sz);
    if (sz == 0) {
        free(ptr);
        return nullptr;
    }
    size_t old_sz = malloc_size(ptr);
    g_global_memory.dec(old_sz);
    void * r = realloc_core(ptr, sz);
    size_t new_sz = malloc_size(r);
    g_global_memory.inc(new_sz);
    if (r || sz == 0)
        return r;
    else
        throw std::bad_alloc();
}

void free(void * ptr) {
    if (ptr) {
        size_t sz = malloc_size(ptr);
        g_global_memory.dec(sz);
    }
    free_core(ptr);
}
}

void* operator new(std::size_t sz) throw(std::bad_alloc) { return lean::malloc(sz, true); }
void  operator delete(void * ptr) throw() { return lean::free(ptr); }
void* operator new[](std::size_t sz) throw(std::bad_alloc) { return lean::malloc(sz, true); }
void  operator delete[](void * ptr) throw() { return lean::free(ptr); }
void* operator new(std::size_t sz, std::nothrow_t const &) noexcept { return lean::malloc(sz, false); }
void* operator new[](std::size_t sz, std::nothrow_t const &) noexcept { return lean::malloc(sz, false); }

#pragma GCC diagnostic ignored "-Wc++14-compat"
void operator delete(void * ptr, size_t _size) throw() { return lean::free(ptr); }
void operator delete[](void * ptr, size_t _size) throw() { return lean::free(ptr); }
#endif
<commit_msg>feat(util/memory.cpp): use COMP_HAS_SIZED_DEALLOCATION macro<commit_after>/*
Copyright (c) 2013 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.

Author: Leonardo de Moura
*/
#include <new>
#include <cstdlib>
#include <iostream>
#include "./compatibility.h"
#include "util/exception.h"
#include "util/memory.h"

namespace lean {
void set_max_memory_megabyte(unsigned max) {
    size_t m = max;
    m *= 1024 * 1024;
    set_max_memory(m);
}
}

#if !defined(LEAN_TRACK_MEMORY)
namespace lean {
size_t     get_allocated_memory() {
    return 0;
}

void set_max_memory(size_t) {
    throw exception("Lean was compiled without memory consumption tracking "
                    "(possible solution: compile using LEAN_TRACK_MEMORY)");
}

void check_memory(char const * component_name) {
    // do nothing when LEAN_TRACK_MEMORY is not defined
}

void * malloc(size_t sz, bool use_ex)  {
    void * r = ::malloc(sz);
    if (r || sz == 0)
        return r;
    else if (use_ex)
        throw std::bad_alloc();
    else
        return nullptr;
}

void * malloc(size_t sz) {
    return malloc(sz, true);
}

void * realloc(void * ptr, size_t sz) {
    void * r = ::realloc(ptr, sz);
    if (r || sz == 0)
        return r;
    else
        throw std::bad_alloc();
}

void free(void * ptr) {
    ::free(ptr);
}
}

#else
#include "util/thread.h"

#if defined(HAS_MALLOC_USABLE_SIZE)
#include <malloc.h> // NOLINT
namespace lean {
inline size_t malloc_size(void * ptr)             { return malloc_usable_size(ptr); }
inline void * malloc_core(size_t sz)              { return ::malloc(sz); }
inline void * realloc_core(void * ptr, size_t sz) { return ::realloc(ptr, sz); }
inline void   free_core(void * ptr)               { ::free(ptr); }
}
// REMARK: We commented the following piece of code because tc_malloc_size is hanging

// #elif defined(HAS_TCMALLOC)
// #include <gperftools/tcmalloc.h>
// namespace lean {
// inline size_t malloc_size(void * ptr)             { return tc_malloc_size(ptr); }
// inline void * malloc_core(size_t sz)              { return tc_malloc(sz); }
// inline void * realloc_core(void * ptr, size_t sz) { return tc_realloc(ptr, sz); }
// inline void   free_core(void * ptr)               { tc_free(ptr); }
// }
#elif defined(HAS_MALLOCSIZE)
#include <malloc/malloc.h> // NOLINT
namespace lean {
inline size_t malloc_size(void * ptr)             { return ::malloc_size(ptr); }
inline void * malloc_core(size_t sz)              { return ::malloc(sz); }
inline void * realloc_core(void * ptr, size_t sz) { return ::realloc(ptr, sz); }
inline void   free_core(void * ptr)               { ::free(ptr); }
}
#elif defined(HAS_MSIZE)
#include <malloc.h> // NOLINT
namespace lean {
inline size_t malloc_size(void * ptr)             { return _msize(ptr); }
inline void * malloc_core(size_t sz)              { return ::malloc(sz); }
inline void * realloc_core(void * ptr, size_t sz) { return ::realloc(ptr, sz); }
inline void   free_core(void * ptr)               { ::free(ptr); }
}
#else
namespace lean {
void * save_alloc_size(void * ptr, size_t sz) {
    if (ptr) {
        size_t * r = static_cast<size_t*>(ptr);
        *r = sz;
        return r + 1;
    } else {
        return ptr;
    }
}
inline size_t malloc_size(void * ptr)             { return static_cast<size_t*>(ptr)[-1]; }
inline void * malloc_core(size_t sz)              { return save_alloc_size(::malloc(sz + sizeof(sz)), sz); }
inline void * realloc_core(void * ptr, size_t sz) { return save_alloc_size(::realloc(static_cast<size_t*>(ptr) - 1, sz + sizeof(sz)), sz); }
inline void   free_core(void * ptr)               { ::free(static_cast<size_t*>(ptr) - 1); }
}
#endif

namespace lean {
class alloc_info {
    atomic<size_t> m_size;
public:
    alloc_info():m_size(0) {}
    ~alloc_info() {}
    void inc(size_t sz) { m_size += sz; }
    void dec(size_t sz) { m_size -= sz; }
    size_t size() const { return m_size; }
};

// TODO(Leo): use explicit initialization?
static alloc_info g_global_memory;
static size_t     g_max_memory = 0;

void set_max_memory(size_t max) {
    g_max_memory = max;
}

size_t get_allocated_memory() {
    return g_global_memory.size();
}

void check_memory(char const * component_name) {
    if (g_max_memory != 0 && get_allocated_memory() > g_max_memory)
        throw memory_exception(component_name);
}

void * malloc(size_t sz, bool use_ex)  {
    void * r = malloc_core(sz);
    if (r || sz == 0) {
        size_t rsz = malloc_size(r);
        g_global_memory.inc(rsz);
        return r;
    } else if (use_ex) {
        throw std::bad_alloc();
    } else {
        return nullptr;
    }
}

void * malloc(size_t sz) {
    return malloc(sz, true);
}

void * realloc(void * ptr, size_t sz) {
    if (ptr == nullptr)
        return malloc(sz);
    if (sz == 0) {
        free(ptr);
        return nullptr;
    }
    size_t old_sz = malloc_size(ptr);
    g_global_memory.dec(old_sz);
    void * r = realloc_core(ptr, sz);
    size_t new_sz = malloc_size(r);
    g_global_memory.inc(new_sz);
    if (r || sz == 0)
        return r;
    else
        throw std::bad_alloc();
}

void free(void * ptr) {
    if (ptr) {
        size_t sz = malloc_size(ptr);
        g_global_memory.dec(sz);
    }
    free_core(ptr);
}
}

void* operator new(std::size_t sz) throw(std::bad_alloc) { return lean::malloc(sz, true); }
void  operator delete(void * ptr) throw() { return lean::free(ptr); }
void* operator new[](std::size_t sz) throw(std::bad_alloc) { return lean::malloc(sz, true); }
void  operator delete[](void * ptr) throw() { return lean::free(ptr); }
void* operator new(std::size_t sz, std::nothrow_t const &) noexcept { return lean::malloc(sz, false); }
void* operator new[](std::size_t sz, std::nothrow_t const &) noexcept { return lean::malloc(sz, false); }

#ifdef COMP_HAS_SIZED_DEALLOCATION
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wc++14-compat"
void operator delete(void * ptr, size_t) throw() { return lean::free(ptr); }
void operator delete[](void * ptr, size_t) throw() { return lean::free(ptr); }
#pragma GCC diagnostic pop
#endif
#endif
<|endoftext|>