<commit_before>#ifndef UTILS_UTILS_HPP
#define UTILS_UTILS_HPP

#include <joint/devkit/ExceptionInfo.hpp>
#include <joint/devkit/JointException.hpp>
#include <joint/devkit/ScopeExit.hpp>
#include <joint/devkit/StringBuilder.hpp>

#include <utils/JPtr.hpp>

#define JNI_WRAP_CPP_BEGIN \
	try {

#define JNI_WRAP_CPP_END(OkRetVal_, FailRetVal_) \
		return (OkRetVal_); \
	} catch (const std::exception& ex) { \
		GetLogger().Error() << JOINT_SOURCE_LOCATION ": " << ex; \
		::joint::java::ThrowJavaException(env, ex.what()); \
		return (FailRetVal_); \
	}

#define JNI_WRAP_CPP_END_VOID() \
	} catch (const std::exception& ex) { \
		GetLogger().Error() << JOINT_SOURCE_LOCATION ": " << ex; \
		::joint::java::ThrowJavaException(env, ex.what()); \
	}

#define JAVA_CALL(...) JAVA_CALL_EX(env, __VA_ARGS__)
#define JAVA_CALL_EX(Env_, ...) ::joint::java::JavaCallImpl(Env_, (__VA_ARGS__), JOINT_SOURCE_LOCATION)

#define JAVA_CALL_VOID(...) JAVA_CALL_VOID_EX(env, __VA_ARGS__)
#define JAVA_CALL_VOID_EX(Env_, ...) do { __VA_ARGS__; ::joint::java::JavaCallImpl(Env_, 0, JOINT_SOURCE_LOCATION); } while (false)

namespace joint {
namespace java
{

	class StringDataHolder
	{
	private:
		JNIEnv*            _env;
		jstring            _strObj;
		const char*        _data;

	public:
		StringDataHolder(JStringWeakRef str)
		{ Init(str.GetEnv(), str.Get()); }

		~StringDataHolder()
		{ _env->ReleaseStringUTFChars(_strObj, _data); }

		const char* GetData() const
		{ return _data; }

	private:
		void Init(JNIEnv* env, jstring str)
		{
			_env = JOINT_DEVKIT_REQUIRE_NOT_NULL(env);
			_strObj = JOINT_DEVKIT_REQUIRE_NOT_NULL(str);
			jboolean is_copy = false;
			_data = _env->GetStringUTFChars(_strObj, &is_copy);
		}
	};

	inline std::string ToStdString(JStringTempRef str)
	{ return StringDataHolder(str.Weak()).GetData(); }

	inline void ThrowJavaException(JNIEnv* env, const std::string& msg)
	{
		const char* LoggerName = "Joint.Java.Utils";

		auto jmsg = JStringLocalRef::StealLocal(env, env->NewStringUTF(msg.c_str()));
		auto RuntimeException_cls = JClassLocalRef::StealLocal(env, env->FindClass("java/lang/RuntimeException"));
		if (!RuntimeException_cls)
			JOINT_TERMINATE("Could not find class java.lang.RuntimeException");

		jmethodID RuntimeException_ctor_id = env->GetMethodID(RuntimeException_cls.Get(), "<init>", "(Ljava/lang/String;)V");
		if (!RuntimeException_ctor_id)
			JOINT_TERMINATE("Could not find java.lang.RuntimeException(java.lang.String) constructor");

		auto ex = JThrowableLocalRef::StealLocal(env, reinterpret_cast<jthrowable>(env->NewObject(RuntimeException_cls.Get(), RuntimeException_ctor_id, jmsg.Get())));
		if (!ex)
			JOINT_TERMINATE("Could not create java.lang.RuntimeException object");

		env->Throw(ex.Get());
	}

#define DETAIL_JOINT_JAVA_TERMINATE_ON_EXCEPTION do { if (env->ExceptionCheck()) JOINT_TERMINATE_EX("Joint.Java.Utils", "Got an exception from java while processing another one"); } while (false)

	inline devkit::ExceptionInfo GetJavaExceptionInfo(JNIEnv *env)
	{
		using namespace devkit;

		if (!env->ExceptionCheck())
			JOINT_TERMINATE_EX("Joint.Java.Utils", "GetJavaExceptionInfo failed: no active java exception");

		jthrowable raw_throwable = env->ExceptionOccurred();
		env->ExceptionClear();
		auto ex = JThrowableLocalRef::StealLocal(env, raw_throwable);

		auto throwable_class = JClassLocalRef::StealLocal(env, env->FindClass("java/lang/Throwable"));
		DETAIL_JOINT_JAVA_TERMINATE_ON_EXCEPTION;
		jmethodID toString_id = env->GetMethodID(throwable_class.Get(), "toString", "()Ljava/lang/String;");
		DETAIL_JOINT_JAVA_TERMINATE_ON_EXCEPTION;
		jmethodID getStackTrace_id = env->GetMethodID(throwable_class.Get(), "getStackTrace", "()[Ljava/lang/StackTraceElement;");
		DETAIL_JOINT_JAVA_TERMINATE_ON_EXCEPTION;
		auto jmsg = JStringLocalRef::StealLocal(env, env->CallObjectMethod(ex.Get(), toString_id));
		DETAIL_JOINT_JAVA_TERMINATE_ON_EXCEPTION;

		auto ste_class = JClassLocalRef::StealLocal(env, env->FindClass("java/lang/StackTraceElement"));
		DETAIL_JOINT_JAVA_TERMINATE_ON_EXCEPTION;
		jmethodID ste_getClassName_id = env->GetMethodID(ste_class.Get(), "getClassName", "()Ljava/lang/String;");
		DETAIL_JOINT_JAVA_TERMINATE_ON_EXCEPTION;
		jmethodID ste_getFileName_id = env->GetMethodID(ste_class.Get(), "getFileName", "()Ljava/lang/String;");
		DETAIL_JOINT_JAVA_TERMINATE_ON_EXCEPTION;
		jmethodID ste_getLineNumber_id = env->GetMethodID(ste_class.Get(), "getLineNumber", "()I");
		DETAIL_JOINT_JAVA_TERMINATE_ON_EXCEPTION;
		jmethodID ste_getMethodName_id = env->GetMethodID(ste_class.Get(), "getMethodName", "()Ljava/lang/String;");
		DETAIL_JOINT_JAVA_TERMINATE_ON_EXCEPTION;
		auto jst = JObjArrayLocalRef::StealLocal(env, env->CallObjectMethod(ex.Get(), getStackTrace_id));
		DETAIL_JOINT_JAVA_TERMINATE_ON_EXCEPTION;

		auto st_len = env->GetArrayLength(jst.Get());
		ExceptionInfo::StackTrace st;

		auto JointException_cls = JClassLocalRef::StealLocal(env, env->FindClass("org/joint/JointException"));
		DETAIL_JOINT_JAVA_TERMINATE_ON_EXCEPTION;
		if (env->IsInstanceOf(ex.Get(), JointException_cls.Get()))
		{
			jfieldID nativeData_id = env->GetFieldID(JointException_cls.Get(), "nativeData", "J");
			DETAIL_JOINT_JAVA_TERMINATE_ON_EXCEPTION;
			auto ex_info = reinterpret_cast<const ExceptionInfo*>(env->GetLongField(ex.Get(), nativeData_id));
			DETAIL_JOINT_JAVA_TERMINATE_ON_EXCEPTION;
			if (ex_info)
			{
				st.reserve(st_len + ex_info->GetStackTrace().size());
				std::copy(ex_info->GetStackTrace().begin(), ex_info->GetStackTrace().end(), std::back_inserter(st));
			}
		}

		st.reserve(st_len);

		for (int i = 0; i < st_len; ++i)
		{
			auto ste = JObjLocalRef::StealLocal(env, env->GetObjectArrayElement(jst.Get(), i));
			DETAIL_JOINT_JAVA_TERMINATE_ON_EXCEPTION;
			auto class_name = JStringLocalRef::StealLocal(env, env->CallObjectMethod(ste.Get(), ste_getClassName_id));
			DETAIL_JOINT_JAVA_TERMINATE_ON_EXCEPTION;
			auto file_name = JStringLocalRef::StealLocal(env, env->CallObjectMethod(ste.Get(), ste_getFileName_id));
			DETAIL_JOINT_JAVA_TERMINATE_ON_EXCEPTION;
			jint line_num = env->CallIntMethod(ste.Get(), ste_getLineNumber_id);
			DETAIL_JOINT_JAVA_TERMINATE_ON_EXCEPTION;
			auto method_name = JStringLocalRef::StealLocal(env, env->CallObjectMethod(ste.Get(), ste_getMethodName_id));
			DETAIL_JOINT_JAVA_TERMINATE_ON_EXCEPTION;
			st.emplace_back(
					"",
					StringDataHolder(file_name).GetData(),
					line_num,
					"",
					StringBuilder() % StringDataHolder(class_name).GetData() % "." % StringDataHolder(method_name).GetData()
				);
		}

		return ExceptionInfo(StringDataHolder(jmsg).GetData(), st);
	}

#undef DETAIL_JOINT_JAVA_TERMINATE_ON_EXCEPTION

	void ThrowExceptionFromJava(JNIEnv* env, const char* location);

	template < typename T_ >
	T_ JavaCallImpl(JNIEnv *env, T_ result, const char* location)
	{
		if (env->ExceptionCheck())
			ThrowExceptionFromJava(env, location);

		return result;
	}

}}

#endif
<commit_msg>Added env->ExceptionDescribe() to DETAIL_JOINT_JAVA_TERMINATE_ON_EXCEPTION macro<commit_after>#ifndef UTILS_UTILS_HPP
#define UTILS_UTILS_HPP

#include <joint/devkit/ExceptionInfo.hpp>
#include <joint/devkit/JointException.hpp>
#include <joint/devkit/ScopeExit.hpp>
#include <joint/devkit/StringBuilder.hpp>

#include <utils/JPtr.hpp>

#define JNI_WRAP_CPP_BEGIN \
	try {

#define JNI_WRAP_CPP_END(OkRetVal_, FailRetVal_) \
		return (OkRetVal_); \
	} catch (const std::exception& ex) { \
		GetLogger().Error() << JOINT_SOURCE_LOCATION ": " << ex; \
		::joint::java::ThrowJavaException(env, ex.what()); \
		return (FailRetVal_); \
	}

#define JNI_WRAP_CPP_END_VOID() \
	} catch (const std::exception& ex) { \
		GetLogger().Error() << JOINT_SOURCE_LOCATION ": " << ex; \
		::joint::java::ThrowJavaException(env, ex.what()); \
	}

#define JAVA_CALL(...) JAVA_CALL_EX(env, __VA_ARGS__)
#define JAVA_CALL_EX(Env_, ...) ::joint::java::JavaCallImpl(Env_, (__VA_ARGS__), JOINT_SOURCE_LOCATION)

#define JAVA_CALL_VOID(...) JAVA_CALL_VOID_EX(env, __VA_ARGS__)
#define JAVA_CALL_VOID_EX(Env_, ...) do { __VA_ARGS__; ::joint::java::JavaCallImpl(Env_, 0, JOINT_SOURCE_LOCATION); } while (false)

namespace joint {
namespace java
{

	class StringDataHolder
	{
	private:
		JNIEnv*            _env;
		jstring            _strObj;
		const char*        _data;

	public:
		StringDataHolder(JStringWeakRef str)
		{ Init(str.GetEnv(), str.Get()); }

		~StringDataHolder()
		{ _env->ReleaseStringUTFChars(_strObj, _data); }

		const char* GetData() const
		{ return _data; }

	private:
		void Init(JNIEnv* env, jstring str)
		{
			_env = JOINT_DEVKIT_REQUIRE_NOT_NULL(env);
			_strObj = JOINT_DEVKIT_REQUIRE_NOT_NULL(str);
			jboolean is_copy = false;
			_data = _env->GetStringUTFChars(_strObj, &is_copy);
		}
	};

	inline std::string ToStdString(JStringTempRef str)
	{ return StringDataHolder(str.Weak()).GetData(); }

	inline void ThrowJavaException(JNIEnv* env, const std::string& msg)
	{
		const char* LoggerName = "Joint.Java.Utils";

		auto jmsg = JStringLocalRef::StealLocal(env, env->NewStringUTF(msg.c_str()));
		auto RuntimeException_cls = JClassLocalRef::StealLocal(env, env->FindClass("java/lang/RuntimeException"));
		if (!RuntimeException_cls)
			JOINT_TERMINATE("Could not find class java.lang.RuntimeException");

		jmethodID RuntimeException_ctor_id = env->GetMethodID(RuntimeException_cls.Get(), "<init>", "(Ljava/lang/String;)V");
		if (!RuntimeException_ctor_id)
			JOINT_TERMINATE("Could not find java.lang.RuntimeException(java.lang.String) constructor");

		auto ex = JThrowableLocalRef::StealLocal(env, reinterpret_cast<jthrowable>(env->NewObject(RuntimeException_cls.Get(), RuntimeException_ctor_id, jmsg.Get())));
		if (!ex)
			JOINT_TERMINATE("Could not create java.lang.RuntimeException object");

		env->Throw(ex.Get());
	}

#define DETAIL_JOINT_JAVA_TERMINATE_ON_EXCEPTION \
		do { \
			if (env->ExceptionCheck()) \
			{ \
				env->ExceptionDescribe(); \
				JOINT_TERMINATE_EX("Joint.Java.Utils", "Got an exception from java while processing another one"); \
			} \
		} while (false)

	inline devkit::ExceptionInfo GetJavaExceptionInfo(JNIEnv *env)
	{
		using namespace devkit;

		if (!env->ExceptionCheck())
			JOINT_TERMINATE_EX("Joint.Java.Utils", "GetJavaExceptionInfo failed: no active java exception");

		jthrowable raw_throwable = env->ExceptionOccurred();
		env->ExceptionClear();
		auto ex = JThrowableLocalRef::StealLocal(env, raw_throwable);

		auto throwable_class = JClassLocalRef::StealLocal(env, env->FindClass("java/lang/Throwable"));
		DETAIL_JOINT_JAVA_TERMINATE_ON_EXCEPTION;
		jmethodID toString_id = env->GetMethodID(throwable_class.Get(), "toString", "()Ljava/lang/String;");
		DETAIL_JOINT_JAVA_TERMINATE_ON_EXCEPTION;
		jmethodID getStackTrace_id = env->GetMethodID(throwable_class.Get(), "getStackTrace", "()[Ljava/lang/StackTraceElement;");
		DETAIL_JOINT_JAVA_TERMINATE_ON_EXCEPTION;
		auto jmsg = JStringLocalRef::StealLocal(env, env->CallObjectMethod(ex.Get(), toString_id));
		DETAIL_JOINT_JAVA_TERMINATE_ON_EXCEPTION;

		auto ste_class = JClassLocalRef::StealLocal(env, env->FindClass("java/lang/StackTraceElement"));
		DETAIL_JOINT_JAVA_TERMINATE_ON_EXCEPTION;
		jmethodID ste_getClassName_id = env->GetMethodID(ste_class.Get(), "getClassName", "()Ljava/lang/String;");
		DETAIL_JOINT_JAVA_TERMINATE_ON_EXCEPTION;
		jmethodID ste_getFileName_id = env->GetMethodID(ste_class.Get(), "getFileName", "()Ljava/lang/String;");
		DETAIL_JOINT_JAVA_TERMINATE_ON_EXCEPTION;
		jmethodID ste_getLineNumber_id = env->GetMethodID(ste_class.Get(), "getLineNumber", "()I");
		DETAIL_JOINT_JAVA_TERMINATE_ON_EXCEPTION;
		jmethodID ste_getMethodName_id = env->GetMethodID(ste_class.Get(), "getMethodName", "()Ljava/lang/String;");
		DETAIL_JOINT_JAVA_TERMINATE_ON_EXCEPTION;
		auto jst = JObjArrayLocalRef::StealLocal(env, env->CallObjectMethod(ex.Get(), getStackTrace_id));
		DETAIL_JOINT_JAVA_TERMINATE_ON_EXCEPTION;

		auto st_len = env->GetArrayLength(jst.Get());
		ExceptionInfo::StackTrace st;

		auto JointException_cls = JClassLocalRef::StealLocal(env, env->FindClass("org/joint/JointException"));
		DETAIL_JOINT_JAVA_TERMINATE_ON_EXCEPTION;
		if (env->IsInstanceOf(ex.Get(), JointException_cls.Get()))
		{
			jfieldID nativeData_id = env->GetFieldID(JointException_cls.Get(), "nativeData", "J");
			DETAIL_JOINT_JAVA_TERMINATE_ON_EXCEPTION;
			auto ex_info = reinterpret_cast<const ExceptionInfo*>(env->GetLongField(ex.Get(), nativeData_id));
			DETAIL_JOINT_JAVA_TERMINATE_ON_EXCEPTION;
			if (ex_info)
			{
				st.reserve(st_len + ex_info->GetStackTrace().size());
				std::copy(ex_info->GetStackTrace().begin(), ex_info->GetStackTrace().end(), std::back_inserter(st));
			}
		}

		st.reserve(st_len);

		for (int i = 0; i < st_len; ++i)
		{
			auto ste = JObjLocalRef::StealLocal(env, env->GetObjectArrayElement(jst.Get(), i));
			DETAIL_JOINT_JAVA_TERMINATE_ON_EXCEPTION;
			auto class_name = JStringLocalRef::StealLocal(env, env->CallObjectMethod(ste.Get(), ste_getClassName_id));
			DETAIL_JOINT_JAVA_TERMINATE_ON_EXCEPTION;
			auto file_name = JStringLocalRef::StealLocal(env, env->CallObjectMethod(ste.Get(), ste_getFileName_id));
			DETAIL_JOINT_JAVA_TERMINATE_ON_EXCEPTION;
			jint line_num = env->CallIntMethod(ste.Get(), ste_getLineNumber_id);
			DETAIL_JOINT_JAVA_TERMINATE_ON_EXCEPTION;
			auto method_name = JStringLocalRef::StealLocal(env, env->CallObjectMethod(ste.Get(), ste_getMethodName_id));
			DETAIL_JOINT_JAVA_TERMINATE_ON_EXCEPTION;
			st.emplace_back(
					"",
					StringDataHolder(file_name).GetData(),
					line_num,
					"",
					StringBuilder() % StringDataHolder(class_name).GetData() % "." % StringDataHolder(method_name).GetData()
				);
		}

		return ExceptionInfo(StringDataHolder(jmsg).GetData(), st);
	}

#undef DETAIL_JOINT_JAVA_TERMINATE_ON_EXCEPTION

	void ThrowExceptionFromJava(JNIEnv* env, const char* location);

	template < typename T_ >
	T_ JavaCallImpl(JNIEnv *env, T_ result, const char* location)
	{
		if (env->ExceptionCheck())
			ThrowExceptionFromJava(env, location);

		return result;
	}

}}

#endif
<|endoftext|>


<commit_before>// Copyright Daniel Wallin 2006. Use, modification and distribution is
// subject to the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#include <libtorrent/alert.hpp>
#include <libtorrent/alert_types.hpp>
#include <boost/python.hpp>

using namespace boost::python;
using namespace libtorrent;

extern char const* alert_doc;
extern char const* alert_msg_doc;
extern char const* alert_severity_doc;
extern char const* listen_failed_alert_doc;
extern char const* file_error_alert_doc;
extern char const* tracker_announce_alert_doc;
extern char const* tracker_alert_doc;
extern char const* tracker_reply_alert_doc;
extern char const* tracker_warning_alert_doc;
extern char const* url_seed_alert_doc;
extern char const* hash_failed_alert_doc;
extern char const* peer_ban_alert_doc;
extern char const* peer_error_alert_doc;
extern char const* invalid_request_alert_doc;
extern char const* peer_request_doc;
extern char const* torrent_finished_alert_doc;
extern char const* metadata_failed_alert_doc;
extern char const* metadata_received_alert_doc;
extern char const* fastresume_rejected_alert_doc;

void bind_alert()
{
    using boost::noncopyable;

    {
        scope alert_scope = class_<alert, noncopyable>("alert", alert_doc, no_init)
            .def(
                "msg", &alert::msg, return_value_policy<copy_const_reference>()
              , alert_msg_doc
            )
            .def("severity", &alert::severity, alert_severity_doc)
            .def(
                "__str__", &alert::msg, return_value_policy<copy_const_reference>()
              , alert_msg_doc
            )
            ;

        enum_<alert::severity_t>("severity_levels")
            .value("debug", alert::severity_t::debug)
            .value("info", alert::severity_t::info)
            .value("warning", alert::severity_t::warning)
            .value("critical", alert::severity_t::critical)
            .value("fatal", alert::severity_t::fatal)
            .value("none", alert::severity_t::none)
            ;
    }

    class_<listen_failed_alert, bases<alert>, noncopyable>(
        "listen_failed_alert", listen_failed_alert_doc, no_init
    );

    class_<file_error_alert, bases<alert>, noncopyable>(
        "file_error_alert", file_error_alert_doc, no_init
    )
        .def_readonly("handle", &file_error_alert::handle)
        ;

    class_<tracker_announce_alert, bases<alert>, noncopyable>(
        "tracker_announce_alert", tracker_announce_alert_doc, no_init
    )
        .def_readonly("handle", &tracker_announce_alert::handle)
        ;

    class_<tracker_alert, bases<alert>, noncopyable>(
        "tracker_alert", tracker_alert_doc, no_init
    )
        .def_readonly("handle", &tracker_alert::handle)
        .def_readonly("times_in_row", &tracker_alert::times_in_row)
        .def_readonly("status_code", &tracker_alert::status_code)
        ;

    class_<tracker_reply_alert, bases<alert>, noncopyable>(
        "tracker_reply_alert", tracker_reply_alert_doc, no_init
    )
        .def_readonly("handle", &tracker_reply_alert::handle)
        ;

    class_<tracker_warning_alert, bases<alert>, noncopyable>(
        "tracker_warning_alert", tracker_warning_alert_doc, no_init
    )
        .def_readonly("handle", &tracker_warning_alert::handle)
        ;

    class_<url_seed_alert, bases<alert>, noncopyable>(
        "url_seed_alert", url_seed_alert_doc, no_init
    )
        .def_readonly("url", &url_seed_alert::url)
        ;

    class_<hash_failed_alert, bases<alert>, noncopyable>(
        "hash_failed_alert", hash_failed_alert_doc, no_init
    )
        .def_readonly("handle", &hash_failed_alert::handle)
        .def_readonly("piece_index", &hash_failed_alert::piece_index)
        ;

    class_<peer_ban_alert, bases<alert>, noncopyable>(
        "peer_ban_alert", peer_ban_alert_doc, no_init
    )
        .def_readonly("ip", &peer_ban_alert::ip)
        .def_readonly("handle", &peer_ban_alert::handle)
        ;

    class_<peer_error_alert, bases<alert>, noncopyable>(
        "peer_error_alert", peer_error_alert_doc, no_init
    )
        .def_readonly("ip", &peer_error_alert::ip)
        .def_readonly("pid", &peer_error_alert::pid)
        ;

    class_<invalid_request_alert, bases<alert>, noncopyable>(
        "invalid_request_alert", invalid_request_alert_doc, no_init
    )
        .def_readonly("handle", &invalid_request_alert::handle)
        .def_readonly("ip", &invalid_request_alert::ip)
        .def_readonly("request", &invalid_request_alert::request)
        .def_readonly("pid", &invalid_request_alert::pid)
        ;

    class_<peer_request>("peer_request", peer_request_doc)
        .def_readonly("piece", &peer_request::piece)
        .def_readonly("start", &peer_request::start)
        .def_readonly("length", &peer_request::length)
        .def(self == self)
        ;

    class_<torrent_finished_alert, bases<alert>, noncopyable>(
        "torrent_finished_alert", torrent_finished_alert_doc, no_init
    )
        .def_readonly("handle", &torrent_finished_alert::handle)
        ;

    class_<metadata_failed_alert, bases<alert>, noncopyable>(
        "metadata_failed_alert", metadata_failed_alert_doc, no_init
    )
        .def_readonly("handle", &metadata_failed_alert::handle)
        ;

    class_<metadata_received_alert, bases<alert>, noncopyable>(
        "metadata_received_alert", metadata_received_alert_doc, no_init
    )
        .def_readonly("handle", &metadata_received_alert::handle)
        ;

    class_<fastresume_rejected_alert, bases<alert>, noncopyable>(
        "fastresume_rejected_alert", fastresume_rejected_alert_doc, no_init
    )
        .def_readonly("handle", &fastresume_rejected_alert::handle)
        ;
}

<commit_msg>fixed typo<commit_after>// Copyright Daniel Wallin 2006. Use, modification and distribution is
// subject to the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#include <libtorrent/alert.hpp>
#include <libtorrent/alert_types.hpp>
#include <boost/python.hpp>

using namespace boost::python;
using namespace libtorrent;

extern char const* alert_doc;
extern char const* alert_msg_doc;
extern char const* alert_severity_doc;
extern char const* listen_failed_alert_doc;
extern char const* file_error_alert_doc;
extern char const* tracker_announce_alert_doc;
extern char const* tracker_alert_doc;
extern char const* tracker_reply_alert_doc;
extern char const* tracker_warning_alert_doc;
extern char const* url_seed_alert_doc;
extern char const* hash_failed_alert_doc;
extern char const* peer_ban_alert_doc;
extern char const* peer_error_alert_doc;
extern char const* invalid_request_alert_doc;
extern char const* peer_request_doc;
extern char const* torrent_finished_alert_doc;
extern char const* metadata_failed_alert_doc;
extern char const* metadata_received_alert_doc;
extern char const* fastresume_rejected_alert_doc;

void bind_alert()
{
    using boost::noncopyable;

    {
        scope alert_scope = class_<alert, noncopyable>("alert", alert_doc, no_init)
            .def(
                "msg", &alert::msg, return_value_policy<copy_const_reference>()
              , alert_msg_doc
            )
            .def("severity", &alert::severity, alert_severity_doc)
            .def(
                "__str__", &alert::msg, return_value_policy<copy_const_reference>()
              , alert_msg_doc
            )
            ;

        enum_<alert::severity_t>("severity_levels")
            .value("debug", alert::debug)
            .value("info", alert::info)
            .value("warning", alert::warning)
            .value("critical", alert::critical)
            .value("fatal", alert::fatal)
            .value("none", alert::none)
            ;
    }

    class_<listen_failed_alert, bases<alert>, noncopyable>(
        "listen_failed_alert", listen_failed_alert_doc, no_init
    );

    class_<file_error_alert, bases<alert>, noncopyable>(
        "file_error_alert", file_error_alert_doc, no_init
    )
        .def_readonly("handle", &file_error_alert::handle)
        ;

    class_<tracker_announce_alert, bases<alert>, noncopyable>(
        "tracker_announce_alert", tracker_announce_alert_doc, no_init
    )
        .def_readonly("handle", &tracker_announce_alert::handle)
        ;

    class_<tracker_alert, bases<alert>, noncopyable>(
        "tracker_alert", tracker_alert_doc, no_init
    )
        .def_readonly("handle", &tracker_alert::handle)
        .def_readonly("times_in_row", &tracker_alert::times_in_row)
        .def_readonly("status_code", &tracker_alert::status_code)
        ;

    class_<tracker_reply_alert, bases<alert>, noncopyable>(
        "tracker_reply_alert", tracker_reply_alert_doc, no_init
    )
        .def_readonly("handle", &tracker_reply_alert::handle)
        ;

    class_<tracker_warning_alert, bases<alert>, noncopyable>(
        "tracker_warning_alert", tracker_warning_alert_doc, no_init
    )
        .def_readonly("handle", &tracker_warning_alert::handle)
        ;

    class_<url_seed_alert, bases<alert>, noncopyable>(
        "url_seed_alert", url_seed_alert_doc, no_init
    )
        .def_readonly("url", &url_seed_alert::url)
        ;

    class_<hash_failed_alert, bases<alert>, noncopyable>(
        "hash_failed_alert", hash_failed_alert_doc, no_init
    )
        .def_readonly("handle", &hash_failed_alert::handle)
        .def_readonly("piece_index", &hash_failed_alert::piece_index)
        ;

    class_<peer_ban_alert, bases<alert>, noncopyable>(
        "peer_ban_alert", peer_ban_alert_doc, no_init
    )
        .def_readonly("ip", &peer_ban_alert::ip)
        .def_readonly("handle", &peer_ban_alert::handle)
        ;

    class_<peer_error_alert, bases<alert>, noncopyable>(
        "peer_error_alert", peer_error_alert_doc, no_init
    )
        .def_readonly("ip", &peer_error_alert::ip)
        .def_readonly("pid", &peer_error_alert::pid)
        ;

    class_<invalid_request_alert, bases<alert>, noncopyable>(
        "invalid_request_alert", invalid_request_alert_doc, no_init
    )
        .def_readonly("handle", &invalid_request_alert::handle)
        .def_readonly("ip", &invalid_request_alert::ip)
        .def_readonly("request", &invalid_request_alert::request)
        .def_readonly("pid", &invalid_request_alert::pid)
        ;

    class_<peer_request>("peer_request", peer_request_doc)
        .def_readonly("piece", &peer_request::piece)
        .def_readonly("start", &peer_request::start)
        .def_readonly("length", &peer_request::length)
        .def(self == self)
        ;

    class_<torrent_finished_alert, bases<alert>, noncopyable>(
        "torrent_finished_alert", torrent_finished_alert_doc, no_init
    )
        .def_readonly("handle", &torrent_finished_alert::handle)
        ;

    class_<metadata_failed_alert, bases<alert>, noncopyable>(
        "metadata_failed_alert", metadata_failed_alert_doc, no_init
    )
        .def_readonly("handle", &metadata_failed_alert::handle)
        ;

    class_<metadata_received_alert, bases<alert>, noncopyable>(
        "metadata_received_alert", metadata_received_alert_doc, no_init
    )
        .def_readonly("handle", &metadata_received_alert::handle)
        ;

    class_<fastresume_rejected_alert, bases<alert>, noncopyable>(
        "fastresume_rejected_alert", fastresume_rejected_alert_doc, no_init
    )
        .def_readonly("handle", &fastresume_rejected_alert::handle)
        ;
}

<|endoftext|>


<commit_before>/******************************************************************************
The MIT License(MIT)

Embedded Template Library.

Copyright(c) 2014 jwellbelove

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 <UnitTest++/UnitTest++.h>

#include <iterator>
#include <cstdint>
#include "../crc8.h"
#include "../crc16.h"
#include "../crc16_ccitt.h"
#include "../crc16_kermit.h"
#include "../crc32.h"
#include "../crc64_ecma.h"

namespace
{
  SUITE(TestCRC)
  {
    //*************************************************************************
    TEST(TestCRC8)
    {
      unsigned char data[] = { '1', '2', '3', '4', '5', '6', '7', '8', '9' };

      uint8_t crc = etl::crc8(std::begin(data), std::end(data));

      CHECK_EQUAL(0xF4, crc);
    }

    //*************************************************************************
    TEST(TestCRC16)
    {
      unsigned char data[] = { '1', '2', '3', '4', '5', '6', '7', '8', '9' };

      uint16_t crc = etl::crc16(std::begin(data), std::end(data));

      CHECK_EQUAL(0xBB3D, crc);
    }

    //*************************************************************************
    TEST(TestCRC16CCITT)
    {
      unsigned char data[] = { '1', '2', '3', '4', '5', '6', '7', '8', '9' };

      uint16_t crc = etl::crc16_ccitt(std::begin(data), std::end(data));

      CHECK_EQUAL(0x29B1, crc);
    }

    //*************************************************************************
    TEST(TestCRC16Kermit)
    {
      unsigned char data[] = { '1', '2', '3', '4', '5', '6', '7', '8', '9' };

      uint16_t crc = etl::crc16_kermit(std::begin(data), std::end(data));

      CHECK_EQUAL(0x2189, crc);
    }

    //*************************************************************************
    TEST(TestCRC32)
    {
      unsigned char data[] = { '1', '2', '3', '4', '5', '6', '7', '8', '9' };

      uint32_t crc = etl::crc32(std::begin(data), std::end(data));

      CHECK_EQUAL(0xCBF43926, crc);
    }

    //*************************************************************************
    TEST(TestCRC64ECMA)
    {
      unsigned char data[] = { '1', '2', '3', '4', '5', '6', '7', '8', '9' };

      uint64_t crc = etl::crc64_ecma(std::begin(data), std::end(data));

      CHECK_EQUAL(0x6C40DF5F0B497347, crc);
    }
  };
}

<commit_msg>CRC unit tests<commit_after>/******************************************************************************
The MIT License(MIT)

Embedded Template Library.

Copyright(c) 2014 jwellbelove

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 <UnitTest++/UnitTest++.h>

#include <iterator>
#include <string>
#include <cstdint>
#include "../crc8_ccitt.h"
#include "../crc16.h"
#include "../crc16_ccitt.h"
#include "../crc16_kermit.h"
#include "../crc32.h"
#include "../crc64_ecma.h"

namespace
{
  SUITE(TestCRC)
  {
    //*************************************************************************
    TEST(TestCRC8)
    {
      std::string data("123456789");

      uint8_t crc = etl::crc8_ccitt(data.begin(), data.end());

      CHECK_EQUAL(0xF4, crc);
    }

    //*************************************************************************
    TEST(TestCRC16)
    {
      std::string data("123456789");

      uint16_t crc = etl::crc16(data.begin(), data.end());

      CHECK_EQUAL(0xBB3D, crc);
    }

    //*************************************************************************
    TEST(TestCRC16CCITT)
    {
      std::string data("123456789");

      uint16_t crc = etl::crc16_ccitt(data.begin(), data.end());

      CHECK_EQUAL(0x29B1, crc);
    }

    //*************************************************************************
    TEST(TestCRC16Kermit)
    {
      std::string data("123456789");

      uint16_t crc = etl::crc16_kermit(data.begin(), data.end());

      CHECK_EQUAL(0x2189, crc);
    }

    //*************************************************************************
    TEST(TestCRC32)
    {
      std::string data("123456789");

      uint32_t crc = etl::crc32(data.begin(), data.end());

      CHECK_EQUAL(0xCBF43926, crc);
    }

    //*************************************************************************
    TEST(TestCRC64ECMA)
    {
      std::string data("123456789");

      uint64_t crc = etl::crc64_ecma(data.begin(), data.end());

      CHECK_EQUAL(0x6C40DF5F0B497347, crc);
    }
  };
}

<|endoftext|>


<commit_before>#include "greedy_solver.h"

#include <algorithm>
#include <cassert>
#include <functional>
#include <vector>

#include "cyc_limits.h"
#include "error.h"
#include "logger.h"

namespace cyclus {

double Capacity(const Arc& a, double u_curr_qty, double v_curr_qty) {
  bool min = true;
  double ucap = Capacity(a.unode(), a, !min, u_curr_qty);
  double vcap = Capacity(a.vnode(), a, min, v_curr_qty);

  CLOG(cyclus::LEV_DEBUG1) << "Capacity for unode of arc: " << ucap;
  CLOG(cyclus::LEV_DEBUG1) << "Capacity for vnode of arc: " << vcap;
  CLOG(cyclus::LEV_DEBUG1) << "Capacity for arc         : "
                           << std::min(ucap, vcap);

  return std::min(ucap, vcap);
}

double Capacity(ExchangeNode::Ptr n, const Arc& a, bool min_cap,
                double curr_qty) {
  if (n->group == NULL) {
    throw cyclus::StateError("An notion of node capacity requires a nodegroup.");
  }

  if (n->unit_capacities[a].size() == 0) {
    return n->qty - curr_qty;
  }

  std::vector<double>& unit_caps = n->unit_capacities[a];
  const std::vector<double>& group_caps = n->group->capacities();
  std::vector<double> caps;
  double grp_cap, u_cap, cap;

  for (int i = 0; i < unit_caps.size(); i++) {
    grp_cap = group_caps[i];
    u_cap = unit_caps[i];
    cap = grp_cap / u_cap;
    CLOG(cyclus::LEV_DEBUG1) << "Capacity for node: ";
    CLOG(cyclus::LEV_DEBUG1) << "   group capacity: " << grp_cap;
    CLOG(cyclus::LEV_DEBUG1) << "    unit capacity: " << u_cap;
    CLOG(cyclus::LEV_DEBUG1) << "         capacity: " << cap;

    // special case for unlimited capacities
    if (grp_cap == std::numeric_limits<double>::max()) {
      caps.push_back(std::numeric_limits<double>::max());
    } else {
      caps.push_back(cap);
    }
  }

  if (min_cap) {  // the smallest value is constraining (for bids)
    cap = *std::min_element(caps.begin(), caps.end());
  } else {  // the largest value must be met (for requests)
    cap = *std::max_element(caps.begin(), caps.end());
  }
  return std::min(cap, n->qty - curr_qty);
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
GreedySolver::GreedySolver(bool exclusive_orders, GreedyPreconditioner* c)
    : conditioner_(c),
      ExchangeSolver(exclusive_orders) {}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
GreedySolver::~GreedySolver() {
  if (conditioner_ != NULL)
    delete conditioner_;
}

void GreedySolver::Condition() {
  if (conditioner_ == NULL)
    conditioner_ = new GreedyPreconditioner(std::map<std::string, double>());

  conditioner_->Condition(graph_);
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
double GreedySolver::SolveGraph() {
  Condition();
  obj_ = 0;
  unmatched_ = 0;
  n_qty_.clear();

  std::for_each(graph_->request_groups().begin(),
                graph_->request_groups().end(),
                std::bind1st(
                    std::mem_fun(&GreedySolver::Init_),
                    this));

  std::for_each(graph_->supply_groups().begin(),
                graph_->supply_groups().end(),
                std::bind1st(
                    std::mem_fun(&GreedySolver::Init_),
                    this));

  std::for_each(graph_->request_groups().begin(),
                graph_->request_groups().end(),
                std::bind1st(
                    std::mem_fun(&GreedySolver::GreedilySatisfySet_),
                    this));

  obj_ += unmatched_ * PseudoCost_();
  return obj_;
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void GreedySolver::Init_(ExchangeNodeGroup::Ptr g) {
  for (int i = 0; i != g->nodes().size(); i++) {
    n_qty_[g->nodes()[i]] = 0;
  }
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void GreedySolver::GreedilySatisfySet_(RequestGroup::Ptr prs) {
  std::vector<ExchangeNode::Ptr>& nodes = prs->nodes();
  std::stable_sort(nodes.begin(), nodes.end(), AvgPrefComp);

  std::vector<ExchangeNode::Ptr>::iterator req_it = nodes.begin();
  double target = prs->qty();
  double match = 0;

  ExchangeNode::Ptr u, v;
  std::vector<Arc>::const_iterator arc_it;
  std::vector<Arc> sorted;
  double remain, tomatch, excl_val;

  CLOG(LEV_DEBUG1) << "Greedy Solving for " << target
                   << " amount of a resource.";

  while ((match <= target) && (req_it != nodes.end())) {
    // this if statement is needed because map.at() will throw if the key does
    // not exist, which is a corner case for when there is a request with no bid
    // arcs associated with it
    if (graph_->node_arc_map().count(*req_it) > 0) {
      const std::vector<Arc>& arcs = graph_->node_arc_map().at(*req_it);
      sorted = std::vector<Arc>(arcs);  // make a copy for now
      std::stable_sort(sorted.begin(), sorted.end(), ReqPrefComp);
      arc_it = sorted.begin();

      while ((match <= target) && (arc_it != sorted.end())) {
        remain = target - match;
        const Arc& a = *arc_it;
        u = a.unode();
        v = a.vnode();

        // capacity adjustment
        tomatch = std::min(remain, Capacity(a, n_qty_[u], n_qty_[v]));

        // exclusivity adjustment
        if (arc_it->exclusive()) {
          excl_val = a.excl_val();
          tomatch = (tomatch < excl_val) ? 0 : excl_val;
        }

        if (tomatch > eps()) {
          CLOG(LEV_DEBUG1) << "Greedy Solver is matching " << tomatch
                           << " amount of a resource.";
          UpdateCapacity_(u, a, tomatch);
          UpdateCapacity_(v, a, tomatch);
          n_qty_[u] += tomatch;
          n_qty_[v] += tomatch;
          graph_->AddMatch(a, tomatch);

          match += tomatch;
          UpdateObj_(tomatch, u->prefs[a]);
        }
        ++arc_it;
      }  // while( (match =< target) && (arc_it != arcs.end()) )
    }  // if(graph_->node_arc_map().count(*req_it) > 0)
    ++req_it;
  }  // while( (match =< target) && (req_it != nodes.end()) )

  unmatched_ += target - match;
}

void GreedySolver::UpdateObj_(double qty, double pref) {
  // updates minimizing object (i.e., 1/pref is a cost and the objective is cost
  // * flow)
  obj_ += qty / pref;
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void GreedySolver::UpdateCapacity_(ExchangeNode::Ptr n, const Arc& a,
                                   double qty) {
  using cyclus::IsNegative;
  using cyclus::ValueError;

  std::vector<double>& unit_caps = n->unit_capacities[a];
  std::vector<double>& caps = n->group->capacities();
  assert(unit_caps.size() == caps.size());
  for (int i = 0; i < caps.size(); i++) {
    double prev = caps[i];
    // special case for unlimited capacities
    CLOG(cyclus::LEV_DEBUG1) << "Updating capacity value from: "
                             << prev;
    caps[i] = (prev == std::numeric_limits<double>::max()) ?
              std::numeric_limits<double>::max() :
              prev - qty * unit_caps[i];
    CLOG(cyclus::LEV_DEBUG1) << "                          to: "
                             << caps[i];
  }

  if (IsNegative(n->qty - qty)) {
    std::stringstream ss;
    ss << "A bid for " << n->commod << " was set at " << n->qty
       << " but has been matched to a higher value " << qty
       << ". This could be due to a problem with your "
       << "bid portfolio constraints.";
    throw ValueError(ss.str());
  }
}

double GreedySolver::PseudoCost_() {
  std::vector<ExchangeNode::Ptr>::iterator n_it;
  std::map<Arc, std::vector<double> >::iterator c_it;
  std::map<Arc, double>::iterator p_it;
  std::vector<RequestGroup::Ptr>::iterator rg_it;
  std::vector<ExchangeNodeGroup::Ptr>::iterator sg_it;
  double min_cap, pref, coeff;

  double max_coeff = std::numeric_limits<double>::min();
  double min_unit_cap = std::numeric_limits<double>::max();

  for (sg_it = graph_->supply_groups().begin();
       sg_it != graph_->supply_groups().end();
       ++sg_it) {
    std::vector<ExchangeNode::Ptr>& nodes = (*sg_it)->nodes();
    for (n_it = nodes.begin(); n_it != nodes.end(); ++n_it) {
      // update min_unit_cap
      std::map<Arc, std::vector<double> >::iterator c_it;
      std::map<Arc, std::vector<double> >& caps = (*n_it)->unit_capacities;
      for (c_it = caps.begin(); c_it != caps.end(); ++c_it) {
        std::vector<double>& ucaps = c_it->second;
        if (!ucaps.empty()) {
          min_cap = *std::min_element(ucaps.begin(), ucaps.end());
          if (min_cap < min_unit_cap)
            min_unit_cap = min_cap;
        }
      }
    }
  }

  for (rg_it = graph_->request_groups().begin();
       rg_it != graph_->request_groups().end();
       ++rg_it) {
    std::vector<ExchangeNode::Ptr>& nodes = (*rg_it)->nodes();
    for (n_it = nodes.begin(); n_it != nodes.end(); ++n_it) {
      // update min_unit_cap
      std::map<Arc, std::vector<double> >::iterator c_it;
      std::map<Arc, std::vector<double> >& caps = (*n_it)->unit_capacities;
      for (c_it = caps.begin(); c_it != caps.end(); ++c_it) {
        std::vector<double>& ucaps = c_it->second;
        if (!ucaps.empty()) {
          min_cap = *std::min_element(ucaps.begin(), ucaps.end());
          if (min_cap < min_unit_cap)
            min_unit_cap = min_cap;
        }
      }
o
      // update max_pref_
      std::map<Arc, double>& prefs = (*n_it)->prefs;
      for (p_it = prefs.begin(); p_it != prefs.end(); ++p_it) {
        pref = p_it->second;
        const Arc& a = p_it->first;
        coeff = (exclusive_orders_ && a.exclusive()) ?
                a.excl_val() / pref : 1.0 / pref;
        if (coeff > max_coeff)
          max_coeff = coeff;
      }
    }
  }

  double cost_add_ = 1; // this matches the prog_solver faux arc costs
  return max_coeff / min_unit_cap + cost_add_;
}

}  // namespace cyclus
<commit_msg>errant o<commit_after>#include "greedy_solver.h"

#include <algorithm>
#include <cassert>
#include <functional>
#include <vector>

#include "cyc_limits.h"
#include "error.h"
#include "logger.h"

namespace cyclus {

double Capacity(const Arc& a, double u_curr_qty, double v_curr_qty) {
  bool min = true;
  double ucap = Capacity(a.unode(), a, !min, u_curr_qty);
  double vcap = Capacity(a.vnode(), a, min, v_curr_qty);

  CLOG(cyclus::LEV_DEBUG1) << "Capacity for unode of arc: " << ucap;
  CLOG(cyclus::LEV_DEBUG1) << "Capacity for vnode of arc: " << vcap;
  CLOG(cyclus::LEV_DEBUG1) << "Capacity for arc         : "
                           << std::min(ucap, vcap);

  return std::min(ucap, vcap);
}

double Capacity(ExchangeNode::Ptr n, const Arc& a, bool min_cap,
                double curr_qty) {
  if (n->group == NULL) {
    throw cyclus::StateError("An notion of node capacity requires a nodegroup.");
  }

  if (n->unit_capacities[a].size() == 0) {
    return n->qty - curr_qty;
  }

  std::vector<double>& unit_caps = n->unit_capacities[a];
  const std::vector<double>& group_caps = n->group->capacities();
  std::vector<double> caps;
  double grp_cap, u_cap, cap;

  for (int i = 0; i < unit_caps.size(); i++) {
    grp_cap = group_caps[i];
    u_cap = unit_caps[i];
    cap = grp_cap / u_cap;
    CLOG(cyclus::LEV_DEBUG1) << "Capacity for node: ";
    CLOG(cyclus::LEV_DEBUG1) << "   group capacity: " << grp_cap;
    CLOG(cyclus::LEV_DEBUG1) << "    unit capacity: " << u_cap;
    CLOG(cyclus::LEV_DEBUG1) << "         capacity: " << cap;

    // special case for unlimited capacities
    if (grp_cap == std::numeric_limits<double>::max()) {
      caps.push_back(std::numeric_limits<double>::max());
    } else {
      caps.push_back(cap);
    }
  }

  if (min_cap) {  // the smallest value is constraining (for bids)
    cap = *std::min_element(caps.begin(), caps.end());
  } else {  // the largest value must be met (for requests)
    cap = *std::max_element(caps.begin(), caps.end());
  }
  return std::min(cap, n->qty - curr_qty);
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
GreedySolver::GreedySolver(bool exclusive_orders, GreedyPreconditioner* c)
    : conditioner_(c),
      ExchangeSolver(exclusive_orders) {}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
GreedySolver::~GreedySolver() {
  if (conditioner_ != NULL)
    delete conditioner_;
}

void GreedySolver::Condition() {
  if (conditioner_ == NULL)
    conditioner_ = new GreedyPreconditioner(std::map<std::string, double>());

  conditioner_->Condition(graph_);
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
double GreedySolver::SolveGraph() {
  Condition();
  obj_ = 0;
  unmatched_ = 0;
  n_qty_.clear();

  std::for_each(graph_->request_groups().begin(),
                graph_->request_groups().end(),
                std::bind1st(
                    std::mem_fun(&GreedySolver::Init_),
                    this));

  std::for_each(graph_->supply_groups().begin(),
                graph_->supply_groups().end(),
                std::bind1st(
                    std::mem_fun(&GreedySolver::Init_),
                    this));

  std::for_each(graph_->request_groups().begin(),
                graph_->request_groups().end(),
                std::bind1st(
                    std::mem_fun(&GreedySolver::GreedilySatisfySet_),
                    this));

  obj_ += unmatched_ * PseudoCost_();
  return obj_;
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void GreedySolver::Init_(ExchangeNodeGroup::Ptr g) {
  for (int i = 0; i != g->nodes().size(); i++) {
    n_qty_[g->nodes()[i]] = 0;
  }
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void GreedySolver::GreedilySatisfySet_(RequestGroup::Ptr prs) {
  std::vector<ExchangeNode::Ptr>& nodes = prs->nodes();
  std::stable_sort(nodes.begin(), nodes.end(), AvgPrefComp);

  std::vector<ExchangeNode::Ptr>::iterator req_it = nodes.begin();
  double target = prs->qty();
  double match = 0;

  ExchangeNode::Ptr u, v;
  std::vector<Arc>::const_iterator arc_it;
  std::vector<Arc> sorted;
  double remain, tomatch, excl_val;

  CLOG(LEV_DEBUG1) << "Greedy Solving for " << target
                   << " amount of a resource.";

  while ((match <= target) && (req_it != nodes.end())) {
    // this if statement is needed because map.at() will throw if the key does
    // not exist, which is a corner case for when there is a request with no bid
    // arcs associated with it
    if (graph_->node_arc_map().count(*req_it) > 0) {
      const std::vector<Arc>& arcs = graph_->node_arc_map().at(*req_it);
      sorted = std::vector<Arc>(arcs);  // make a copy for now
      std::stable_sort(sorted.begin(), sorted.end(), ReqPrefComp);
      arc_it = sorted.begin();

      while ((match <= target) && (arc_it != sorted.end())) {
        remain = target - match;
        const Arc& a = *arc_it;
        u = a.unode();
        v = a.vnode();

        // capacity adjustment
        tomatch = std::min(remain, Capacity(a, n_qty_[u], n_qty_[v]));

        // exclusivity adjustment
        if (arc_it->exclusive()) {
          excl_val = a.excl_val();
          tomatch = (tomatch < excl_val) ? 0 : excl_val;
        }

        if (tomatch > eps()) {
          CLOG(LEV_DEBUG1) << "Greedy Solver is matching " << tomatch
                           << " amount of a resource.";
          UpdateCapacity_(u, a, tomatch);
          UpdateCapacity_(v, a, tomatch);
          n_qty_[u] += tomatch;
          n_qty_[v] += tomatch;
          graph_->AddMatch(a, tomatch);

          match += tomatch;
          UpdateObj_(tomatch, u->prefs[a]);
        }
        ++arc_it;
      }  // while( (match =< target) && (arc_it != arcs.end()) )
    }  // if(graph_->node_arc_map().count(*req_it) > 0)
    ++req_it;
  }  // while( (match =< target) && (req_it != nodes.end()) )

  unmatched_ += target - match;
}

void GreedySolver::UpdateObj_(double qty, double pref) {
  // updates minimizing object (i.e., 1/pref is a cost and the objective is cost
  // * flow)
  obj_ += qty / pref;
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void GreedySolver::UpdateCapacity_(ExchangeNode::Ptr n, const Arc& a,
                                   double qty) {
  using cyclus::IsNegative;
  using cyclus::ValueError;

  std::vector<double>& unit_caps = n->unit_capacities[a];
  std::vector<double>& caps = n->group->capacities();
  assert(unit_caps.size() == caps.size());
  for (int i = 0; i < caps.size(); i++) {
    double prev = caps[i];
    // special case for unlimited capacities
    CLOG(cyclus::LEV_DEBUG1) << "Updating capacity value from: "
                             << prev;
    caps[i] = (prev == std::numeric_limits<double>::max()) ?
              std::numeric_limits<double>::max() :
              prev - qty * unit_caps[i];
    CLOG(cyclus::LEV_DEBUG1) << "                          to: "
                             << caps[i];
  }

  if (IsNegative(n->qty - qty)) {
    std::stringstream ss;
    ss << "A bid for " << n->commod << " was set at " << n->qty
       << " but has been matched to a higher value " << qty
       << ". This could be due to a problem with your "
       << "bid portfolio constraints.";
    throw ValueError(ss.str());
  }
}

double GreedySolver::PseudoCost_() {
  std::vector<ExchangeNode::Ptr>::iterator n_it;
  std::map<Arc, std::vector<double> >::iterator c_it;
  std::map<Arc, double>::iterator p_it;
  std::vector<RequestGroup::Ptr>::iterator rg_it;
  std::vector<ExchangeNodeGroup::Ptr>::iterator sg_it;
  double min_cap, pref, coeff;

  double max_coeff = std::numeric_limits<double>::min();
  double min_unit_cap = std::numeric_limits<double>::max();

  for (sg_it = graph_->supply_groups().begin();
       sg_it != graph_->supply_groups().end();
       ++sg_it) {
    std::vector<ExchangeNode::Ptr>& nodes = (*sg_it)->nodes();
    for (n_it = nodes.begin(); n_it != nodes.end(); ++n_it) {
      // update min_unit_cap
      std::map<Arc, std::vector<double> >::iterator c_it;
      std::map<Arc, std::vector<double> >& caps = (*n_it)->unit_capacities;
      for (c_it = caps.begin(); c_it != caps.end(); ++c_it) {
        std::vector<double>& ucaps = c_it->second;
        if (!ucaps.empty()) {
          min_cap = *std::min_element(ucaps.begin(), ucaps.end());
          if (min_cap < min_unit_cap)
            min_unit_cap = min_cap;
        }
      }
    }
  }

  for (rg_it = graph_->request_groups().begin();
       rg_it != graph_->request_groups().end();
       ++rg_it) {
    std::vector<ExchangeNode::Ptr>& nodes = (*rg_it)->nodes();
    for (n_it = nodes.begin(); n_it != nodes.end(); ++n_it) {
      // update min_unit_cap
      std::map<Arc, std::vector<double> >::iterator c_it;
      std::map<Arc, std::vector<double> >& caps = (*n_it)->unit_capacities;
      for (c_it = caps.begin(); c_it != caps.end(); ++c_it) {
        std::vector<double>& ucaps = c_it->second;
        if (!ucaps.empty()) {
          min_cap = *std::min_element(ucaps.begin(), ucaps.end());
          if (min_cap < min_unit_cap)
            min_unit_cap = min_cap;
        }
      }

      // update max_pref_
      std::map<Arc, double>& prefs = (*n_it)->prefs;
      for (p_it = prefs.begin(); p_it != prefs.end(); ++p_it) {
        pref = p_it->second;
        const Arc& a = p_it->first;
        coeff = (exclusive_orders_ && a.exclusive()) ?
                a.excl_val() / pref : 1.0 / pref;
        if (coeff > max_coeff)
          max_coeff = coeff;
      }
    }
  }

  double cost_add_ = 1; // this matches the prog_solver faux arc costs
  return max_coeff / min_unit_cap + cost_add_;
}

}  // namespace cyclus
<|endoftext|>


<commit_before><commit_msg>gui: fix non-gui build missing symbols<commit_after><|endoftext|>


<commit_before>// Eflags register
#define FL_CF           0x00000001      // Carry Flag
#define FL_PF           0x00000004      // Parity Flag
#define FL_AF           0x00000010      // Auxiliary carry Flag
#define FL_ZF           0x00000040      // Zero Flag
#define FL_SF           0x00000080      // Sign Flag
#define FL_TF           0x00000100      // Trap Flag
#define FL_IF           0x00000200      // Interrupt Enable
#define FL_DF           0x00000400      // Direction Flag
#define FL_OF           0x00000800      // Overflow Flag
#define FL_IOPL_MASK    0x00003000      // I/O Privilege Level bitmask
#define FL_IOPL_0       0x00000000      //   IOPL == 0
#define FL_IOPL_1       0x00001000      //   IOPL == 1
#define FL_IOPL_2       0x00002000      //   IOPL == 2
#define FL_IOPL_3       0x00003000      //   IOPL == 3
#define FL_NT           0x00004000      // Nested Task
#define FL_RF           0x00010000      // Resume Flag
#define FL_VM           0x00020000      // Virtual 8086 mode
#define FL_AC           0x00040000      // Alignment Check
#define FL_VIF          0x00080000      // Virtual Interrupt Flag
#define FL_VIP          0x00100000      // Virtual Interrupt Pending
#define FL_ID           0x00200000      // ID flag

// Page fault error codes
#define FEC_PR          0x1     // Page fault caused by protection violation
#define FEC_WR          0x2     // Page fault caused by a write
#define FEC_U           0x4     // Page fault occured while in user mode

// Control Register flags
#define CR0_PE		0x00000001	// Protection Enable
#define CR0_MP		0x00000002	// Monitor coProcessor
#define CR0_EM		0x00000004	// Emulation
#define CR0_TS		0x00000008	// Task Switched
#define CR0_ET		0x00000010	// Extension Type
#define CR0_NE		0x00000020	// Numeric Errror
#define CR0_WP		0x00010000	// Write Protect
#define CR0_AM		0x00040000	// Alignment Mask
#define CR0_NW		0x20000000	// Not Writethrough
#define CR0_CD		0x40000000	// Cache Disable
#define CR0_PG		0x80000000	// Paging

#define CR4_PCE         0x100           // RDPMC at CPL > 0

// FS/GS base registers
#define MSR_FS_BASE     0xc0000100
#define MSR_GS_BASE     0xc0000101
#define MSR_GS_KERNBASE 0xc0000102

// SYSCALL and SYSRET registers
#define MSR_STAR        0xc0000081
#define MSR_LSTAR       0xc0000082
#define MSR_CSTAR       0xc0000083
#define MSR_SFMASK      0xc0000084

// AMD performance event-select registers
#define MSR_AMD_PERF_SEL0  0xC0010000
#define MSR_AMD_PERF_SEL1  0xC0010001
#define MSR_AMD_PERF_SEL2  0xC0010002
#define MSR_AMD_PERF_SEL3  0xC0010003
// AMD performance event-count registers
#define MSR_AMD_PERF_CNT0  0xC0010004
#define MSR_AMD_PERF_CNT1  0xC0010005
#define MSR_AMD_PERF_CNT2  0xC0010006
#define MSR_AMD_PERF_CNT3  0xC0010007

// Intel performance event-select registers
#define MSR_INTEL_PERF_SEL0 0x00000186
#define MSR_INTEL_PERF_SEL1 0x00000187
// Intel performance event-count registers
#define MSR_INTEL_PERF_CNT0 0x000000c1
#define MSR_INTEL_PERF_CNT1 0x000000c2

// Common event-select bits
#define PERF_SEL_USR        (1ULL << 16)
#define PERF_SEL_OS         (1ULL << 17)
#define PERF_SEL_EDGE       (1ULL << 18)
#define PERF_SEL_INT        (1ULL << 20)
#define PERF_SEL_ENABLE     (1ULL << 22)
#define PERF_SEL_INV        (1ULL << 23)

// CPUID function 0x00000001
#define CPUID_FEATURES      0x00000001
#define FEATURE_ECX_MWAIT   (1 << 3)

// CPUID function 0x00000005
#define CPUID_MWAIT         0x00000005

<commit_msg>Bits for reading APICID from a cpuid register<commit_after>// Eflags register
#define FL_CF           0x00000001      // Carry Flag
#define FL_PF           0x00000004      // Parity Flag
#define FL_AF           0x00000010      // Auxiliary carry Flag
#define FL_ZF           0x00000040      // Zero Flag
#define FL_SF           0x00000080      // Sign Flag
#define FL_TF           0x00000100      // Trap Flag
#define FL_IF           0x00000200      // Interrupt Enable
#define FL_DF           0x00000400      // Direction Flag
#define FL_OF           0x00000800      // Overflow Flag
#define FL_IOPL_MASK    0x00003000      // I/O Privilege Level bitmask
#define FL_IOPL_0       0x00000000      //   IOPL == 0
#define FL_IOPL_1       0x00001000      //   IOPL == 1
#define FL_IOPL_2       0x00002000      //   IOPL == 2
#define FL_IOPL_3       0x00003000      //   IOPL == 3
#define FL_NT           0x00004000      // Nested Task
#define FL_RF           0x00010000      // Resume Flag
#define FL_VM           0x00020000      // Virtual 8086 mode
#define FL_AC           0x00040000      // Alignment Check
#define FL_VIF          0x00080000      // Virtual Interrupt Flag
#define FL_VIP          0x00100000      // Virtual Interrupt Pending
#define FL_ID           0x00200000      // ID flag

// Page fault error codes
#define FEC_PR          0x1     // Page fault caused by protection violation
#define FEC_WR          0x2     // Page fault caused by a write
#define FEC_U           0x4     // Page fault occured while in user mode

// Control Register flags
#define CR0_PE		0x00000001	// Protection Enable
#define CR0_MP		0x00000002	// Monitor coProcessor
#define CR0_EM		0x00000004	// Emulation
#define CR0_TS		0x00000008	// Task Switched
#define CR0_ET		0x00000010	// Extension Type
#define CR0_NE		0x00000020	// Numeric Errror
#define CR0_WP		0x00010000	// Write Protect
#define CR0_AM		0x00040000	// Alignment Mask
#define CR0_NW		0x20000000	// Not Writethrough
#define CR0_CD		0x40000000	// Cache Disable
#define CR0_PG		0x80000000	// Paging

#define CR4_PCE         0x100           // RDPMC at CPL > 0

// FS/GS base registers
#define MSR_FS_BASE     0xc0000100
#define MSR_GS_BASE     0xc0000101
#define MSR_GS_KERNBASE 0xc0000102

// SYSCALL and SYSRET registers
#define MSR_STAR        0xc0000081
#define MSR_LSTAR       0xc0000082
#define MSR_CSTAR       0xc0000083
#define MSR_SFMASK      0xc0000084

// AMD performance event-select registers
#define MSR_AMD_PERF_SEL0  0xC0010000
#define MSR_AMD_PERF_SEL1  0xC0010001
#define MSR_AMD_PERF_SEL2  0xC0010002
#define MSR_AMD_PERF_SEL3  0xC0010003
// AMD performance event-count registers
#define MSR_AMD_PERF_CNT0  0xC0010004
#define MSR_AMD_PERF_CNT1  0xC0010005
#define MSR_AMD_PERF_CNT2  0xC0010006
#define MSR_AMD_PERF_CNT3  0xC0010007

// Intel performance event-select registers
#define MSR_INTEL_PERF_SEL0 0x00000186
#define MSR_INTEL_PERF_SEL1 0x00000187
// Intel performance event-count registers
#define MSR_INTEL_PERF_CNT0 0x000000c1
#define MSR_INTEL_PERF_CNT1 0x000000c2

// Common event-select bits
#define PERF_SEL_USR        (1ULL << 16)
#define PERF_SEL_OS         (1ULL << 17)
#define PERF_SEL_EDGE       (1ULL << 18)
#define PERF_SEL_INT        (1ULL << 20)
#define PERF_SEL_ENABLE     (1ULL << 22)
#define PERF_SEL_INV        (1ULL << 23)

// CPUID function 0x00000001
#define CPUID_FEATURES      0x00000001
#define FEATURE_ECX_MWAIT   (1 << 3)
#define FEATURE_EBX_APIC(x) (((x) >> 24) & 0xff)

// CPUID function 0x00000005
#define CPUID_MWAIT         0x00000005
<|endoftext|>


<commit_before>#include "stdafx.h"
#include "Core/SymbolTable.h"
#include "Util/FileClasses.h"
#include "Util/Util.h"
#include "Common.h"

const wchar_t validSymbolCharacters[] = L"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_.";

bool operator<(SymbolKey const& lhs, SymbolKey const& rhs)
{
	if (lhs.file != rhs.file)
		return lhs.file < rhs.file;
	if (lhs.section != rhs.section)
		return lhs.section < rhs.section;
	return lhs.name.compare(rhs.name) < 0;
}

SymbolTable::SymbolTable()
{
	uniqueCount = 0;
}

SymbolTable::~SymbolTable()
{
	clear();
}

void SymbolTable::clear()
{
	for (size_t i = 0; i < labels.size(); i++)
	{
		delete labels[i];
	}

	symbols.clear();
	labels.clear();
	equations.clear();
	uniqueCount = 0;
}

void SymbolTable::setFileSectionValues(const std::wstring& symbol, unsigned int& file, unsigned int& section)
{
	if (symbol[0] == '@')
	{
		if (symbol[1] != '@')
		{
			// static label, @. the section doesn't matter
			section = -1;
		}
	} else {
		// global label. neither file nor section matters
		file = section = -1;
	}
}

Label* SymbolTable::getLabel(const std::wstring& symbol, unsigned int file, unsigned int section)
{
	if (isValidSymbolName(symbol) == false)
		return NULL;

	int actualSection = section;
	setFileSectionValues(symbol,file,section);
	SymbolKey key = { symbol, file, section };

	// find label, create new one if it doesn't exist
	auto it = symbols.find(key);
	if (it == symbols.end())
	{
		SymbolInfo value = { LabelSymbol, labels.size() };
		symbols[key] = value;

		Label* result = new Label(symbol);
		if (section == actualSection)
			result->setSection(section);			// local, set section of parent
		else
			result->setSection(actualSection+1);	// global, set section of children
		labels.push_back(result);
		return result;
	}

	// make sure not to match symbols that aren't labels
	if (it->second.type != LabelSymbol)
		return NULL;

	return labels[it->second.index];
}

bool SymbolTable::symbolExists(const std::wstring& symbol, unsigned int file, unsigned int section)
{
	if (isValidSymbolName(symbol) == false)
		return false;

	setFileSectionValues(symbol,file,section);

	SymbolKey key = { symbol, file, section };
	auto it = symbols.find(key);
	return it != symbols.end();
}

bool SymbolTable::isValidSymbolName(const std::wstring& symbol)
{
	size_t size = symbol.size();
	size_t start = 0;

	// don't match empty names
	if (size == 0 || symbol.compare(L"@") == 0 || symbol.compare(L"@@") == 0)
		return false;

	if (symbol[0] == '@')
	{
		start++;
		if (size > 1 && symbol[1] == '@')
			start++;
	}

	if (symbol[start] >= '0' && symbol[start] <= '9')
		return false;

	for (size_t i = start; i < size; i++)
	{
		if (wcschr(validSymbolCharacters,symbol[i]) == NULL)
			return false;
	}

	return true;
}

bool SymbolTable::isValidSymbolCharacter(wchar_t character, bool first)
{
	character = towlower(character);
	if (character >= 'a' && character <= 'z') return true;
	if (!first && character >= '0' && character <= '9') return true;
	if (character == '_' || character == '.') return true;
	if (character == '@') return true;
	return false;
}

bool SymbolTable::addEquation(const std::wstring& name, unsigned int file, unsigned int section, std::wstring& replacement)
{
	if (isValidSymbolName(name) == false)
		return false;

	if (symbolExists(name,file,section))
		return false;

	setFileSectionValues(name,file,section);

	SymbolKey key = { name, file, section };
	SymbolInfo value = { EquationSymbol, equations.size() };
	symbols[key] = value;

	Equation equation = { name, replacement, file, section };
	equations.push_back(equation);
	return true;
}

std::wstring SymbolTable::insertEquations(const std::wstring& line, unsigned int file, unsigned int section)
{
	std::wstring result;

	size_t pos = 0;
	while (pos < line.size())
	{
		if (line[pos] != '@' && !isValidSymbolCharacter(line[pos]))
		{
			result += line[pos++];
			continue;
		}

		size_t start = pos++;
		while (line[pos] == '@' && pos < line.size())
			pos++;
		while (isValidSymbolCharacter(line[pos]) && pos < line.size())
			pos++;

		std::wstring word = line.substr(start,pos-start);
		bool found = false;
		for (size_t i = 0; i < equations.size(); i++)
		{
			const Equation& eq = equations.at(i);
			if ((eq.file == -1 || eq.file == file) &&
				(eq.section == -1 || eq.section == section))
			{
				if (eq.key.size() != word.size())
					continue;

				if (eq.key != word)
					continue;

				result += eq.value;
				found = true;
				break;
			}
		}

		if (!found)
			result += word;
	}

	return result;
}

// TODO: better
std::wstring SymbolTable::getUniqueLabelName()
{
	return formatString(L"__armips_label_%08X__",uniqueCount++);
}

void SymbolTable::addLabels(const std::vector<LabelDefinition>& labels)
{
	int lastSection = 0;
	for (const LabelDefinition& def: labels)
	{
		if (!isValidSymbolName(def.name))
			continue;

		Label* label = getLabel(def.name,(unsigned int)Global.FileInfo.FileNum,Global.Section);
		if (label == NULL)
			continue;

		if (isLocalSymbol(def.name) == false)
			Global.Section++;

		label->setDefined(true);
		label->setValue(def.value);
	}
}

int SymbolTable::findSection(u64 address)
{
	int smallestBefore = -1;
	int smallestDiff = 0x7FFFFFFF;

	for (auto& lab: labels)
	{
		int diff = (int)(address-lab->getValue());
		if (diff >= 0 && diff < smallestDiff)
		{
			smallestDiff = diff;
			smallestBefore = lab->getSection();
		}
	}

	return smallestBefore;
}<commit_msg>Optimize isValidSymbolCharacter().<commit_after>#include "stdafx.h"
#include "Core/SymbolTable.h"
#include "Util/FileClasses.h"
#include "Util/Util.h"
#include "Common.h"

const wchar_t validSymbolCharacters[] = L"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_.";

bool operator<(SymbolKey const& lhs, SymbolKey const& rhs)
{
	if (lhs.file != rhs.file)
		return lhs.file < rhs.file;
	if (lhs.section != rhs.section)
		return lhs.section < rhs.section;
	return lhs.name.compare(rhs.name) < 0;
}

SymbolTable::SymbolTable()
{
	uniqueCount = 0;
}

SymbolTable::~SymbolTable()
{
	clear();
}

void SymbolTable::clear()
{
	for (size_t i = 0; i < labels.size(); i++)
	{
		delete labels[i];
	}

	symbols.clear();
	labels.clear();
	equations.clear();
	uniqueCount = 0;
}

void SymbolTable::setFileSectionValues(const std::wstring& symbol, unsigned int& file, unsigned int& section)
{
	if (symbol[0] == '@')
	{
		if (symbol[1] != '@')
		{
			// static label, @. the section doesn't matter
			section = -1;
		}
	} else {
		// global label. neither file nor section matters
		file = section = -1;
	}
}

Label* SymbolTable::getLabel(const std::wstring& symbol, unsigned int file, unsigned int section)
{
	if (isValidSymbolName(symbol) == false)
		return NULL;

	int actualSection = section;
	setFileSectionValues(symbol,file,section);
	SymbolKey key = { symbol, file, section };

	// find label, create new one if it doesn't exist
	auto it = symbols.find(key);
	if (it == symbols.end())
	{
		SymbolInfo value = { LabelSymbol, labels.size() };
		symbols[key] = value;

		Label* result = new Label(symbol);
		if (section == actualSection)
			result->setSection(section);			// local, set section of parent
		else
			result->setSection(actualSection+1);	// global, set section of children
		labels.push_back(result);
		return result;
	}

	// make sure not to match symbols that aren't labels
	if (it->second.type != LabelSymbol)
		return NULL;

	return labels[it->second.index];
}

bool SymbolTable::symbolExists(const std::wstring& symbol, unsigned int file, unsigned int section)
{
	if (isValidSymbolName(symbol) == false)
		return false;

	setFileSectionValues(symbol,file,section);

	SymbolKey key = { symbol, file, section };
	auto it = symbols.find(key);
	return it != symbols.end();
}

bool SymbolTable::isValidSymbolName(const std::wstring& symbol)
{
	size_t size = symbol.size();
	size_t start = 0;

	// don't match empty names
	if (size == 0 || symbol.compare(L"@") == 0 || symbol.compare(L"@@") == 0)
		return false;

	if (symbol[0] == '@')
	{
		start++;
		if (size > 1 && symbol[1] == '@')
			start++;
	}

	if (symbol[start] >= '0' && symbol[start] <= '9')
		return false;

	for (size_t i = start; i < size; i++)
	{
		if (wcschr(validSymbolCharacters,symbol[i]) == NULL)
			return false;
	}

	return true;
}

bool SymbolTable::isValidSymbolCharacter(wchar_t character, bool first)
{
	if ((character >= 'a' && character <= 'z') || character >= 'A' && character <= 'Z') return true;
	if (!first && character >= '0' && character <= '9') return true;
	if (character == '_' || character == '.') return true;
	if (character == '@') return true;
	return false;
}

bool SymbolTable::addEquation(const std::wstring& name, unsigned int file, unsigned int section, std::wstring& replacement)
{
	if (isValidSymbolName(name) == false)
		return false;

	if (symbolExists(name,file,section))
		return false;

	setFileSectionValues(name,file,section);

	SymbolKey key = { name, file, section };
	SymbolInfo value = { EquationSymbol, equations.size() };
	symbols[key] = value;

	Equation equation = { name, replacement, file, section };
	equations.push_back(equation);
	return true;
}

std::wstring SymbolTable::insertEquations(const std::wstring& line, unsigned int file, unsigned int section)
{
	std::wstring result;

	size_t pos = 0;
	while (pos < line.size())
	{
		if (line[pos] != '@' && !isValidSymbolCharacter(line[pos]))
		{
			result += line[pos++];
			continue;
		}

		size_t start = pos++;
		while (line[pos] == '@' && pos < line.size())
			pos++;
		while (isValidSymbolCharacter(line[pos]) && pos < line.size())
			pos++;

		std::wstring word = line.substr(start,pos-start);
		bool found = false;
		for (size_t i = 0; i < equations.size(); i++)
		{
			const Equation& eq = equations.at(i);
			if ((eq.file == -1 || eq.file == file) &&
				(eq.section == -1 || eq.section == section))
			{
				if (eq.key.size() != word.size())
					continue;

				if (eq.key != word)
					continue;

				result += eq.value;
				found = true;
				break;
			}
		}

		if (!found)
			result += word;
	}

	return result;
}

// TODO: better
std::wstring SymbolTable::getUniqueLabelName()
{
	return formatString(L"__armips_label_%08X__",uniqueCount++);
}

void SymbolTable::addLabels(const std::vector<LabelDefinition>& labels)
{
	int lastSection = 0;
	for (const LabelDefinition& def: labels)
	{
		if (!isValidSymbolName(def.name))
			continue;

		Label* label = getLabel(def.name,(unsigned int)Global.FileInfo.FileNum,Global.Section);
		if (label == NULL)
			continue;

		if (isLocalSymbol(def.name) == false)
			Global.Section++;

		label->setDefined(true);
		label->setValue(def.value);
	}
}

int SymbolTable::findSection(u64 address)
{
	int smallestBefore = -1;
	int smallestDiff = 0x7FFFFFFF;

	for (auto& lab: labels)
	{
		int diff = (int)(address-lab->getValue());
		if (diff >= 0 && diff < smallestDiff)
		{
			smallestDiff = diff;
			smallestBefore = lab->getSection();
		}
	}

	return smallestBefore;
}<|endoftext|>


<commit_before>/*

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

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

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

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

*/

#include "libtorrent/session.hpp"
#include "libtorrent/session_settings.hpp"
#include "libtorrent/hasher.hpp"
#include "libtorrent/alert_types.hpp"
#include "libtorrent/bencode.hpp"
#include "libtorrent/thread.hpp"
#include "libtorrent/time.hpp"
#include "libtorrent/file.hpp"
#include <boost/tuple/tuple.hpp>
#include <boost/bind.hpp>

#include "test.hpp"
#include "setup_transfer.hpp"
#include <fstream>
#include <iostream>

using namespace libtorrent;
using boost::tuples::ignore;

void test_transfer()
{
	// in case the previous run was terminated
	error_code ec;
	remove_all("./tmp1_utp", ec);
	remove_all("./tmp2_utp", ec);

	session ses1(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48885, 49930), "0.0.0.0", 0);
	session ses2(fingerprint("LT", 0, 1, 0, 0), std::make_pair(49885, 50930), "0.0.0.0", 0);

	session_settings sett;

	sett.enable_outgoing_tcp = false;
	sett.min_reconnect_time = 1;
	sett.announce_to_all_trackers = true;
	sett.announce_to_all_tiers = true;
	// make sure we announce to both http and udp trackers
	sett.prefer_udp_trackers = false;

	// for performance testing
//	sett.disable_hash_checks = true;
//	sett.utp_delayed_ack = 0;

	// disable this to use regular size packets over loopback
//	sett.utp_dynamic_sock_buf = false;

	ses1.set_settings(sett);
	ses2.set_settings(sett);

#ifndef TORRENT_DISABLE_ENCRYPTION
	pe_settings pes;
	pes.out_enc_policy = pe_settings::disabled;
	pes.in_enc_policy = pe_settings::disabled;
	ses1.set_pe_settings(pes);
	ses2.set_pe_settings(pes);
#endif

	torrent_handle tor1;
	torrent_handle tor2;

	create_directory("./tmp1_utp", ec);
	std::ofstream file("./tmp1_utp/temporary");
	boost::intrusive_ptr<torrent_info> t = ::create_torrent(&file, 512 * 1024, 20, false);
	file.close();

	// for performance testing
	add_torrent_params atp;
//	atp.storage = &disabled_storage_constructor;

	// test using piece sizes smaller than 16kB
	boost::tie(tor1, tor2, ignore) = setup_transfer(&ses1, &ses2, 0
		, true, false, true, "_utp", 0, &t, false, &atp);

	for (int i = 0; i < 300; ++i)
	{
		print_alerts(ses1, "ses1", true, true, true);
		print_alerts(ses2, "ses2", true, true, true);

		torrent_status st1 = tor1.status();
		torrent_status st2 = tor2.status();

		std::cerr
			<< "\033[32m" << int(st1.download_payload_rate / 1000.f) << "kB/s "
			<< "\033[33m" << int(st1.upload_payload_rate / 1000.f) << "kB/s "
			<< "\033[0m" << int(st1.progress * 100) << "% "
			<< st1.num_peers
			<< ": "
			<< "\033[32m" << int(st2.download_payload_rate / 1000.f) << "kB/s "
			<< "\033[31m" << int(st2.upload_payload_rate / 1000.f) << "kB/s "
			<< "\033[0m" << int(st2.progress * 100) << "% "
			<< st2.num_peers
			<< " cc: " << st2.connect_candidates
			<< std::endl;

		if (st2.is_finished) break;

		test_sleep(500);

		TEST_CHECK(st1.state == torrent_status::seeding
			|| st1.state == torrent_status::checking_files);
		TEST_CHECK(st2.state == torrent_status::downloading);
	}

	TEST_CHECK(tor1.status().is_finished);
	TEST_CHECK(tor2.status().is_finished);
}

int test_main()
{
	using namespace libtorrent;

	test_transfer();

	error_code ec;
	remove_all("./tmp1_utp", ec);
	remove_all("./tmp2_utp", ec);

	return 0;
}

<commit_msg>make test_utp more likely to pass<commit_after>/*

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

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

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

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

*/

#include "libtorrent/session.hpp"
#include "libtorrent/session_settings.hpp"
#include "libtorrent/hasher.hpp"
#include "libtorrent/alert_types.hpp"
#include "libtorrent/bencode.hpp"
#include "libtorrent/thread.hpp"
#include "libtorrent/time.hpp"
#include "libtorrent/file.hpp"
#include <boost/tuple/tuple.hpp>
#include <boost/bind.hpp>

#include "test.hpp"
#include "setup_transfer.hpp"
#include <fstream>
#include <iostream>

using namespace libtorrent;
using boost::tuples::ignore;

void test_transfer()
{
	// in case the previous run was terminated
	error_code ec;
	remove_all("./tmp1_utp", ec);
	remove_all("./tmp2_utp", ec);

	session ses1(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48885, 49930), "0.0.0.0", 0);
	session ses2(fingerprint("LT", 0, 1, 0, 0), std::make_pair(49885, 50930), "0.0.0.0", 0);

	session_settings sett;

	sett.enable_outgoing_tcp = false;
	sett.min_reconnect_time = 1;
	sett.announce_to_all_trackers = true;
	sett.announce_to_all_tiers = true;
	// make sure we announce to both http and udp trackers
	sett.prefer_udp_trackers = false;

	// for performance testing
//	sett.disable_hash_checks = true;
//	sett.utp_delayed_ack = 0;

	// disable this to use regular size packets over loopback
//	sett.utp_dynamic_sock_buf = false;

	ses1.set_settings(sett);
	ses2.set_settings(sett);

#ifndef TORRENT_DISABLE_ENCRYPTION
	pe_settings pes;
	pes.out_enc_policy = pe_settings::disabled;
	pes.in_enc_policy = pe_settings::disabled;
	ses1.set_pe_settings(pes);
	ses2.set_pe_settings(pes);
#endif

	torrent_handle tor1;
	torrent_handle tor2;

	create_directory("./tmp1_utp", ec);
	std::ofstream file("./tmp1_utp/temporary");
	boost::intrusive_ptr<torrent_info> t = ::create_torrent(&file, 512 * 1024, 20, false);
	file.close();

	// for performance testing
	add_torrent_params atp;
//	atp.storage = &disabled_storage_constructor;

	// test using piece sizes smaller than 16kB
	boost::tie(tor1, tor2, ignore) = setup_transfer(&ses1, &ses2, 0
		, true, false, true, "_utp", 0, &t, false, &atp);

	for (int i = 0; i < 300; ++i)
	{
		print_alerts(ses1, "ses1", true, true, true);
		print_alerts(ses2, "ses2", true, true, true);

		test_sleep(500);

		torrent_status st1 = tor1.status();
		torrent_status st2 = tor2.status();

		std::cerr
			<< "\033[32m" << int(st1.download_payload_rate / 1000.f) << "kB/s "
			<< "\033[33m" << int(st1.upload_payload_rate / 1000.f) << "kB/s "
			<< "\033[0m" << int(st1.progress * 100) << "% "
			<< st1.num_peers
			<< ": "
			<< "\033[32m" << int(st2.download_payload_rate / 1000.f) << "kB/s "
			<< "\033[31m" << int(st2.upload_payload_rate / 1000.f) << "kB/s "
			<< "\033[0m" << int(st2.progress * 100) << "% "
			<< st2.num_peers
			<< " cc: " << st2.connect_candidates
			<< std::endl;

		if (st2.is_finished) break;

		TEST_CHECK(st1.state == torrent_status::seeding
			|| st1.state == torrent_status::checking_files);
		TEST_CHECK(st2.state == torrent_status::downloading);
	}

	TEST_CHECK(tor1.status().is_finished);
	TEST_CHECK(tor2.status().is_finished);
}

int test_main()
{
	using namespace libtorrent;

	test_transfer();

	error_code ec;
	remove_all("./tmp1_utp", ec);
	remove_all("./tmp2_utp", ec);

	return 0;
}

<|endoftext|>


<commit_before>#include <set>
#include <string>
#include <fstream>
#include <streambuf>

#include "errors.hpp"
#include <boost/bind.hpp>

#include "arch/runtime/thread_pool.hpp"   /* for `run_in_blocker_pool()` */
#include "http/file_app.hpp"
#include "logger.hpp"
#include "stl_utils.hpp"

file_http_app_t::file_http_app_t(std::set<std::string> _whitelist, std::string _asset_dir)
    : whitelist(_whitelist), asset_dir(_asset_dir)
{ }

http_res_t file_http_app_t::handle(const http_req_t &req) {
    if (req.method != GET) {
        /* Method not allowed. */
        return http_res_t(405);
    }
    std::string resource(req.resource.as_string());
    if (resource != "/" && resource != "" && !std_contains(whitelist, resource)) {
        logINF("Someone asked for the nonwhitelisted file %s, if this should be accessible add it to the whitelist.", resource.c_str());
        return http_res_t(403);
    }

    http_res_t res;
    std::string filename;

    if (resource == "/" || resource == "") {
        filename = "/index.html";
    } else {
        filename = resource;
    }

    thread_pool_t::run_in_blocker_pool(boost::bind(&file_http_app_t::handle_blocking, this, filename, &res));

    if (res.code == 404) {
        logINF("File %s was requested and is on the whitelist but we didn't find it in the directory.", (asset_dir + filename).c_str());
    }
    if (res.code >= 400) {
        return http_res_t(res.code);
    }

    return res;
}

void file_http_app_t::handle_blocking(std::string filename, http_res_t *res_out) {
    // FIXME: make sure that we won't walk out of our sandbox! Check symbolic links, etc.
    std::ifstream f((asset_dir + filename).c_str());

    if (f.fail()) {
        res_out->code = 404;
        return;
    }

    f.seekg(0, std::ios::end);

    if (f.fail()) {
        goto INTERNAL_ERROR;
    }

    res_out->body.reserve(f.tellg());

    if (f.fail()) {
        goto INTERNAL_ERROR;
    }

    f.seekg(0, std::ios::beg);

    if (f.fail()) {
        goto INTERNAL_ERROR;
    }

    res_out->body.assign((std::istreambuf_iterator<char>(f)),
                          std::istreambuf_iterator<char>());

    res_out->code = 200;

    return;

INTERNAL_ERROR:
    res_out->code = 500;
}
<commit_msg>remove useless branch<commit_after>#include <set>
#include <string>
#include <fstream>
#include <streambuf>

#include "errors.hpp"
#include <boost/bind.hpp>

#include "arch/runtime/thread_pool.hpp"   /* for `run_in_blocker_pool()` */
#include "http/file_app.hpp"
#include "logger.hpp"
#include "stl_utils.hpp"

file_http_app_t::file_http_app_t(std::set<std::string> _whitelist, std::string _asset_dir)
    : whitelist(_whitelist), asset_dir(_asset_dir)
{ }

http_res_t file_http_app_t::handle(const http_req_t &req) {
    if (req.method != GET) {
        /* Method not allowed. */
        return http_res_t(405);
    }
    std::string resource(req.resource.as_string());
    if (resource != "/" && resource != "" && !std_contains(whitelist, resource)) {
        logINF("Someone asked for the nonwhitelisted file %s, if this should be accessible add it to the whitelist.", resource.c_str());
        return http_res_t(403);
    }

    http_res_t res;
    std::string filename;

    if (resource == "/" || resource == "") {
        filename = "/index.html";
    } else {
        filename = resource;
    }

    thread_pool_t::run_in_blocker_pool(boost::bind(&file_http_app_t::handle_blocking, this, filename, &res));

    if (res.code == 404) {
        logINF("File %s was requested and is on the whitelist but we didn't find it in the directory.", (asset_dir + filename).c_str());
    }

    return res;
}

void file_http_app_t::handle_blocking(std::string filename, http_res_t *res_out) {
    // FIXME: make sure that we won't walk out of our sandbox! Check symbolic links, etc.
    std::ifstream f((asset_dir + filename).c_str());

    if (f.fail()) {
        res_out->code = 404;
        return;
    }

    f.seekg(0, std::ios::end);

    if (f.fail()) {
        goto INTERNAL_ERROR;
    }

    res_out->body.reserve(f.tellg());

    if (f.fail()) {
        goto INTERNAL_ERROR;
    }

    f.seekg(0, std::ios::beg);

    if (f.fail()) {
        goto INTERNAL_ERROR;
    }

    res_out->body.assign((std::istreambuf_iterator<char>(f)),
                          std::istreambuf_iterator<char>());

    res_out->code = 200;

    return;

INTERNAL_ERROR:
    res_out->code = 500;
}
<|endoftext|>


<commit_before>#include "gb-include.h"

#include "HashTable.h"

HashTable::HashTable () {
	m_keys = NULL;
	m_vals = NULL;
	m_numSlots     = 0;
	m_numSlotsUsed = 0;
	m_doFree       = true;
	m_label = NULL;
}

// returns false and sets errno on error
bool HashTable::set ( long initialNumTerms , char *buf , long bufSize ,
		      char *label ) {
	reset();
	m_label = label;
	if ( ! m_label ) m_label = "hashtablekv";
	return setTableSize ( initialNumTerms , buf , bufSize );
}

HashTable::~HashTable ( ) { reset ( ); }

// . call clean() to do a more careful reset
// . clean will rehash
void HashTable::reset ( ) {
	if ( m_doFree ) {
		if (m_keys) mfree(m_keys,m_numSlots*sizeof(long),m_label);
		if (m_vals) mfree(m_vals,m_numSlots*sizeof(long),m_label);
	}
	m_keys = NULL;
	m_vals = NULL;
	m_numSlots     = 0;
	m_numSlotsUsed = 0;
	// do not do this because then ::load() fails b/c you can't
	// pass a label into that yet
	//m_label = NULL;
}

void HashTable::clear ( ) {
	// vacate all slots
	if ( m_keys ) memset ( m_keys , 0 , sizeof(long) * m_numSlots );
	m_numSlotsUsed = 0;
}

// . returns the slot number for "key"
// . returns -1 if key not in hash table
long HashTable::getOccupiedSlotNum ( long key ) {
	if ( m_numSlots <= 0 ) return -1;
        //long n = ((unsigned long)key) % ((unsigned long)m_numSlots);
        long n = ((unsigned long)key) & m_mask;
        long count = 0;
        while ( count++ < m_numSlots ) {
                if ( m_keys [ n ] == 0   ) return -1;
		if ( m_keys [ n ] == key ) return  n;
		if ( ++n == m_numSlots ) n = 0;
        }
        log("hashtable: Could not get key. Table is full.");
        return -1;
}

// return 0 if key not in hash table
long HashTable::getValue ( long key ) {
	// returns -1 if key not in hash table
	long n = getOccupiedSlotNum ( key );
	if ( n < 0 ) return 0;
	return m_vals[n];
}

// . returns false and sets errno on error, returns true otherwise
// . adds scores if termId already exists in table
bool HashTable::addKey ( long key , long value , long *slot ) {
	// keys of 0 mean empty! they are reserved... fix that!
	if ( key == 0 ) { char *xx=NULL; *xx=0; }
	// check to see if we should grow the table
	if ( 100 * m_numSlotsUsed >= m_numSlots * 90 ) {
		long growTo = (m_numSlots * 120 ) / 100  + 20;
		if ( ! setTableSize ( growTo , NULL , 0 ) ) return false;
	}
        //long n = ((unsigned long)key) % ((unsigned long)m_numSlots);
        long n = ((unsigned long)key) & m_mask;
        long count = 0;
        while ( count++ < m_numSlots ) {
                if ( m_keys [ n ] == 0   ) break;
		if ( m_keys [ n ] == key ) break;
		if ( ++n == m_numSlots ) n = 0;
        }
	// bail if not found
	if ( count >= m_numSlots ) {
		g_errno = ENOMEM;
		return log("hashtable: Could not add key. Table is full.");
	}
	if ( m_keys [ n ] == 0 ) {
		// inc count if we're the first
		m_numSlotsUsed++;
		// and store the ky
		m_keys [ n ] = key;
	}
	// insert the value for this key
	m_vals [ n ] = value;
	if ( slot ) *slot = n;
	return true;
}

// patch the hole so chaining still works
bool HashTable::removeKey ( long key ) {
	// returns -1 if key not in hash table
	long n = getOccupiedSlotNum(key);
	if ( n < 0 ) return true;
	m_keys[n] = 0;
	m_numSlotsUsed--;
	if ( ++n >= m_numSlots ) n = 0;
	// keep looping until we hit an empty slot
	long val;
	while ( m_keys[n] ) {
		key = m_keys[n];
		val = m_vals[n];
		m_keys[n] = 0;
		m_numSlotsUsed--;
		addKey ( key , val );
		if ( ++n >= m_numSlots ) n = 0;
	}
	return true;
}

// patch the hole so chaining still works
void HashTable::removeSlot ( long n ) {
	// returns -1 if key not in hash table
	//long n = getOccupiedSlotNum(key);
	//if ( n < 0 ) return true;
	long key = m_keys[n];
	// sanity check, must not be empty
	if ( key == 0 ) { char *xx = NULL; *xx = 0; }
	// delete it
	m_keys[n] = 0;
	m_numSlotsUsed--;
	if ( ++n >= m_numSlots ) n = 0;
	// keep looping until we hit an empty slot
	long val;
	while ( m_keys[n] ) {
		key = m_keys[n];
		val = m_vals[n];
		m_keys[n] = 0;
		m_numSlotsUsed--;
		addKey ( key , val );
		if ( ++n >= m_numSlots ) n = 0;
	}
}

// . set table size to "n" slots
// . rehashes the termId/score pairs into new table
// . returns false and sets errno on error
bool HashTable::setTableSize ( long oldn , char *buf , long bufSize ) {
	// don't change size if we do not need to
	if ( oldn == m_numSlots ) return true;
	// make it a power of 2
	long n = getHighestLitBitValue ( (unsigned long)oldn * 2 - 1 );
	// do not go negative on me
	if ( oldn == 0 ) n = 0;
	// sanity check
	if ( n < oldn ) { char *xx = NULL; *xx = 0; }
	// do we have a buf?
	long need = 2 * n * sizeof(long);
	// sanity check, buf should also meet what we need
	if ( buf && bufSize < need ) { char *xx = NULL; *xx = 0; }
	// set the buf
	long *newKeys ;
	long *newVals ;
	// if we should not free note that
	bool savedDoFree = m_doFree ;
	// use our buf if we can
	if ( buf ) {
		m_doFree = false;
		bzero ( buf , need );
		newKeys = (long *)buf;
		buf += n * sizeof(long);
		newVals = (long *)buf;
		buf += n * sizeof(long);
	}
	else {
		m_doFree = true;
		newKeys = (long *)mcalloc ( n * sizeof(long) , m_label);
		if ( ! newKeys ) return false;
		newVals = (long *)mmalloc ( n * sizeof(long) , m_label);
		if ( ! newVals ) {
			mfree ( newKeys , n * sizeof(long) , m_label );
			return false;
		}
	}
	// rehash the slots if we had some
	if ( m_keys ) {
		for ( long i = 0 ; i < m_numSlots ; i++ ) {
			// skip the empty slots
			if ( m_keys [ i ] == 0 ) continue;
			// get the new slot # for this slot (might be the same)
			//longnum=((unsigned long)m_keys[i])%((unsigned long)n)
			long num=((unsigned long)m_keys[i])&
				((unsigned long)(n-1));
			// if that is occupied, go down
			while ( newKeys[num] ) if ( ++num >= n ) num = 0;
			// move the slotPtr/key/size to this new slot
			newKeys [ num ] = m_keys [ i ];
			newVals [ num ] = m_vals [ i ];
		}
	}
	// free the old guys
	if ( m_keys && savedDoFree ) {
		mfree ( m_keys , m_numSlots * sizeof(long) , m_label );
		mfree ( m_vals , m_numSlots * sizeof(long) , m_label );
	}
	// assign the new slots, m_numSlotsUsed should be the same
	m_keys = newKeys;
	m_vals = newVals;
	m_numSlots = n;
	m_mask     = n - 1;
	return true;
}

// both return false and set g_errno on error, true otherwise
bool HashTable::load ( char *dir , char *filename ) {
	reset();
	File f;
	f.set ( dir , filename );
	if ( ! f.doesExist() ) return true;
	log(LOG_INFO,"admin: Loading hashtable from %s%s",dir,filename);
	if ( ! f.open ( O_RDONLY) ) return false;
	long numSlots;
	long numSlotsUsed;
	long off = 0;
	if ( ! f.read ( &numSlots     , 4 , off ) ) return false;
	off += 4;
	if ( ! f.read ( &numSlotsUsed , 4 , off ) ) return false;
	off += 4;
	if ( ! setTableSize ( numSlots , NULL , 0 ) ) return false;
	if ( ! f.read ( m_keys        , numSlots * 4 , off ) ) return false;
	off += numSlots * 4;
	if ( ! f.read ( m_vals        , numSlots * 4 , off ) ) return false;
	off += numSlots * 4;
	m_numSlotsUsed = numSlotsUsed;
	f.close();
	return true;
}

bool HashTable::save ( char *dir , char *filename ) {
	File f;
	f.set ( dir , filename );
	log(LOG_INFO,"admin: Saving hashtable from %s%s",dir,filename);
	if ( ! f.open ( O_RDWR | O_CREAT ) ) return false;
	long numSlots     = m_numSlots;
	long numSlotsUsed = m_numSlotsUsed;
	long off = 0;
	if ( ! f.write ( &numSlots     , 4 , off ) ) return false;
	off += 4;
	if ( ! f.write ( &numSlotsUsed , 4 , off ) ) return false;
	off += 4;
	if ( ! f.write ( m_keys        , numSlots * 4 , off ) ) return false;
	off += numSlots * 4;
	if ( ! f.write ( m_vals        , numSlots * 4 , off ) ) return false;
	off += numSlots * 4;
	f.close();
	return true;
}
<commit_msg>fix core from last push.<commit_after>#include "gb-include.h"

#include "HashTable.h"

HashTable::HashTable () {
	m_keys = NULL;
	m_vals = NULL;
	m_numSlots     = 0;
	m_numSlotsUsed = 0;
	m_doFree       = true;
	m_label = NULL;
}

// returns false and sets errno on error
bool HashTable::set ( long initialNumTerms , char *buf , long bufSize ,
		      char *label ) {
	reset();
	m_label = label;
	if ( ! m_label ) m_label = "hashtablekv";
	return setTableSize ( initialNumTerms , buf , bufSize );
}

HashTable::~HashTable ( ) { reset ( ); }

// . call clean() to do a more careful reset
// . clean will rehash
void HashTable::reset ( ) {
	if ( m_doFree ) {
		if (m_keys) mfree(m_keys,m_numSlots*sizeof(long),"hashtablev");
		if (m_vals) mfree(m_vals,m_numSlots*sizeof(long),"hashtablev");
	}
	m_keys = NULL;
	m_vals = NULL;
	m_numSlots     = 0;
	m_numSlotsUsed = 0;
	// do not do this because then ::load() fails b/c you can't
	// pass a label into that yet
	//m_label = NULL;
}

void HashTable::clear ( ) {
	// vacate all slots
	if ( m_keys ) memset ( m_keys , 0 , sizeof(long) * m_numSlots );
	m_numSlotsUsed = 0;
}

// . returns the slot number for "key"
// . returns -1 if key not in hash table
long HashTable::getOccupiedSlotNum ( long key ) {
	if ( m_numSlots <= 0 ) return -1;
        //long n = ((unsigned long)key) % ((unsigned long)m_numSlots);
        long n = ((unsigned long)key) & m_mask;
        long count = 0;
        while ( count++ < m_numSlots ) {
                if ( m_keys [ n ] == 0   ) return -1;
		if ( m_keys [ n ] == key ) return  n;
		if ( ++n == m_numSlots ) n = 0;
        }
        log("hashtable: Could not get key. Table is full.");
        return -1;
}

// return 0 if key not in hash table
long HashTable::getValue ( long key ) {
	// returns -1 if key not in hash table
	long n = getOccupiedSlotNum ( key );
	if ( n < 0 ) return 0;
	return m_vals[n];
}

// . returns false and sets errno on error, returns true otherwise
// . adds scores if termId already exists in table
bool HashTable::addKey ( long key , long value , long *slot ) {
	// keys of 0 mean empty! they are reserved... fix that!
	if ( key == 0 ) { char *xx=NULL; *xx=0; }
	// check to see if we should grow the table
	if ( 100 * m_numSlotsUsed >= m_numSlots * 90 ) {
		long growTo = (m_numSlots * 120 ) / 100  + 20;
		if ( ! setTableSize ( growTo , NULL , 0 ) ) return false;
	}
        //long n = ((unsigned long)key) % ((unsigned long)m_numSlots);
        long n = ((unsigned long)key) & m_mask;
        long count = 0;
        while ( count++ < m_numSlots ) {
                if ( m_keys [ n ] == 0   ) break;
		if ( m_keys [ n ] == key ) break;
		if ( ++n == m_numSlots ) n = 0;
        }
	// bail if not found
	if ( count >= m_numSlots ) {
		g_errno = ENOMEM;
		return log("hashtable: Could not add key. Table is full.");
	}
	if ( m_keys [ n ] == 0 ) {
		// inc count if we're the first
		m_numSlotsUsed++;
		// and store the ky
		m_keys [ n ] = key;
	}
	// insert the value for this key
	m_vals [ n ] = value;
	if ( slot ) *slot = n;
	return true;
}

// patch the hole so chaining still works
bool HashTable::removeKey ( long key ) {
	// returns -1 if key not in hash table
	long n = getOccupiedSlotNum(key);
	if ( n < 0 ) return true;
	m_keys[n] = 0;
	m_numSlotsUsed--;
	if ( ++n >= m_numSlots ) n = 0;
	// keep looping until we hit an empty slot
	long val;
	while ( m_keys[n] ) {
		key = m_keys[n];
		val = m_vals[n];
		m_keys[n] = 0;
		m_numSlotsUsed--;
		addKey ( key , val );
		if ( ++n >= m_numSlots ) n = 0;
	}
	return true;
}

// patch the hole so chaining still works
void HashTable::removeSlot ( long n ) {
	// returns -1 if key not in hash table
	//long n = getOccupiedSlotNum(key);
	//if ( n < 0 ) return true;
	long key = m_keys[n];
	// sanity check, must not be empty
	if ( key == 0 ) { char *xx = NULL; *xx = 0; }
	// delete it
	m_keys[n] = 0;
	m_numSlotsUsed--;
	if ( ++n >= m_numSlots ) n = 0;
	// keep looping until we hit an empty slot
	long val;
	while ( m_keys[n] ) {
		key = m_keys[n];
		val = m_vals[n];
		m_keys[n] = 0;
		m_numSlotsUsed--;
		addKey ( key , val );
		if ( ++n >= m_numSlots ) n = 0;
	}
}

// . set table size to "n" slots
// . rehashes the termId/score pairs into new table
// . returns false and sets errno on error
bool HashTable::setTableSize ( long oldn , char *buf , long bufSize ) {
	// don't change size if we do not need to
	if ( oldn == m_numSlots ) return true;
	// make it a power of 2
	long n = getHighestLitBitValue ( (unsigned long)oldn * 2 - 1 );
	// do not go negative on me
	if ( oldn == 0 ) n = 0;
	// sanity check
	if ( n < oldn ) { char *xx = NULL; *xx = 0; }
	// do we have a buf?
	long need = 2 * n * sizeof(long);
	// sanity check, buf should also meet what we need
	if ( buf && bufSize < need ) { char *xx = NULL; *xx = 0; }
	// set the buf
	long *newKeys ;
	long *newVals ;
	// if we should not free note that
	bool savedDoFree = m_doFree ;
	// use our buf if we can
	if ( buf ) {
		m_doFree = false;
		bzero ( buf , need );
		newKeys = (long *)buf;
		buf += n * sizeof(long);
		newVals = (long *)buf;
		buf += n * sizeof(long);
	}
	else {
		m_doFree = true;
		char *label = m_label;
		if ( ! label ) label = "hashtablev";
		newKeys = (long *)mcalloc ( n * sizeof(long) , label);
		if ( ! newKeys ) return false;
		newVals = (long *)mmalloc ( n * sizeof(long) , label);
		if ( ! newVals ) {
			mfree ( newKeys , n * sizeof(long) , label );
			return false;
		}
	}
	// rehash the slots if we had some
	if ( m_keys ) {
		for ( long i = 0 ; i < m_numSlots ; i++ ) {
			// skip the empty slots
			if ( m_keys [ i ] == 0 ) continue;
			// get the new slot # for this slot (might be the same)
			//longnum=((unsigned long)m_keys[i])%((unsigned long)n)
			long num=((unsigned long)m_keys[i])&
				((unsigned long)(n-1));
			// if that is occupied, go down
			while ( newKeys[num] ) if ( ++num >= n ) num = 0;
			// move the slotPtr/key/size to this new slot
			newKeys [ num ] = m_keys [ i ];
			newVals [ num ] = m_vals [ i ];
		}
	}
	// free the old guys
	if ( m_keys && savedDoFree ) {
		mfree ( m_keys , m_numSlots * sizeof(long) , "hashtablev" );
		mfree ( m_vals , m_numSlots * sizeof(long) , "hashtablev" );
	}
	// assign the new slots, m_numSlotsUsed should be the same
	m_keys = newKeys;
	m_vals = newVals;
	m_numSlots = n;
	m_mask     = n - 1;
	return true;
}

// both return false and set g_errno on error, true otherwise
bool HashTable::load ( char *dir , char *filename ) {
	reset();
	File f;
	f.set ( dir , filename );
	if ( ! f.doesExist() ) return true;
	log(LOG_INFO,"admin: Loading hashtable from %s%s",dir,filename);
	if ( ! f.open ( O_RDONLY) ) return false;
	long numSlots;
	long numSlotsUsed;
	long off = 0;
	if ( ! f.read ( &numSlots     , 4 , off ) ) return false;
	off += 4;
	if ( ! f.read ( &numSlotsUsed , 4 , off ) ) return false;
	off += 4;
	if ( ! setTableSize ( numSlots , NULL , 0 ) ) return false;
	if ( ! f.read ( m_keys        , numSlots * 4 , off ) ) return false;
	off += numSlots * 4;
	if ( ! f.read ( m_vals        , numSlots * 4 , off ) ) return false;
	off += numSlots * 4;
	m_numSlotsUsed = numSlotsUsed;
	f.close();
	return true;
}

bool HashTable::save ( char *dir , char *filename ) {
	File f;
	f.set ( dir , filename );
	log(LOG_INFO,"admin: Saving hashtable from %s%s",dir,filename);
	if ( ! f.open ( O_RDWR | O_CREAT ) ) return false;
	long numSlots     = m_numSlots;
	long numSlotsUsed = m_numSlotsUsed;
	long off = 0;
	if ( ! f.write ( &numSlots     , 4 , off ) ) return false;
	off += 4;
	if ( ! f.write ( &numSlotsUsed , 4 , off ) ) return false;
	off += 4;
	if ( ! f.write ( m_keys        , numSlots * 4 , off ) ) return false;
	off += numSlots * 4;
	if ( ! f.write ( m_vals        , numSlots * 4 , off ) ) return false;
	off += numSlots * 4;
	f.close();
	return true;
}
<|endoftext|>