<commit_before>//
// Created by marvin on 03.04.16.
//

#include "Shoebill.h"

Shoebill &Shoebill::GetInstance()
{
    static Shoebill instance;
    return instance;
}

Shoebill::Shoebill()
{
}

Shoebill::~Shoebill()
{

}

int Shoebill::Initialize(JNIEnv *env)
{
    if (initialized)
    {
        LOG("[SHOEBILL] Shoebill is already initialized.");
        return -2;
    }
    shoebillLauncherClass = env->FindClass(LAUNCHER_CLASS_NAME);
    if (!shoebillLauncherClass)
    {
        sampgdk_logprintf("  > Error: Can't find launcher class [%s].", LAUNCHER_CLASS_NAME);
        return -1;
    }

    static jmethodID loadNativeLibraryMethodID = env->GetStaticMethodID(shoebillLauncherClass,
                                                                        LOAD_NATIVE_LIBRARY_METHOD_NAME,
                                                                        LOAD_NATIVE_LIBRARY_METHOD_SIGN);
    if (!loadNativeLibraryMethodID)
    {
        sampgdk_logprintf("  > Error: Can't find launcher method [%s::%s%s].", LAUNCHER_CLASS_NAME,
                          LOAD_NATIVE_LIBRARY_METHOD_NAME, LOAD_NATIVE_LIBRARY_METHOD_SIGN);
        return -6;
    }

    env->CallStaticVoidMethod(shoebillLauncherClass, loadNativeLibraryMethodID);
    if (env->ExceptionCheck())
    {
        jni_jvm_printExceptionStack(env);
        sampgdk_logprintf("  > Error: Can't load Shoebill JNI library.");
        return -7;
    }
    shoebillLauncherClass = (jclass) (env->NewGlobalRef(shoebillLauncherClass));
    jvm->AttachCurrentThread((void **) &env, NULL);

    StartShoebill();
    initialized = true;
    return 0;
}

int Shoebill::CreateShoebillObject(JNIEnv *env)
{
    if (initialized)
    {
        LOG("[SHOEBILL] Shoebill is already initialized!");
        return -9;
    }

    static jmethodID resolveDependenciesMethodID = env->GetStaticMethodID(shoebillLauncherClass,
                                                                          RESOLVE_DEPENDENCIES_METHOD_NAME,
                                                                          RESOLVE_DEPENDENCIES_METHOD_SIGN);
    if (!resolveDependenciesMethodID)
    {
        sampgdk_logprintf("ShoebillPlugin Error: Can't find launcher method [%s::%s%s].", LAUNCHER_CLASS_NAME,
                          RESOLVE_DEPENDENCIES_METHOD_NAME, RESOLVE_DEPENDENCIES_METHOD_SIGN);
        return -8;
    }

    jobject context = env->CallStaticObjectMethod(shoebillLauncherClass, resolveDependenciesMethodID);
    if (!context)
    {
        jni_jvm_printExceptionStack(env);
        sampgdk_logprintf("ShoebillPlugin Error: Can't resolve dependencies.");
        return -2;
    }

    static jmethodID createShoebillMethodID = env->GetStaticMethodID(shoebillLauncherClass, CREATE_SHOEBILL_METHOD_NAME,
                                                                     CREATE_SHOEBILL_METHOD_SIGN);
    if (!createShoebillMethodID)
    {
        sampgdk_logprintf(
                "ShoebillPlugin Error: Can't find launcher method [%s::%s%s], maybe the launcher library is outdated.",
                LAUNCHER_CLASS_NAME, CREATE_SHOEBILL_METHOD_NAME, CREATE_SHOEBILL_METHOD_SIGN);
        return -3;
    }

    std::unordered_set<AMX *> amxInstances = AmxInstanceManager::GetInstance().GetInstances();
    jsize size = amxInstances.size();
    jint *array = new jint[size];
    {
        int i = 0;
        for (std::unordered_set<AMX *>::iterator it = amxInstances.begin();
             it != amxInstances.end() && i < size; it++, i++)
        {
            array[i] = (jint) (*it);
        }
    }
    jintArray amxHandleArray = env->NewIntArray(size);
    env->SetIntArrayRegion(amxHandleArray, 0, size, array);
    delete array;

    shoebillObject = env->CallStaticObjectMethod(shoebillLauncherClass, createShoebillMethodID, context,
                                                 amxHandleArray);
    if (!shoebillObject)
    {
        jni_jvm_printExceptionStack(env);
        sampgdk_logprintf("ShoebillPlugin Error: Can't create shoebill object.");
        return -4;
    }

    shoebillClass = env->GetObjectClass(shoebillObject);
    if (!shoebillClass)
    {
        sampgdk_logprintf("ShoebillPlugin Error: Can't get shoebill class.");
        return -5;
    }

#if defined(LINUX)
    std::ifstream codepageFile(CODEPAGE_FILE_PATH, std::ifstream::in);
    if (codepageFile.is_open())
    {
        char input[256], charset[256];
        unsigned int code = 0;
        while (codepageFile.good())
        {
            codepageFile.getline(input, 256);
            sscanf(input, "%u %s", &code, charset);
            if (code && charset[0])
            {
                if (codepages.find(code) != codepages.end())
                    sampgdk_logprintf("  > Error: Codepage already in use, %d=%s", code, codepages[code].c_str());
                else
                {
                    codepages[code] = std::string(charset);
                }
            }
            code = 0;
            charset[0] = 0;
        }
        codepageFile.close();
    }
    else
    {
        sampgdk_logprintf("  > Error: Can't open %s.", CODEPAGE_FILE_PATH);
    }
#endif

    static jmethodID getCallbackHandlerMethodID = env->GetMethodID(shoebillClass, "getCallbackHandler",
                                                                   "()Lnet/gtaun/shoebill/samp/SampCallbackHandler;");
    if (!getCallbackHandlerMethodID)
    {
        sampgdk_logprintf("ShoebillPlugin Error: Can't find method getCallbackHandler().");
        return -6;
    }

    callbackHandlerObject = env->CallObjectMethod(shoebillObject, getCallbackHandlerMethodID);
    if (callbackHandlerObject == NULL)
    {
        sampgdk_logprintf("ShoebillPlugin Error: Can't find main EventHandler.");
        return -7;
    }

    shoebillObject = env->NewGlobalRef(shoebillObject);
    shoebillClass = (jclass) (env->NewGlobalRef(shoebillClass));
    callbackHandlerObject = env->NewGlobalRef(callbackHandlerObject);
    callbackHandlerClass = (jclass) (env->NewGlobalRef(env->GetObjectClass(callbackHandlerObject)));
    initialized = true;
    OnShoebillLoad();
    sampgdk_logprintf("  > Shoebill has been initialized.");
    return 0;
}

int Shoebill::ReleaseShoebillObject(JNIEnv *env)
{
    if (!initialized)
    {
        LOG("[SHOEBILL] Shoebill is not yet initialized!");
        return 0;
    }

    if (shoebillObject) env->DeleteGlobalRef(shoebillObject);
    shoebillObject = NULL;

    if (shoebillClass) env->DeleteGlobalRef(shoebillClass);
    shoebillClass = NULL;

    if (callbackHandlerObject) env->DeleteGlobalRef(callbackHandlerObject);
    callbackHandlerObject = NULL;

    if (callbackHandlerClass) env->DeleteGlobalRef(callbackHandlerClass);
    callbackHandlerClass = NULL;

    return 1;
}

int Shoebill::Uninitialize(JNIEnv *env)
{
    ReleaseShoebillObject(env);
    if (shoebillLauncherClass) env->DeleteGlobalRef(shoebillLauncherClass);
    shoebillLauncherClass = NULL;
    initialized = false;
    codepages.clear(); //Clear Codepages
    return 0;
}

void Shoebill::OnShoebillLoad()
{
    if (!callbackHandlerObject) return;

    JNIEnv *env;
    jvm->AttachCurrentThread((void **) &env, NULL);

    static jmethodID jmid = env->GetMethodID(callbackHandlerClass, "onShoebillLoad", "()V");
    if (!jmid) return;
    env->CallVoidMethod(callbackHandlerObject, jmid);
    jni_jvm_printExceptionStack(env);
}

bool Shoebill::OnPluginLoad()
{
    sampgdk_logprintf("  > Shoebill 1.2 NativePlugin for SA-MP 0.3.7 by MK124, JoJLlmAn & 123marvin123");

    char classpath[2048] = {0};
    if (findAndGenerateClassPath(JVM_CLASSPATH_SEARCH_PATH, classpath) < 0)
    {
        sampgdk_logprintf("  > Error: Can't find launcher library.");
        return false;
    }
    JNIEnv *env;
    if (jni_jvm_create(&env, classpath, JVM_OPTION_FILE_PATH) < 0)
    {
        sampgdk_logprintf("  > Error: Can't create Java VM.");
        return false;
    }
    sampgdk_logprintf("  > Java VM has been created.");
    jvm->AttachCurrentThread((void **) &env, NULL);
    int ret = Initialize(env);
    return ret >= 0;
}

bool Shoebill::OnPluginUnload()
{
    if (!callbackHandlerObject) return false;

    JNIEnv *env;
    jvm->AttachCurrentThread((void **) &env, NULL);

    static jmethodID jmid = env->GetMethodID(callbackHandlerClass, "onShoebillUnload", "()V");
    if (!jmid) return false;

    env->CallVoidMethod(callbackHandlerObject, jmid);
    jni_jvm_printExceptionStack(env);
    Uninitialize(env);
    if (jni_jvm_destroy(env) >= 0)
    {
        sampgdk_logprintf("  > Java VM has been destroyed.");
        return true;
    }
    return false;
}

int Shoebill::StartShoebill()
{
    if (initialized)
    {
        LOG("[SHOEBILL] Shoebill is already started.");
        return 0;
    }
    JNIEnv *env = NULL;
    jvm->AttachCurrentThread((void **) &env, NULL);
    return CreateShoebillObject(env);
}

void Shoebill::OnProcessTick()
{
    if (!callbackHandlerObject) return;

    JNIEnv *env = NULL;
    jvm->AttachCurrentThread((void **) &env, NULL);

    static jmethodID jmid = env->GetMethodID(callbackHandlerClass, "onProcessTick", "()V");
    if (!jmid) return;

    env->CallVoidMethod(callbackHandlerObject, jmid);
    jni_jvm_printExceptionStack(env);
}

int Shoebill::RestartShoebill()
{
    JNIEnv *env;
    jvm->AttachCurrentThread((void **) &env, NULL);
    if (!env) return 0;
    Uninitialize(env);
    Initialize(env);
    return 1;
}

int Shoebill::CallRegisteredFunction(AMX *amx, std::string functionName, jobjectArray parameters)
{
    if (!callbackHandlerObject) return -1;

    JNIEnv *env = NULL;
    jvm->AttachCurrentThread((void **) &env, NULL);

    static jmethodID jmid = env->GetMethodID(callbackHandlerClass, "onRegisteredFunctionCall",
                                             "(ILjava/lang/String;[Ljava/lang/Object;)I");
    if (!jmid) return -1;

    auto jstr = env->NewStringUTF(functionName.c_str());

    int result = env->CallIntMethod(callbackHandlerObject, jmid, amx, jstr, parameters);
    jni_jvm_printExceptionStack(env);
    return result;
}

void Shoebill::OnAmxLoad(AMX *amx)
{
    amx_Register(amx, PluginExports, -1);
    AmxInstanceManager::GetInstance().RegisterAmx(amx);
    if (!callbackHandlerObject) return;

    JNIEnv *env;
    jvm->AttachCurrentThread((void **) &env, NULL);

    static jmethodID jmid = env->GetMethodID(callbackHandlerClass, "onAmxLoad", "(I)V");
    if (!jmid) return;

    env->CallVoidMethod(callbackHandlerObject, jmid, amx);
    jni_jvm_printExceptionStack(env);

    int count;
    auto natives = sampgdk::GetNatives(count);
    for (int i = 0; i < count; i++)
    {
        const AMX_NATIVE_INFO native = *natives;
        NativeFunctionManager::GetInstance().RegisterFunction(amx, native.name, native.func, i);
        ++natives;
    }
}

void Shoebill::OnAmxUnload(AMX *amx)
{
    AmxInstanceManager::GetInstance().UnregisterAmx(amx);
    if (!callbackHandlerObject) return;

    JNIEnv *env;
    jvm->AttachCurrentThread((void **) &env, NULL);

    static jmethodID jmid = env->GetMethodID(callbackHandlerClass, "onAmxUnload", "(I)V");
    if (!jmid) return;

    env->CallVoidMethod(callbackHandlerObject, jmid, amx);
    jni_jvm_printExceptionStack(env);
}

<commit_msg>Change version info<commit_after>//
// Created by marvin on 03.04.16.
//

#include "Shoebill.h"

Shoebill &Shoebill::GetInstance()
{
    static Shoebill instance;
    return instance;
}

Shoebill::Shoebill()
{
}

Shoebill::~Shoebill()
{

}

int Shoebill::Initialize(JNIEnv *env)
{
    if (initialized)
    {
        LOG("[SHOEBILL] Shoebill is already initialized.");
        return -2;
    }
    shoebillLauncherClass = env->FindClass(LAUNCHER_CLASS_NAME);
    if (!shoebillLauncherClass)
    {
        sampgdk_logprintf("  > Error: Can't find launcher class [%s].", LAUNCHER_CLASS_NAME);
        return -1;
    }

    static jmethodID loadNativeLibraryMethodID = env->GetStaticMethodID(shoebillLauncherClass,
                                                                        LOAD_NATIVE_LIBRARY_METHOD_NAME,
                                                                        LOAD_NATIVE_LIBRARY_METHOD_SIGN);
    if (!loadNativeLibraryMethodID)
    {
        sampgdk_logprintf("  > Error: Can't find launcher method [%s::%s%s].", LAUNCHER_CLASS_NAME,
                          LOAD_NATIVE_LIBRARY_METHOD_NAME, LOAD_NATIVE_LIBRARY_METHOD_SIGN);
        return -6;
    }

    env->CallStaticVoidMethod(shoebillLauncherClass, loadNativeLibraryMethodID);
    if (env->ExceptionCheck())
    {
        jni_jvm_printExceptionStack(env);
        sampgdk_logprintf("  > Error: Can't load Shoebill JNI library.");
        return -7;
    }
    shoebillLauncherClass = (jclass) (env->NewGlobalRef(shoebillLauncherClass));
    jvm->AttachCurrentThread((void **) &env, NULL);

    StartShoebill();
    initialized = true;
    return 0;
}

int Shoebill::CreateShoebillObject(JNIEnv *env)
{
    if (initialized)
    {
        LOG("[SHOEBILL] Shoebill is already initialized!");
        return -9;
    }

    static jmethodID resolveDependenciesMethodID = env->GetStaticMethodID(shoebillLauncherClass,
                                                                          RESOLVE_DEPENDENCIES_METHOD_NAME,
                                                                          RESOLVE_DEPENDENCIES_METHOD_SIGN);
    if (!resolveDependenciesMethodID)
    {
        sampgdk_logprintf("ShoebillPlugin Error: Can't find launcher method [%s::%s%s].", LAUNCHER_CLASS_NAME,
                          RESOLVE_DEPENDENCIES_METHOD_NAME, RESOLVE_DEPENDENCIES_METHOD_SIGN);
        return -8;
    }

    jobject context = env->CallStaticObjectMethod(shoebillLauncherClass, resolveDependenciesMethodID);
    if (!context)
    {
        jni_jvm_printExceptionStack(env);
        sampgdk_logprintf("ShoebillPlugin Error: Can't resolve dependencies.");
        return -2;
    }

    static jmethodID createShoebillMethodID = env->GetStaticMethodID(shoebillLauncherClass, CREATE_SHOEBILL_METHOD_NAME,
                                                                     CREATE_SHOEBILL_METHOD_SIGN);
    if (!createShoebillMethodID)
    {
        sampgdk_logprintf(
                "ShoebillPlugin Error: Can't find launcher method [%s::%s%s], maybe the launcher library is outdated.",
                LAUNCHER_CLASS_NAME, CREATE_SHOEBILL_METHOD_NAME, CREATE_SHOEBILL_METHOD_SIGN);
        return -3;
    }

    std::unordered_set<AMX *> amxInstances = AmxInstanceManager::GetInstance().GetInstances();
    jsize size = amxInstances.size();
    jint *array = new jint[size];
    {
        int i = 0;
        for (std::unordered_set<AMX *>::iterator it = amxInstances.begin();
             it != amxInstances.end() && i < size; it++, i++)
        {
            array[i] = (jint) (*it);
        }
    }
    jintArray amxHandleArray = env->NewIntArray(size);
    env->SetIntArrayRegion(amxHandleArray, 0, size, array);
    delete array;

    shoebillObject = env->CallStaticObjectMethod(shoebillLauncherClass, createShoebillMethodID, context,
                                                 amxHandleArray);
    if (!shoebillObject)
    {
        jni_jvm_printExceptionStack(env);
        sampgdk_logprintf("ShoebillPlugin Error: Can't create shoebill object.");
        return -4;
    }

    shoebillClass = env->GetObjectClass(shoebillObject);
    if (!shoebillClass)
    {
        sampgdk_logprintf("ShoebillPlugin Error: Can't get shoebill class.");
        return -5;
    }

#if defined(LINUX)
    std::ifstream codepageFile(CODEPAGE_FILE_PATH, std::ifstream::in);
    if (codepageFile.is_open())
    {
        char input[256], charset[256];
        unsigned int code = 0;
        while (codepageFile.good())
        {
            codepageFile.getline(input, 256);
            sscanf(input, "%u %s", &code, charset);
            if (code && charset[0])
            {
                if (codepages.find(code) != codepages.end())
                    sampgdk_logprintf("  > Error: Codepage already in use, %d=%s", code, codepages[code].c_str());
                else
                {
                    codepages[code] = std::string(charset);
                }
            }
            code = 0;
            charset[0] = 0;
        }
        codepageFile.close();
    }
    else
    {
        sampgdk_logprintf("  > Error: Can't open %s.", CODEPAGE_FILE_PATH);
    }
#endif

    static jmethodID getCallbackHandlerMethodID = env->GetMethodID(shoebillClass, "getCallbackHandler",
                                                                   "()Lnet/gtaun/shoebill/samp/SampCallbackHandler;");
    if (!getCallbackHandlerMethodID)
    {
        sampgdk_logprintf("ShoebillPlugin Error: Can't find method getCallbackHandler().");
        return -6;
    }

    callbackHandlerObject = env->CallObjectMethod(shoebillObject, getCallbackHandlerMethodID);
    if (callbackHandlerObject == NULL)
    {
        sampgdk_logprintf("ShoebillPlugin Error: Can't find main EventHandler.");
        return -7;
    }

    shoebillObject = env->NewGlobalRef(shoebillObject);
    shoebillClass = (jclass) (env->NewGlobalRef(shoebillClass));
    callbackHandlerObject = env->NewGlobalRef(callbackHandlerObject);
    callbackHandlerClass = (jclass) (env->NewGlobalRef(env->GetObjectClass(callbackHandlerObject)));
    initialized = true;
    OnShoebillLoad();
    sampgdk_logprintf("  > Shoebill has been initialized.");
    return 0;
}

int Shoebill::ReleaseShoebillObject(JNIEnv *env)
{
    if (!initialized)
    {
        LOG("[SHOEBILL] Shoebill is not yet initialized!");
        return 0;
    }

    if (shoebillObject) env->DeleteGlobalRef(shoebillObject);
    shoebillObject = NULL;

    if (shoebillClass) env->DeleteGlobalRef(shoebillClass);
    shoebillClass = NULL;

    if (callbackHandlerObject) env->DeleteGlobalRef(callbackHandlerObject);
    callbackHandlerObject = NULL;

    if (callbackHandlerClass) env->DeleteGlobalRef(callbackHandlerClass);
    callbackHandlerClass = NULL;

    return 1;
}

int Shoebill::Uninitialize(JNIEnv *env)
{
    ReleaseShoebillObject(env);
    if (shoebillLauncherClass) env->DeleteGlobalRef(shoebillLauncherClass);
    shoebillLauncherClass = NULL;
    initialized = false;
    codepages.clear(); //Clear Codepages
    return 0;
}

void Shoebill::OnShoebillLoad()
{
    if (!callbackHandlerObject) return;

    JNIEnv *env;
    jvm->AttachCurrentThread((void **) &env, NULL);

    static jmethodID jmid = env->GetMethodID(callbackHandlerClass, "onShoebillLoad", "()V");
    if (!jmid) return;
    env->CallVoidMethod(callbackHandlerObject, jmid);
    jni_jvm_printExceptionStack(env);
}

bool Shoebill::OnPluginLoad()
{
    sampgdk_logprintf("  > Shoebill 1.3 NativePlugin for SA-MP 0.3.7 by MK124, JoJLlmAn & 123marvin123");

    char classpath[2048] = {0};
    if (findAndGenerateClassPath(JVM_CLASSPATH_SEARCH_PATH, classpath) < 0)
    {
        sampgdk_logprintf("  > Error: Can't find launcher library.");
        return false;
    }
    JNIEnv *env;
    if (jni_jvm_create(&env, classpath, JVM_OPTION_FILE_PATH) < 0)
    {
        sampgdk_logprintf("  > Error: Can't create Java VM.");
        return false;
    }
    sampgdk_logprintf("  > Java VM has been created.");
    jvm->AttachCurrentThread((void **) &env, NULL);
    int ret = Initialize(env);
    return ret >= 0;
}

bool Shoebill::OnPluginUnload()
{
    if (!callbackHandlerObject) return false;

    JNIEnv *env;
    jvm->AttachCurrentThread((void **) &env, NULL);

    static jmethodID jmid = env->GetMethodID(callbackHandlerClass, "onShoebillUnload", "()V");
    if (!jmid) return false;

    env->CallVoidMethod(callbackHandlerObject, jmid);
    jni_jvm_printExceptionStack(env);
    Uninitialize(env);
    if (jni_jvm_destroy(env) >= 0)
    {
        sampgdk_logprintf("  > Java VM has been destroyed.");
        return true;
    }
    return false;
}

int Shoebill::StartShoebill()
{
    if (initialized)
    {
        LOG("[SHOEBILL] Shoebill is already started.");
        return 0;
    }
    JNIEnv *env = NULL;
    jvm->AttachCurrentThread((void **) &env, NULL);
    return CreateShoebillObject(env);
}

void Shoebill::OnProcessTick()
{
    if (!callbackHandlerObject) return;

    JNIEnv *env = NULL;
    jvm->AttachCurrentThread((void **) &env, NULL);

    static jmethodID jmid = env->GetMethodID(callbackHandlerClass, "onProcessTick", "()V");
    if (!jmid) return;

    env->CallVoidMethod(callbackHandlerObject, jmid);
    jni_jvm_printExceptionStack(env);
}

int Shoebill::RestartShoebill()
{
    JNIEnv *env;
    jvm->AttachCurrentThread((void **) &env, NULL);
    if (!env) return 0;
    Uninitialize(env);
    Initialize(env);
    return 1;
}

int Shoebill::CallRegisteredFunction(AMX *amx, std::string functionName, jobjectArray parameters)
{
    if (!callbackHandlerObject) return -1;

    JNIEnv *env = NULL;
    jvm->AttachCurrentThread((void **) &env, NULL);

    static jmethodID jmid = env->GetMethodID(callbackHandlerClass, "onRegisteredFunctionCall",
                                             "(ILjava/lang/String;[Ljava/lang/Object;)I");
    if (!jmid) return -1;

    auto jstr = env->NewStringUTF(functionName.c_str());

    int result = env->CallIntMethod(callbackHandlerObject, jmid, amx, jstr, parameters);
    jni_jvm_printExceptionStack(env);
    return result;
}

void Shoebill::OnAmxLoad(AMX *amx)
{
    amx_Register(amx, PluginExports, -1);
    AmxInstanceManager::GetInstance().RegisterAmx(amx);
    if (!callbackHandlerObject) return;

    JNIEnv *env;
    jvm->AttachCurrentThread((void **) &env, NULL);

    static jmethodID jmid = env->GetMethodID(callbackHandlerClass, "onAmxLoad", "(I)V");
    if (!jmid) return;

    env->CallVoidMethod(callbackHandlerObject, jmid, amx);
    jni_jvm_printExceptionStack(env);

    int count;
    auto natives = sampgdk::GetNatives(count);
    for (int i = 0; i < count; i++)
    {
        const AMX_NATIVE_INFO native = *natives;
        NativeFunctionManager::GetInstance().RegisterFunction(amx, native.name, native.func, i);
        ++natives;
    }
}

void Shoebill::OnAmxUnload(AMX *amx)
{
    AmxInstanceManager::GetInstance().UnregisterAmx(amx);
    if (!callbackHandlerObject) return;

    JNIEnv *env;
    jvm->AttachCurrentThread((void **) &env, NULL);

    static jmethodID jmid = env->GetMethodID(callbackHandlerClass, "onAmxUnload", "(I)V");
    if (!jmid) return;

    env->CallVoidMethod(callbackHandlerObject, jmid, amx);
    jni_jvm_printExceptionStack(env);
}

<|endoftext|>


<commit_before>#include "GroupLabelPreProcessor.h"
#include <bundles/mining/MiningSearchService.h>

#include <glog/logging.h>

namespace sf1r
{

void GroupLabelPreProcessor::process(
    KeywordSearchActionItem& actionItem,
    KeywordSearchResult& searchResult)
{
    faceted::GroupParam& groupParam = actionItem.groupParam_;
    typedef faceted::GroupParam::AutoSelectLimitMap LimitMap;
    LimitMap& limitMap = groupParam.autoSelectLimits_;

    if (limitMap.empty())
        return;

    const std::string& query = actionItem.env_.queryString_;
    typedef faceted::GroupParam::GroupLabelMap GroupLabelMap;
    GroupLabelMap& totalLabels = groupParam.groupLabels_;
    GroupLabelMap& autoSelectLabels = searchResult.autoSelectGroupLabels_;

    for (LimitMap::const_iterator limitIt = limitMap.begin();
         limitIt != limitMap.end(); ++limitIt)
    {
        pushTopLabels_(totalLabels, autoSelectLabels,
                       query, limitIt->first, limitIt->second);
    }
}

void GroupLabelPreProcessor::pushTopLabels_(
    faceted::GroupParam::GroupLabelMap& totalLabels,
    faceted::GroupParam::GroupLabelMap& autoSelectLabels,
    const std::string& query,
    const std::string& propName,
    int limit)
{
    typedef faceted::GroupParam::GroupPathVec GroupPathVec;
    GroupPathVec pathVec;
    std::vector<int> freqVec;

    if (! miningSearchService_->getFreqGroupLabel(
            query, propName, limit, pathVec, freqVec))
    {
        LOG(ERROR) << "failed to get frequent label for group property: "
                   << propName << ", query: " << query;
    }

    if (pathVec.empty())
    {
        if(limit <3) limit = 3;
        miningSearchService_->GetProductCategory(query, limit, pathVec);
    }

    for (GroupPathVec::const_iterator pathIt = pathVec.begin();
         pathIt != pathVec.end(); ++pathIt)
    {
        totalLabels[propName].push_back(*pathIt);
    }
    autoSelectLabels[propName].swap(pathVec);
}

} // namespace sf1r
<commit_msg>recover lowerbound auto_select_limit from 3 to 1<commit_after>#include "GroupLabelPreProcessor.h"
#include <bundles/mining/MiningSearchService.h>

#include <glog/logging.h>

namespace sf1r
{

void GroupLabelPreProcessor::process(
    KeywordSearchActionItem& actionItem,
    KeywordSearchResult& searchResult)
{
    faceted::GroupParam& groupParam = actionItem.groupParam_;
    typedef faceted::GroupParam::AutoSelectLimitMap LimitMap;
    LimitMap& limitMap = groupParam.autoSelectLimits_;

    if (limitMap.empty())
        return;

    const std::string& query = actionItem.env_.queryString_;
    typedef faceted::GroupParam::GroupLabelMap GroupLabelMap;
    GroupLabelMap& totalLabels = groupParam.groupLabels_;
    GroupLabelMap& autoSelectLabels = searchResult.autoSelectGroupLabels_;

    for (LimitMap::const_iterator limitIt = limitMap.begin();
         limitIt != limitMap.end(); ++limitIt)
    {
        pushTopLabels_(totalLabels, autoSelectLabels,
                       query, limitIt->first, limitIt->second);
    }
}

void GroupLabelPreProcessor::pushTopLabels_(
    faceted::GroupParam::GroupLabelMap& totalLabels,
    faceted::GroupParam::GroupLabelMap& autoSelectLabels,
    const std::string& query,
    const std::string& propName,
    int limit)
{
    typedef faceted::GroupParam::GroupPathVec GroupPathVec;
    GroupPathVec pathVec;
    std::vector<int> freqVec;

    if (! miningSearchService_->getFreqGroupLabel(
            query, propName, limit, pathVec, freqVec))
    {
        LOG(ERROR) << "failed to get frequent label for group property: "
                   << propName << ", query: " << query;
    }

    if (pathVec.empty())
    {
        //if(limit <3) limit = 3;
        miningSearchService_->GetProductCategory(query, limit, pathVec);
    }

    for (GroupPathVec::const_iterator pathIt = pathVec.begin();
         pathIt != pathVec.end(); ++pathIt)
    {
        totalLabels[propName].push_back(*pathIt);
    }
    autoSelectLabels[propName].swap(pathVec);
}

} // namespace sf1r
<|endoftext|>


<commit_before>// This may look like C code, but it is really -*- C++ -*-
//
// Copyright Bob Friesenhahn, 1999, 2000, 2001, 2002, 2003
//
// Pixels Implementation
//

#define MAGICKCORE_IMPLEMENTATION  1
#define MAGICK_PLUSPLUS_IMPLEMENTATION 1

#include <cstring>
#include "Magick++/Include.h"
#include <string> // This is here to compile with Visual C++
#include "Magick++/Thread.h"
#include "Magick++/Exception.h"
#include "Magick++/Pixels.h"

Magick::Pixels::Pixels(Magick::Image &image_)
  : _image(image_),
    _view(AcquireVirtualCacheView(_image.image(),&_exception)),
    _x(0),
    _y(0),
    _columns(0),
    _rows(0)
{
  GetExceptionInfo(&_exception);

  if (!_view)
    throwExceptionExplicit(OptionError,"Empty view detected.");
}

Magick::Pixels::~Pixels(void)
{
  if (_view)
    _view=DestroyCacheView(_view);

  (void) DestroyExceptionInfo(&_exception);
}

Magick::Quantum* Magick::Pixels::get(const ssize_t x_,const ssize_t y_,
  const size_t columns_,const size_t rows_)
{
  _x=x_;
  _y=y_;
  _columns=columns_;
  _rows=rows_;

  Quantum* pixels=GetCacheViewAuthenticPixels(_view,x_,y_,columns_,rows_,
    &_exception);

  if (!pixels)
    throwException(_exception);

  return pixels;
}

const Magick::Quantum* Magick::Pixels::getConst(const ssize_t x_,
  const ssize_t y_,const size_t columns_,const size_t rows_)
{
  _x=x_;
  _y=y_;
  _columns=columns_;
  _rows=rows_;

  const Quantum* pixels=GetCacheViewVirtualPixels(_view,x_,y_,columns_,rows_,
    &_exception);

  if (!pixels)
    throwException(_exception);

  return pixels;
}

ssize_t Magick::Pixels::offset(PixelChannel channel) const
{
  if (_image.constImage()->channel_map[channel].traits == UndefinedPixelTrait)
    return -1;
  return _image.constImage()->channel_map[channel].offset;
}

Magick::Quantum* Magick::Pixels::set(const ssize_t x_,const ssize_t y_,
  const size_t columns_,const size_t rows_)
{
  _x=x_;
  _y=y_;
  _columns=columns_;
  _rows=rows_;

  Quantum* pixels=QueueCacheViewAuthenticPixels(_view,x_,y_,columns_,rows_,
    &_exception);

  if (!pixels)
    throwException(_exception);

  return pixels;
}

void Magick::Pixels::sync(void)
{
  if(!SyncCacheViewAuthenticPixels(_view,&_exception))
    throwException(_exception);
}

// Return pixel colormap index array
/*
Magick::void* Magick::Pixels::metacontent(void)
{
  void* pixel_metacontent=GetCacheViewAuthenticMetacontent(_view);

  if (!pixel_metacontent)
    _image.throwImageException();

  return pixel_metacontent;
}
*/

Magick::PixelData::PixelData(Magick::Image &image_,std::string map_,
  const StorageType type_)
{
  init(image_,0,0,image_.columns(),image_.rows(),map_,type_);
}

Magick::PixelData::PixelData(Magick::Image &image_,const ::ssize_t x_,
  const ::ssize_t y_,const size_t width_,const size_t height_,std::string map_,
  const StorageType type_)
{
  init(image_,x_,y_,width_,height_,map_,type_);
}

Magick::PixelData::~PixelData(void)
{
  relinquish();
}

const void *Magick::PixelData::data(void) const
{
  return(_data);
}

const ::ssize_t Magick::PixelData::length(void) const
{
  return(_length);
}

const ::ssize_t Magick::PixelData::size(void) const
{
  return(_size);
}

void Magick::PixelData::init(Magick::Image &image_,const ::ssize_t x_,
  const ::ssize_t y_,const size_t width_,const size_t height_,
  std::string map_,const StorageType type_)
{
  size_t
    size;

  _data=(void *) NULL;
  _length=0;
  _size=0;
  if ((x_ < 0) || (width_ < 0) || (y_ < 0) || (height_ < 0) ||
      (x_ > image_.columns()) || (width_ + x_ > image_.columns()) ||
      (y_ > image_.rows()) || (height_ + y_ > image_.rows()) ||
      (map_.length() == 0))
    return;

  switch(type_)
  {
    case CharPixel:
      size=sizeof(unsigned char);
      break;
    case DoublePixel:
      size=sizeof(double);
      break;
    case FloatPixel:
      size=sizeof(float);
      break;
    case LongPixel:
      size=sizeof(unsigned int);
      break;
    case LongLongPixel:
      size=sizeof(MagickSizeType);
      break;
    case QuantumPixel:
      size=sizeof(Quantum);
      break;
    case ShortPixel:
      size=sizeof(unsigned short);
      break;
    default:
      throwExceptionExplicit(OptionError,"Invalid type");
      return;
  }

  _length=width_*height_*map_.length();
  _size=_length*size;
  _data=AcquireMagickMemory(_size);

  GetPPException;
  MagickCore::ExportImagePixels(image_.constImage(),x_,y_,width_,height_,
    map_.c_str(),type_,_data,&exceptionInfo);
  if (exceptionInfo.severity != UndefinedException)
    relinquish();
  ThrowPPException;
}

void Magick::PixelData::relinquish(void) throw()
{
  if (_data != (void *)NULL)
    _data=RelinquishMagickMemory(_data);
  _length=0;
  _size=0;
}<commit_msg>Build fix.<commit_after>// This may look like C code, but it is really -*- C++ -*-
//
// Copyright Bob Friesenhahn, 1999, 2000, 2001, 2002, 2003
//
// Pixels Implementation
//

#define MAGICKCORE_IMPLEMENTATION  1
#define MAGICK_PLUSPLUS_IMPLEMENTATION 1

#include <cstring>
#include "Magick++/Include.h"
#include <string> // This is here to compile with Visual C++
#include "Magick++/Thread.h"
#include "Magick++/Exception.h"
#include "Magick++/Pixels.h"

Magick::Pixels::Pixels(Magick::Image &image_)
  : _image(image_),
    _view(AcquireVirtualCacheView(_image.image(),&_exception)),
    _x(0),
    _y(0),
    _columns(0),
    _rows(0)
{
  GetExceptionInfo(&_exception);

  if (!_view)
    throwExceptionExplicit(OptionError,"Empty view detected.");
}

Magick::Pixels::~Pixels(void)
{
  if (_view)
    _view=DestroyCacheView(_view);

  (void) DestroyExceptionInfo(&_exception);
}

Magick::Quantum* Magick::Pixels::get(const ssize_t x_,const ssize_t y_,
  const size_t columns_,const size_t rows_)
{
  _x=x_;
  _y=y_;
  _columns=columns_;
  _rows=rows_;

  Quantum* pixels=GetCacheViewAuthenticPixels(_view,x_,y_,columns_,rows_,
    &_exception);

  if (!pixels)
    throwException(_exception);

  return pixels;
}

const Magick::Quantum* Magick::Pixels::getConst(const ssize_t x_,
  const ssize_t y_,const size_t columns_,const size_t rows_)
{
  _x=x_;
  _y=y_;
  _columns=columns_;
  _rows=rows_;

  const Quantum* pixels=GetCacheViewVirtualPixels(_view,x_,y_,columns_,rows_,
    &_exception);

  if (!pixels)
    throwException(_exception);

  return pixels;
}

ssize_t Magick::Pixels::offset(PixelChannel channel) const
{
  if (_image.constImage()->channel_map[channel].traits == UndefinedPixelTrait)
    return -1;
  return _image.constImage()->channel_map[channel].offset;
}

Magick::Quantum* Magick::Pixels::set(const ssize_t x_,const ssize_t y_,
  const size_t columns_,const size_t rows_)
{
  _x=x_;
  _y=y_;
  _columns=columns_;
  _rows=rows_;

  Quantum* pixels=QueueCacheViewAuthenticPixels(_view,x_,y_,columns_,rows_,
    &_exception);

  if (!pixels)
    throwException(_exception);

  return pixels;
}

void Magick::Pixels::sync(void)
{
  if(!SyncCacheViewAuthenticPixels(_view,&_exception))
    throwException(_exception);
}

// Return pixel colormap index array
/*
Magick::void* Magick::Pixels::metacontent(void)
{
  void* pixel_metacontent=GetCacheViewAuthenticMetacontent(_view);

  if (!pixel_metacontent)
    _image.throwImageException();

  return pixel_metacontent;
}
*/

Magick::PixelData::PixelData(Magick::Image &image_,std::string map_,
  const StorageType type_)
{
  init(image_,0,0,image_.columns(),image_.rows(),map_,type_);
}

Magick::PixelData::PixelData(Magick::Image &image_,const ::ssize_t x_,
  const ::ssize_t y_,const size_t width_,const size_t height_,std::string map_,
  const StorageType type_)
{
  init(image_,x_,y_,width_,height_,map_,type_);
}

Magick::PixelData::~PixelData(void)
{
  relinquish();
}

const void *Magick::PixelData::data(void) const
{
  return(_data);
}

const ::ssize_t Magick::PixelData::length(void) const
{
  return(_length);
}

const ::ssize_t Magick::PixelData::size(void) const
{
  return(_size);
}

void Magick::PixelData::init(Magick::Image &image_,const ::ssize_t x_,
  const ::ssize_t y_,const size_t width_,const size_t height_,
  std::string map_,const StorageType type_)
{
  size_t
    size;

  _data=(void *) NULL;
  _length=0;
  _size=0;
  if ((x_ < 0) || (width_ < 0) || (y_ < 0) || (height_ < 0) ||
      (x_ > image_.columns()) || (width_ + x_ > image_.columns()) ||
      (y_ > image_.rows()) || (height_ + y_ > image_.rows()) ||
      (map_.length() == 0))
    return;

  switch(type_)
  {
    case CharPixel:
      size=sizeof(unsigned char);
      break;
    case DoublePixel:
      size=sizeof(double);
      break;
    case FloatPixel:
      size=sizeof(float);
      break;
    case LongPixel:
      size=sizeof(unsigned int);
      break;
    case LongLongPixel:
      size=sizeof(MagickSizeType);
      break;
    case QuantumPixel:
      size=sizeof(Quantum);
      break;
    case ShortPixel:
      size=sizeof(unsigned short);
      break;
    default:
      throwExceptionExplicit(OptionError,"Invalid type");
      return;
  }

  _length=width_*height_*map_.length();
  _size=_length*size;
  _data=AcquireMagickMemory(_size);

  GetPPException;
  MagickCore::ExportImagePixels(image_.image(),x_,y_,width_,height_,
    map_.c_str(),type_,_data,&exceptionInfo);
  if (exceptionInfo.severity != UndefinedException)
    relinquish();
  ThrowPPException;
}

void Magick::PixelData::relinquish(void) throw()
{
  if (_data != (void *)NULL)
    _data=RelinquishMagickMemory(_data);
  _length=0;
  _size=0;
}<|endoftext|>


<commit_before>// RUN: llvm-cov show %S/Inputs/showExpansions.covmapping -instr-profile %S/Inputs/showExpansions.profdata -dump -show-expansions -filename-equivalence %s | FileCheck %s

#define DO_SOMETHING_ELSE() \
  do {                      \
  } while (0)
#define ANOTHER_THING() \
  do {                  \
    if (0) {            \
    }                   \
  } while (0)

#define DO_SOMETHING(x)    \
  do {                     \
    if (x)                 \
      DO_SOMETHING_ELSE(); \
    else                   \
      ANOTHER_THING();     \
  } while (0)

int main(int argc, const char *argv[]) {
  for (int i = 0; i < 100; ++i)
    DO_SOMETHING(i);
  return 0;
}

// CHECK: Expansion of {{[0-9]+}}:13 -> 18 @ {{[0-9]+}}, 22:5
// CHECK: Expansion of {{[0-9]+}}:4 -> 5 @ {{[0-9]+}}, 15:7
// CHECK: Expansion of {{[0-9]+}}:7 -> 10 @ {{[0-9]+}}, 17:7

// llvm-cov doesn't work on big endian yet
// XFAIL: powerpc64-, s390x, mips-, mips64-, sparc
<commit_msg>llvm-cov: Remove an overly system specific test<commit_after><|endoftext|>


<commit_before>/* Copyright 2016 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include <deque>
#include <vector>

#include "tensorflow/core/common_runtime/device.h"
#include "tensorflow/core/common_runtime/executor.h"
#include "tensorflow/core/common_runtime/function.h"
#include "tensorflow/core/common_runtime/memory_types.h"
#include "tensorflow/core/framework/function.h"
#include "tensorflow/core/framework/op.h"
#include "tensorflow/core/framework/op_kernel.h"
#include "tensorflow/core/framework/register_types.h"
#include "tensorflow/core/graph/algorithm.h"
#include "tensorflow/core/graph/gradients.h"
#include "tensorflow/core/graph/graph_constructor.h"
#include "tensorflow/core/platform/macros.h"
#include "tensorflow/core/util/device_name_utils.h"

namespace tensorflow {

static const char* const kGradientOp = "SymbolicGradient";

class ArgOp : public OpKernel {
 public:
  explicit ArgOp(OpKernelConstruction* ctx) : OpKernel(ctx) {
    OP_REQUIRES_OK(ctx, ctx->GetAttr("T", &dtype_));
    OP_REQUIRES_OK(ctx, ctx->GetAttr("index", &index_));
  }

  void Compute(OpKernelContext* ctx) override {
    auto frame = ctx->call_frame();
    OP_REQUIRES(ctx, frame != nullptr, errors::Internal("no call frame"));
    Tensor val;
    OP_REQUIRES_OK(ctx, frame->GetArg(index_, &val));
    OP_REQUIRES(ctx, val.dtype() == dtype_,
                errors::InvalidArgument(
                    "Type mismatch: actual ", DataTypeString(val.dtype()),
                    " vs. expect ", DataTypeString(dtype_)));
    ctx->set_output(0, val);
  }

 private:
  int index_;
  DataType dtype_;

  TF_DISALLOW_COPY_AND_ASSIGN(ArgOp);
};

class RetvalOp : public OpKernel {
 public:
  explicit RetvalOp(OpKernelConstruction* ctx) : OpKernel(ctx) {
    OP_REQUIRES_OK(ctx, ctx->GetAttr("T", &dtype_));
    OP_REQUIRES_OK(ctx, ctx->GetAttr("index", &index_));
  }

  void Compute(OpKernelContext* ctx) override {
    const Tensor& val = ctx->input(0);
    OP_REQUIRES(ctx, val.dtype() == dtype_,
                errors::InvalidArgument(
                    "Type mismatch: actual ", DataTypeString(val.dtype()),
                    " vs. expect ", DataTypeString(dtype_)));
    auto frame = ctx->call_frame();
    OP_REQUIRES(ctx, frame != nullptr, errors::Internal("no call frame"));
    OP_REQUIRES_OK(ctx, frame->SetRetval(index_, val));
  }

 private:
  int index_;
  DataType dtype_;

  TF_DISALLOW_COPY_AND_ASSIGN(RetvalOp);
};

REGISTER_SYSTEM_KERNEL_BUILDER(Name("_Arg").Device(DEVICE_CPU), ArgOp);
REGISTER_SYSTEM_KERNEL_BUILDER(Name("_Retval").Device(DEVICE_CPU), RetvalOp);

#if TENSORFLOW_USE_SYCL
#define REGISTER(type)     \
  REGISTER_KERNEL_BUILDER( \
      Name("_Arg").Device(DEVICE_SYCL).TypeConstraint<type>("T"), ArgOp);
TF_CALL_NUMBER_TYPES_NO_INT32(REGISTER)
TF_CALL_bool(REGISTER) REGISTER_KERNEL_BUILDER(Name("_Arg")
                                                   .Device(DEVICE_SYCL)
                                                   .HostMemory("output")
                                                   .TypeConstraint<int32>("T"),
                                               ArgOp);
#undef REGISTER
#define REGISTER(type)                                               \
  REGISTER_KERNEL_BUILDER(                                           \
      Name("_Retval").Device(DEVICE_SYCL).TypeConstraint<type>("T"), \
      RetvalOp);
TF_CALL_NUMBER_TYPES_NO_INT32(REGISTER)
TF_CALL_bool(REGISTER) REGISTER_KERNEL_BUILDER(Name("_Retval")
                                                   .Device(DEVICE_SYCL)
                                                   .HostMemory("input")
                                                   .TypeConstraint<int32>("T"),
                                               RetvalOp);
#undef REGISTER
#endif

#define REGISTER(type)     \
  REGISTER_KERNEL_BUILDER( \
      Name("_Arg").Device(DEVICE_GPU).TypeConstraint<type>("T"), ArgOp);
TF_CALL_NUMBER_TYPES_NO_INT32(REGISTER)
TF_CALL_bool(REGISTER) REGISTER_KERNEL_BUILDER(Name("_Arg")
                                                   .Device(DEVICE_GPU)
                                                   .HostMemory("output")
                                                   .TypeConstraint<int32>("T"),
                                               ArgOp);
#undef REGISTER

REGISTER_KERNEL_BUILDER(Name("_Arg")
                            .Device(DEVICE_GPU)
                            .HostMemory("output")
                            .TypeConstraint<ResourceHandle>("T"),
                        ArgOp);

#define REGISTER(type)     \
  REGISTER_KERNEL_BUILDER( \
      Name("_Retval").Device(DEVICE_GPU).TypeConstraint<type>("T"), RetvalOp);
TF_CALL_NUMBER_TYPES_NO_INT32(REGISTER)
TF_CALL_bool(REGISTER) REGISTER_KERNEL_BUILDER(Name("_Retval")
                                                   .Device(DEVICE_GPU)
                                                   .HostMemory("input")
                                                   .TypeConstraint<int32>("T"),
                                               RetvalOp);
#undef REGISTER

class PassOn : public OpKernel {
 public:
  explicit PassOn(OpKernelConstruction* ctx) : OpKernel(ctx) {
    OP_REQUIRES(ctx, ctx->num_inputs() == ctx->num_outputs(),
                errors::Internal("#inputs != #outputs : ", ctx->num_inputs(),
                                 " vs. ", ctx->num_outputs()));
    for (int i = 0; i < ctx->num_inputs(); ++i) {
      OP_REQUIRES(
          ctx, input_type(i) == output_type(i),
          errors::Internal("Input and output types for position ", i,
                           " do not match: ", DataTypeString(input_type(i)),
                           " vs. ", DataTypeString(output_type(i))));
    }
  }

  void Compute(OpKernelContext* ctx) override {
    for (int i = 0; i < ctx->num_inputs(); ++i) {
      ctx->set_output(i, ctx->input(i));
    }
  }
};

REGISTER_KERNEL_BUILDER(Name("_ListToArray").Device(DEVICE_CPU), PassOn);
REGISTER_KERNEL_BUILDER(Name("_ArrayToList").Device(DEVICE_CPU), PassOn);

#define REGISTER_GPU_KERNELS(type)                                       \
  REGISTER_KERNEL_BUILDER(                                               \
      Name("_ListToArray").Device(DEVICE_GPU).TypeConstraint<type>("T"), \
      PassOn);                                                           \
  REGISTER_KERNEL_BUILDER(                                               \
      Name("_ArrayToList").Device(DEVICE_GPU).TypeConstraint<type>("T"), \
      PassOn);

REGISTER_GPU_KERNELS(Eigen::half);
REGISTER_GPU_KERNELS(float);
REGISTER_GPU_KERNELS(double);

#undef REGISTER_GPU_KERNELS

REGISTER_KERNEL_BUILDER(Name("_ListToArray")
                            .Device(DEVICE_GPU)
                            .HostMemory("input")
                            .HostMemory("output")
                            .TypeConstraint<int32>("T"),
                        PassOn);
REGISTER_KERNEL_BUILDER(Name("_ArrayToList")
                            .Device(DEVICE_GPU)
                            .HostMemory("input")
                            .HostMemory("output")
                            .TypeConstraint<int32>("T"),
                        PassOn);

#ifdef TENSORFLOW_USE_SYCL
#define REGISTER_SYCL_KERNELS(type)                                       \
  REGISTER_KERNEL_BUILDER(                                                \
      Name("_ListToArray").Device(DEVICE_SYCL).TypeConstraint<type>("T"), \
      PassOn);                                                            \
  REGISTER_KERNEL_BUILDER(                                                \
      Name("_ArrayToList").Device(DEVICE_SYCL).TypeConstraint<type>("T"), \
      PassOn);

REGISTER_SYCL_KERNELS(float);
REGISTER_SYCL_KERNELS(double);

#undef REGISTER_SYCL_KERNELS

REGISTER_KERNEL_BUILDER(Name("_ListToArray")
                            .Device(DEVICE_SYCL)
                            .HostMemory("input")
                            .HostMemory("output")
                            .TypeConstraint<int32>("T"),
                        PassOn);
REGISTER_KERNEL_BUILDER(Name("_ArrayToList")
                            .Device(DEVICE_SYCL)
                            .HostMemory("input")
                            .HostMemory("output")
                            .TypeConstraint<int32>("T"),
                        PassOn);
#endif  // TENSORFLOW_USE_SYCL

class SymbolicGradientOp : public AsyncOpKernel {
 public:
  explicit SymbolicGradientOp(OpKernelConstruction* ctx) : AsyncOpKernel(ctx) {}

  ~SymbolicGradientOp() override {}

  void ComputeAsync(OpKernelContext* ctx, DoneCallback done) override {
    FunctionLibraryRuntime* lib = ctx->function_library();
    OP_REQUIRES_ASYNC(ctx, lib != nullptr,
                      errors::Internal("No function library is provided."),
                      done);

    FunctionLibraryRuntime::Handle handle;
    OP_REQUIRES_OK_ASYNC(
        ctx, lib->Instantiate(kGradientOp, AttrSlice(def()), &handle), done);

    FunctionLibraryRuntime::Options opts;
    opts.step_id = ctx->step_id();
    opts.rendezvous = ctx->rendezvous();
    opts.cancellation_manager = ctx->cancellation_manager();
    opts.runner = ctx->runner();
    opts.stats_collector = ctx->stats_collector();
    opts.step_container = ctx->step_container();
    std::vector<Tensor> args;
    args.reserve(ctx->num_inputs());
    for (int i = 0; i < ctx->num_inputs(); ++i) {
      args.push_back(ctx->input(i));
    }
    std::vector<Tensor>* rets = new std::vector<Tensor>;
    lib->Run(
        opts, handle, args, rets, [ctx, done, rets](const Status& status) {
          if (!status.ok()) {
            ctx->SetStatus(status);
          } else if (rets->size() != ctx->num_outputs()) {
            ctx->SetStatus(errors::InvalidArgument(
                "SymGrad expects to return ", ctx->num_outputs(),
                " tensor(s), but get ", rets->size(), " tensor(s) instead."));
          } else {
            for (size_t i = 0; i < rets->size(); ++i) {
              ctx->set_output(i, (*rets)[i]);
            }
          }
          delete rets;
          done();
        });
  }

 private:
  TF_DISALLOW_COPY_AND_ASSIGN(SymbolicGradientOp);
};

REGISTER_KERNEL_BUILDER(Name(kGradientOp).Device(DEVICE_CPU),
                        SymbolicGradientOp);
REGISTER_KERNEL_BUILDER(Name(kGradientOp).Device(DEVICE_GPU),
                        SymbolicGradientOp);
#if TENSORFLOW_USE_SYCL
REGISTER_KERNEL_BUILDER(Name(kGradientOp).Device(DEVICE_SYCL),
                        SymbolicGradientOp);

#endif  // TENSORFLOW_USE_SYCL

class RemoteCallOp : public AsyncOpKernel {
 public:
  explicit RemoteCallOp(OpKernelConstruction* ctx) : AsyncOpKernel(ctx) {
    OP_REQUIRES_OK(ctx, ctx->GetAttr("f", &func_));
  }

  ~RemoteCallOp() override {}

  void ComputeAsync(OpKernelContext* ctx, DoneCallback done) override {
    const Tensor* target;
    OP_REQUIRES_OK_ASYNC(ctx, ctx->input("target", &target), done);
    AttrValueMap attr_values = func_.attr();
    AttrValue v;
    const string& target_device =
        DeviceNameUtils::CanonicalizeDeviceName(target->scalar<string>()());
    v.set_s(target_device);
    AddAttr("_target", v, &attr_values);

    FunctionLibraryRuntime* lib = ctx->function_library();
    OP_REQUIRES_ASYNC(ctx, lib != nullptr,
                      errors::Internal("No function library is provided."),
                      done);
    FunctionLibraryRuntime::Handle handle;
    OP_REQUIRES_OK_ASYNC(
        ctx, lib->Instantiate(func_.name(), AttrSlice(&attr_values), &handle),
        done);

    OpInputList arguments;
    OP_REQUIRES_OK_ASYNC(ctx, ctx->input_list("args", &arguments), done);

    FunctionLibraryRuntime::Options opts;
    opts.step_id = ctx->step_id();
    opts.runner = ctx->runner();
    opts.source_device = lib->device()->name();
    if (opts.source_device != target_device) {
      opts.remote_execution = true;
    }
    opts.rendezvous = ctx->rendezvous();
    std::vector<Tensor> args;
    args.reserve(arguments.size());
    for (const Tensor& argument : arguments) {
      args.push_back(argument);
    }
    auto* rets = new std::vector<Tensor>;
    lib->Run(opts, handle, args, rets, [rets, done, ctx](const Status& status) {
      if (!status.ok()) {
        ctx->SetStatus(status);
      } else {
        for (size_t i = 0; i < rets->size(); ++i) {
          ctx->set_output(i, (*rets)[i]);
        }
      }
      delete rets;
      done();
    });
  }

 private:
  string target_;
  NameAttrList func_;
  TF_DISALLOW_COPY_AND_ASSIGN(RemoteCallOp);
};

REGISTER_KERNEL_BUILDER(
    Name("RemoteCall").Device(DEVICE_CPU).HostMemory("target"), RemoteCallOp);
REGISTER_KERNEL_BUILDER(
    Name("RemoteCall").Device(DEVICE_GPU).HostMemory("target"), RemoteCallOp);
#if TENSORFLOW_USE_SYCL
REGISTER_KERNEL_BUILDER(
    Name("RemoteCall").Device(DEVICE_SYCL).HostMemory("target"), RemoteCallOp);

#endif  // TENSORFLOW_USE_SYCL
}  // namespace tensorflow
<commit_msg>Always create a Rendezvous in RemoteCallOp.<commit_after>/* Copyright 2016 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include <deque>
#include <vector>

#include "tensorflow/core/common_runtime/device.h"
#include "tensorflow/core/common_runtime/executor.h"
#include "tensorflow/core/common_runtime/function.h"
#include "tensorflow/core/common_runtime/memory_types.h"
#include "tensorflow/core/framework/function.h"
#include "tensorflow/core/framework/op.h"
#include "tensorflow/core/framework/op_kernel.h"
#include "tensorflow/core/framework/register_types.h"
#include "tensorflow/core/graph/algorithm.h"
#include "tensorflow/core/graph/gradients.h"
#include "tensorflow/core/graph/graph_constructor.h"
#include "tensorflow/core/platform/macros.h"
#include "tensorflow/core/util/device_name_utils.h"

namespace tensorflow {

static const char* const kGradientOp = "SymbolicGradient";

class ArgOp : public OpKernel {
 public:
  explicit ArgOp(OpKernelConstruction* ctx) : OpKernel(ctx) {
    OP_REQUIRES_OK(ctx, ctx->GetAttr("T", &dtype_));
    OP_REQUIRES_OK(ctx, ctx->GetAttr("index", &index_));
  }

  void Compute(OpKernelContext* ctx) override {
    auto frame = ctx->call_frame();
    OP_REQUIRES(ctx, frame != nullptr, errors::Internal("no call frame"));
    Tensor val;
    OP_REQUIRES_OK(ctx, frame->GetArg(index_, &val));
    OP_REQUIRES(ctx, val.dtype() == dtype_,
                errors::InvalidArgument(
                    "Type mismatch: actual ", DataTypeString(val.dtype()),
                    " vs. expect ", DataTypeString(dtype_)));
    ctx->set_output(0, val);
  }

 private:
  int index_;
  DataType dtype_;

  TF_DISALLOW_COPY_AND_ASSIGN(ArgOp);
};

class RetvalOp : public OpKernel {
 public:
  explicit RetvalOp(OpKernelConstruction* ctx) : OpKernel(ctx) {
    OP_REQUIRES_OK(ctx, ctx->GetAttr("T", &dtype_));
    OP_REQUIRES_OK(ctx, ctx->GetAttr("index", &index_));
  }

  void Compute(OpKernelContext* ctx) override {
    const Tensor& val = ctx->input(0);
    OP_REQUIRES(ctx, val.dtype() == dtype_,
                errors::InvalidArgument(
                    "Type mismatch: actual ", DataTypeString(val.dtype()),
                    " vs. expect ", DataTypeString(dtype_)));
    auto frame = ctx->call_frame();
    OP_REQUIRES(ctx, frame != nullptr, errors::Internal("no call frame"));
    OP_REQUIRES_OK(ctx, frame->SetRetval(index_, val));
  }

 private:
  int index_;
  DataType dtype_;

  TF_DISALLOW_COPY_AND_ASSIGN(RetvalOp);
};

REGISTER_SYSTEM_KERNEL_BUILDER(Name("_Arg").Device(DEVICE_CPU), ArgOp);
REGISTER_SYSTEM_KERNEL_BUILDER(Name("_Retval").Device(DEVICE_CPU), RetvalOp);

#if TENSORFLOW_USE_SYCL
#define REGISTER(type)     \
  REGISTER_KERNEL_BUILDER( \
      Name("_Arg").Device(DEVICE_SYCL).TypeConstraint<type>("T"), ArgOp);
TF_CALL_NUMBER_TYPES_NO_INT32(REGISTER)
TF_CALL_bool(REGISTER) REGISTER_KERNEL_BUILDER(Name("_Arg")
                                                   .Device(DEVICE_SYCL)
                                                   .HostMemory("output")
                                                   .TypeConstraint<int32>("T"),
                                               ArgOp);
#undef REGISTER
#define REGISTER(type)                                               \
  REGISTER_KERNEL_BUILDER(                                           \
      Name("_Retval").Device(DEVICE_SYCL).TypeConstraint<type>("T"), \
      RetvalOp);
TF_CALL_NUMBER_TYPES_NO_INT32(REGISTER)
TF_CALL_bool(REGISTER) REGISTER_KERNEL_BUILDER(Name("_Retval")
                                                   .Device(DEVICE_SYCL)
                                                   .HostMemory("input")
                                                   .TypeConstraint<int32>("T"),
                                               RetvalOp);
#undef REGISTER
#endif

#define REGISTER(type)     \
  REGISTER_KERNEL_BUILDER( \
      Name("_Arg").Device(DEVICE_GPU).TypeConstraint<type>("T"), ArgOp);
TF_CALL_NUMBER_TYPES_NO_INT32(REGISTER)
TF_CALL_bool(REGISTER) REGISTER_KERNEL_BUILDER(Name("_Arg")
                                                   .Device(DEVICE_GPU)
                                                   .HostMemory("output")
                                                   .TypeConstraint<int32>("T"),
                                               ArgOp);
#undef REGISTER

REGISTER_KERNEL_BUILDER(Name("_Arg")
                            .Device(DEVICE_GPU)
                            .HostMemory("output")
                            .TypeConstraint<ResourceHandle>("T"),
                        ArgOp);

#define REGISTER(type)     \
  REGISTER_KERNEL_BUILDER( \
      Name("_Retval").Device(DEVICE_GPU).TypeConstraint<type>("T"), RetvalOp);
TF_CALL_NUMBER_TYPES_NO_INT32(REGISTER)
TF_CALL_bool(REGISTER) REGISTER_KERNEL_BUILDER(Name("_Retval")
                                                   .Device(DEVICE_GPU)
                                                   .HostMemory("input")
                                                   .TypeConstraint<int32>("T"),
                                               RetvalOp);
#undef REGISTER

class PassOn : public OpKernel {
 public:
  explicit PassOn(OpKernelConstruction* ctx) : OpKernel(ctx) {
    OP_REQUIRES(ctx, ctx->num_inputs() == ctx->num_outputs(),
                errors::Internal("#inputs != #outputs : ", ctx->num_inputs(),
                                 " vs. ", ctx->num_outputs()));
    for (int i = 0; i < ctx->num_inputs(); ++i) {
      OP_REQUIRES(
          ctx, input_type(i) == output_type(i),
          errors::Internal("Input and output types for position ", i,
                           " do not match: ", DataTypeString(input_type(i)),
                           " vs. ", DataTypeString(output_type(i))));
    }
  }

  void Compute(OpKernelContext* ctx) override {
    for (int i = 0; i < ctx->num_inputs(); ++i) {
      ctx->set_output(i, ctx->input(i));
    }
  }
};

REGISTER_KERNEL_BUILDER(Name("_ListToArray").Device(DEVICE_CPU), PassOn);
REGISTER_KERNEL_BUILDER(Name("_ArrayToList").Device(DEVICE_CPU), PassOn);

#define REGISTER_GPU_KERNELS(type)                                       \
  REGISTER_KERNEL_BUILDER(                                               \
      Name("_ListToArray").Device(DEVICE_GPU).TypeConstraint<type>("T"), \
      PassOn);                                                           \
  REGISTER_KERNEL_BUILDER(                                               \
      Name("_ArrayToList").Device(DEVICE_GPU).TypeConstraint<type>("T"), \
      PassOn);

REGISTER_GPU_KERNELS(Eigen::half);
REGISTER_GPU_KERNELS(float);
REGISTER_GPU_KERNELS(double);

#undef REGISTER_GPU_KERNELS

REGISTER_KERNEL_BUILDER(Name("_ListToArray")
                            .Device(DEVICE_GPU)
                            .HostMemory("input")
                            .HostMemory("output")
                            .TypeConstraint<int32>("T"),
                        PassOn);
REGISTER_KERNEL_BUILDER(Name("_ArrayToList")
                            .Device(DEVICE_GPU)
                            .HostMemory("input")
                            .HostMemory("output")
                            .TypeConstraint<int32>("T"),
                        PassOn);

#ifdef TENSORFLOW_USE_SYCL
#define REGISTER_SYCL_KERNELS(type)                                       \
  REGISTER_KERNEL_BUILDER(                                                \
      Name("_ListToArray").Device(DEVICE_SYCL).TypeConstraint<type>("T"), \
      PassOn);                                                            \
  REGISTER_KERNEL_BUILDER(                                                \
      Name("_ArrayToList").Device(DEVICE_SYCL).TypeConstraint<type>("T"), \
      PassOn);

REGISTER_SYCL_KERNELS(float);
REGISTER_SYCL_KERNELS(double);

#undef REGISTER_SYCL_KERNELS

REGISTER_KERNEL_BUILDER(Name("_ListToArray")
                            .Device(DEVICE_SYCL)
                            .HostMemory("input")
                            .HostMemory("output")
                            .TypeConstraint<int32>("T"),
                        PassOn);
REGISTER_KERNEL_BUILDER(Name("_ArrayToList")
                            .Device(DEVICE_SYCL)
                            .HostMemory("input")
                            .HostMemory("output")
                            .TypeConstraint<int32>("T"),
                        PassOn);
#endif  // TENSORFLOW_USE_SYCL

class SymbolicGradientOp : public AsyncOpKernel {
 public:
  explicit SymbolicGradientOp(OpKernelConstruction* ctx) : AsyncOpKernel(ctx) {}

  ~SymbolicGradientOp() override {}

  void ComputeAsync(OpKernelContext* ctx, DoneCallback done) override {
    FunctionLibraryRuntime* lib = ctx->function_library();
    OP_REQUIRES_ASYNC(ctx, lib != nullptr,
                      errors::Internal("No function library is provided."),
                      done);

    FunctionLibraryRuntime::Handle handle;
    OP_REQUIRES_OK_ASYNC(
        ctx, lib->Instantiate(kGradientOp, AttrSlice(def()), &handle), done);

    FunctionLibraryRuntime::Options opts;
    opts.step_id = ctx->step_id();
    opts.rendezvous = ctx->rendezvous();
    opts.cancellation_manager = ctx->cancellation_manager();
    opts.runner = ctx->runner();
    opts.stats_collector = ctx->stats_collector();
    opts.step_container = ctx->step_container();
    std::vector<Tensor> args;
    args.reserve(ctx->num_inputs());
    for (int i = 0; i < ctx->num_inputs(); ++i) {
      args.push_back(ctx->input(i));
    }
    std::vector<Tensor>* rets = new std::vector<Tensor>;
    lib->Run(
        opts, handle, args, rets, [ctx, done, rets](const Status& status) {
          if (!status.ok()) {
            ctx->SetStatus(status);
          } else if (rets->size() != ctx->num_outputs()) {
            ctx->SetStatus(errors::InvalidArgument(
                "SymGrad expects to return ", ctx->num_outputs(),
                " tensor(s), but get ", rets->size(), " tensor(s) instead."));
          } else {
            for (size_t i = 0; i < rets->size(); ++i) {
              ctx->set_output(i, (*rets)[i]);
            }
          }
          delete rets;
          done();
        });
  }

 private:
  TF_DISALLOW_COPY_AND_ASSIGN(SymbolicGradientOp);
};

REGISTER_KERNEL_BUILDER(Name(kGradientOp).Device(DEVICE_CPU),
                        SymbolicGradientOp);
REGISTER_KERNEL_BUILDER(Name(kGradientOp).Device(DEVICE_GPU),
                        SymbolicGradientOp);
#if TENSORFLOW_USE_SYCL
REGISTER_KERNEL_BUILDER(Name(kGradientOp).Device(DEVICE_SYCL),
                        SymbolicGradientOp);

#endif  // TENSORFLOW_USE_SYCL

class RemoteCallOp : public AsyncOpKernel {
 public:
  explicit RemoteCallOp(OpKernelConstruction* ctx) : AsyncOpKernel(ctx) {
    OP_REQUIRES_OK(ctx, ctx->GetAttr("f", &func_));
  }

  ~RemoteCallOp() override {}

  void ComputeAsync(OpKernelContext* ctx, DoneCallback done) override {
    const Tensor* target;
    OP_REQUIRES_OK_ASYNC(ctx, ctx->input("target", &target), done);
    AttrValueMap attr_values = func_.attr();
    AttrValue v;
    const string& target_device =
        DeviceNameUtils::CanonicalizeDeviceName(target->scalar<string>()());
    v.set_s(target_device);
    AddAttr("_target", v, &attr_values);

    FunctionLibraryRuntime* lib = ctx->function_library();
    OP_REQUIRES_ASYNC(ctx, lib != nullptr,
                      errors::Internal("No function library is provided."),
                      done);
    FunctionLibraryRuntime::Handle handle;
    OP_REQUIRES_OK_ASYNC(
        ctx, lib->Instantiate(func_.name(), AttrSlice(&attr_values), &handle),
        done);

    OpInputList arguments;
    OP_REQUIRES_OK_ASYNC(ctx, ctx->input_list("args", &arguments), done);

    FunctionLibraryRuntime::Options opts;
    opts.step_id = ctx->step_id();
    opts.runner = ctx->runner();
    opts.source_device = lib->device()->name();
    if (opts.source_device != target_device) {
      opts.remote_execution = true;
    }
    opts.create_rendezvous = true;
    std::vector<Tensor> args;
    args.reserve(arguments.size());
    for (const Tensor& argument : arguments) {
      args.push_back(argument);
    }
    auto* rets = new std::vector<Tensor>;
    lib->Run(opts, handle, args, rets, [rets, done, ctx](const Status& status) {
      if (!status.ok()) {
        ctx->SetStatus(status);
      } else {
        for (size_t i = 0; i < rets->size(); ++i) {
          ctx->set_output(i, (*rets)[i]);
        }
      }
      delete rets;
      done();
    });
  }

 private:
  string target_;
  NameAttrList func_;
  TF_DISALLOW_COPY_AND_ASSIGN(RemoteCallOp);
};

REGISTER_KERNEL_BUILDER(
    Name("RemoteCall").Device(DEVICE_CPU).HostMemory("target"), RemoteCallOp);
REGISTER_KERNEL_BUILDER(
    Name("RemoteCall").Device(DEVICE_GPU).HostMemory("target"), RemoteCallOp);
#if TENSORFLOW_USE_SYCL
REGISTER_KERNEL_BUILDER(
    Name("RemoteCall").Device(DEVICE_SYCL).HostMemory("target"), RemoteCallOp);

#endif  // TENSORFLOW_USE_SYCL
}  // namespace tensorflow
<|endoftext|>


<commit_before>/**
 * \file
 * \brief Scheduler class header
 *
 * \author Copyright (C) 2014-2015 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * \date 2015-02-16
 */

#ifndef INCLUDE_DISTORTOS_SCHEDULER_SCHEDULER_HPP_
#define INCLUDE_DISTORTOS_SCHEDULER_SCHEDULER_HPP_

#include "distortos/scheduler/ThreadControlBlockList.hpp"
#include "distortos/scheduler/SoftwareTimerControlBlockSupervisor.hpp"

namespace distortos
{

/// scheduler namespace has symbols related to scheduling
namespace scheduler
{

class MainThread;

/// Scheduler class is a system's scheduler
class Scheduler
{
public:

	/**
	 * \brief Scheduler's constructor
	 */

	Scheduler();

	/**
	 * \brief Adds new ThreadControlBlock to scheduler.
	 *
	 * ThreadControlBlock's state is changed to "runnable".
	 *
	 * \param [in] threadControlBlock is a reference to added ThreadControlBlock object
	 */

	void add(ThreadControlBlock& threadControlBlock);

	/**
	 * \brief Blocks current thread, transferring it to provided container.
	 *
	 * \param [in] container is a reference to destination container to which the thread will be transferred
	 * \param [in] unblockFunctor is a pointer to ThreadControlBlock::UnblockFunctor which will be executed in
	 * ThreadControlBlock::unblockHook(), default - nullptr (no functor will be executed)
	 *
	 * \return 0 on success, error code otherwise:
	 * - ETIMEDOUT - thread was unblocked with ThreadControlBlock::UnblockReason::Timeout;
	 */

	int block(ThreadControlBlockList& container, const ThreadControlBlock::UnblockFunctor* unblockFunctor = {});

	/**
	 * \brief Blocks thread, transferring it to provided container.
	 *
	 * The thread must be on "runnable" list - trying to block thread in other state is an error.
	 *
	 * \param [in] container is a reference to destination container to which the thread will be transferred
	 * \param [in] iterator is the iterator to the thread that will be blocked
	 * \param [in] unblockFunctor is a pointer to ThreadControlBlock::UnblockFunctor which will be executed in
	 * ThreadControlBlock::unblockHook(), default - nullptr (no functor will be executed)
	 *
	 * \return 0 on success, error code otherwise:
	 * - EINVAL - provided thread is not on "runnable" list;
	 * - ETIMEDOUT - thread was unblocked with ThreadControlBlock::UnblockReason::Timeout (possible only when blocking
	 * current thread);
	 */

	int block(ThreadControlBlockList& container, ThreadControlBlockListIterator iterator,
			const ThreadControlBlock::UnblockFunctor* unblockFunctor = {});

	/**
	 * \brief Blocks current thread with timeout, transferring it to provided container.
	 *
	 * \param [in] container is a reference to destination container to which the thread will be transferred
	 * \param [in] timePoint is the time point at which the thread will be unblocked (if not already unblocked)
	 * \param [in] unblockFunctor is a pointer to ThreadControlBlock::UnblockFunctor which will be executed in
	 * ThreadControlBlock::unblockHook(), default - nullptr (no functor will be executed)
	 *
	 * \return 0 on success, error code otherwise:
	 * - ETIMEDOUT - thread was unblocked because timePoint was reached;
	 */

	int blockUntil(ThreadControlBlockList& container, TickClock::time_point timePoint,
			const ThreadControlBlock::UnblockFunctor* unblockFunctor = {});

	/**
	 * \return number of context switches
	 */

	uint64_t getContextSwitchCount() const;

	/**
	 * \return reference to currently active ThreadBase
	 */

	ThreadBase& getCurrentThreadBase() const
	{
		return getCurrentThreadControlBlock().getOwner();
	}

	/**
	 * \return reference to currently active ThreadControlBlock
	 */

	ThreadControlBlock& getCurrentThreadControlBlock() const
	{
		return *currentThreadControlBlock_;
	}

	/**
	 * \return reference to internal MutexControlBlockListAllocator::Pool object
	 */

	MutexControlBlockListAllocator::Pool& getMutexControlBlockListAllocatorPool()
	{
		return mutexControlBlockListAllocatorPool_;
	}

	/**
	 * \return const reference to internal MutexControlBlockListAllocator:Pool object
	 */

	const MutexControlBlockListAllocator::Pool& getMutexControlBlockListAllocatorPool() const
	{
		return mutexControlBlockListAllocatorPool_;
	}

	/**
	 * \return reference to internal SoftwareTimerControlBlockSupervisor object
	 */

	SoftwareTimerControlBlockSupervisor& getSoftwareTimerSupervisor()
	{
		return softwareTimerControlBlockSupervisor_;
	}

	/**
	 * \return const reference to internal SoftwareTimerControlBlockSupervisor object
	 */

	const SoftwareTimerControlBlockSupervisor& getSoftwareTimerSupervisor() const
	{
		return softwareTimerControlBlockSupervisor_;
	}

	/**
	 * \return const reference to internal ThreadControlBlockListAllocator object
	 */

	const ThreadControlBlockListAllocator& getThreadControlBlockListAllocator() const
	{
		return threadControlBlockListAllocator_;
	}

	/**
	 * \return current value of tick count
	 */

	uint64_t getTickCount() const;

	/**
	 * \brief Scheduler's initialization
	 *
	 * \attention This must be called after constructor, before enabling any scheduling. Priority of main thread must
	 * be higher than priority of idle thread
	 *
	 * \param [in] mainThread is a reference to main thread
	 */

	void initialize(MainThread& mainThread);

	/**
	 * \brief Requests context switch if it is needed.
	 *
	 * \attention This function must be called with interrupt masking enabled.
	 */

	void maybeRequestContextSwitch() const;

	/**
	 * \brief Removes current thread from Scheduler's control.
	 *
	 * Thread's state is changed to "terminated" and it's terminationHook() is called.
	 *
	 * \note This function can be used only after thread's function returns an all cleanup is done.
	 *
	 * \param [in] terminationHook is a pointer to member function of ThreadBase that will be called from within lock
	 * zone just before forced context switch
	 *
	 * \return 0 on success, error code otherwise:
	 * - EINVAL - provided thread is not on "runnable" list and cannot be removed/terminated;
	 */

	int remove(void (ThreadBase::*terminationHook)());

	/**
	 * \brief Resumes suspended thread.
	 *
	 * The thread must be on the "suspended" list - trying to resume thread that is not suspended is an error.
	 *
	 * \param [in] iterator is the iterator to the thread that will be resumed
	 *
	 * \return 0 on success, error code otherwise:
	 * - EINVAL - provided thread is not on "suspended" list;
	 */

	int resume(ThreadControlBlockListIterator iterator);

	/**
	 * \brief Suspends current thread.
	 *
	 * \return 0 on success, error code otherwise
	 */

	int suspend();

	/**
	 * \brief Suspends thread.
	 *
	 * The thread must be on "runnable" list - trying to suspend thread in other state is an error.
	 *
	 * \param [in] iterator is the iterator to the thread that will be suspended
	 *
	 * \return 0 on success, error code otherwise:
	 * - EINVAL - provided thread is not on "runnable" list;
	 */

	int suspend(ThreadControlBlockListIterator iterator);

	/**
	 * \brief Called by architecture-specific code to do final context switch.
	 *
	 * Current task is suspended and the next available task is started.
	 *
	 * \param [in] stackPointer is the current value of current thread's stack pointer
	 *
	 * \return new thread's stack pointer
	 */

	void* switchContext(void* stackPointer);

	/**
	 * \brief Handler of "tick" interrupt.
	 *
	 * \note this must not be called by user code
	 *
	 * \return true if context switch is required, false otherwise
	 */

	bool tickInterruptHandler();

	/**
	 * \brief Unblocks provided thread, transferring it from it's current container to "runnable" container.
	 *
	 * Current container of the thread is obtained with ThreadControlBlock::getList().
	 *
	 * \param [in] iterator is the iterator which points to unblocked thread
	 */

	void unblock(ThreadControlBlockListIterator iterator);

	/**
	 * \brief Yields time slot of the scheduler to next thread.
	 */

	void yield();

private:

	/**
	 * \brief Adds new ThreadControlBlock to scheduler.
	 *
	 * Internal version - without interrupt masking and call to Scheduler::maybeRequestContextSwitch()
	 *
	 * \param [in] threadControlBlock is a reference to added ThreadControlBlock object
	 */

	void addInternal(ThreadControlBlock& threadControlBlock);

	/**
	 * \brief Blocks thread, transferring it to provided container.
	 *
	 * Internal version - without interrupt masking and forced context switch.
	 *
	 * \param [in] container is a reference to destination container to which the thread will be transferred
	 * \param [in] iterator is the iterator to the thread that will be blocked
	 * \param [in] unblockFunctor is a pointer to ThreadControlBlock::UnblockFunctor which will be executed in
	 * ThreadControlBlock::unblockHook()
	 *
	 * \return 0 on success, error code otherwise:
	 * - EINVAL - provided thread is not on "runnable" list;
	 */

	int blockInternal(ThreadControlBlockList& container, ThreadControlBlockListIterator iterator,
			const ThreadControlBlock::UnblockFunctor* unblockFunctor);

	/**
	 * \brief Tests whether context switch is required or not.
	 *
	 * Context switch is required in following situations:
	 * - current thread is no longer on "runnable" list,
	 * - current thread is no longer on the beginning of the "runnable" list (because higher-priority thread is
	 * available or current thread was "rotated" due to round-robin scheduling policy).
	 *
	 * \return true if context switch is required
	 */

	bool isContextSwitchRequired() const;

	/**
	 * \brief Unblocks provided thread, transferring it from it's current container to "runnable" container.
	 *
	 * Current container of the thread is obtained with ThreadControlBlock::getList(). Round-robin quantum of thread is
	 * reset.
	 *
	 * \note Internal version - without interrupt masking and yield()
	 *
	 * \param [in] iterator is the iterator which points to unblocked thread
	 * \param [in] unblockReason is the reason of unblocking of the thread, default -
	 * ThreadControlBlock::UnblockReason::UnblockRequest
	 */

	void unblockInternal(ThreadControlBlockListIterator iterator,
			ThreadControlBlock::UnblockReason unblockReason = ThreadControlBlock::UnblockReason::UnblockRequest);

	/// iterator to the currently active ThreadControlBlock
	ThreadControlBlockListIterator currentThreadControlBlock_;

	/// pool instance used by MutexControlBlockListAllocator
	MutexControlBlockListAllocator::Pool mutexControlBlockListAllocatorPool_;

	/// pool instance used by threadControlBlockListAllocator_
	ThreadControlBlockListAllocator::Pool threadControlBlockListAllocatorPool_;

	/// PoolAllocator<> of ThreadControlBlockList
	ThreadControlBlockListAllocator threadControlBlockListAllocator_;

	/// list of ThreadControlBlock elements in "runnable" state, sorted by priority in descending order
	ThreadControlBlockList runnableList_;

	/// list of ThreadControlBlock elements in "suspended" state, sorted by priority in descending order
	ThreadControlBlockList suspendedList_;

	/// internal SoftwareTimerControlBlockSupervisor object
	SoftwareTimerControlBlockSupervisor softwareTimerControlBlockSupervisor_;

	/// number of context switches
	uint64_t contextSwitchCount_;

	/// tick count
	uint64_t tickCount_;
};

}	// namespace scheduler

}	// namespace distortos

#endif	// INCLUDE_DISTORTOS_SCHEDULER_SCHEDULER_HPP_
<commit_msg>Scheduler: remove Scheduler::getCurrentThreadBase()<commit_after>/**
 * \file
 * \brief Scheduler class header
 *
 * \author Copyright (C) 2014-2015 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * \date 2015-03-03
 */

#ifndef INCLUDE_DISTORTOS_SCHEDULER_SCHEDULER_HPP_
#define INCLUDE_DISTORTOS_SCHEDULER_SCHEDULER_HPP_

#include "distortos/scheduler/ThreadControlBlockList.hpp"
#include "distortos/scheduler/SoftwareTimerControlBlockSupervisor.hpp"

namespace distortos
{

/// scheduler namespace has symbols related to scheduling
namespace scheduler
{

class MainThread;

/// Scheduler class is a system's scheduler
class Scheduler
{
public:

	/**
	 * \brief Scheduler's constructor
	 */

	Scheduler();

	/**
	 * \brief Adds new ThreadControlBlock to scheduler.
	 *
	 * ThreadControlBlock's state is changed to "runnable".
	 *
	 * \param [in] threadControlBlock is a reference to added ThreadControlBlock object
	 */

	void add(ThreadControlBlock& threadControlBlock);

	/**
	 * \brief Blocks current thread, transferring it to provided container.
	 *
	 * \param [in] container is a reference to destination container to which the thread will be transferred
	 * \param [in] unblockFunctor is a pointer to ThreadControlBlock::UnblockFunctor which will be executed in
	 * ThreadControlBlock::unblockHook(), default - nullptr (no functor will be executed)
	 *
	 * \return 0 on success, error code otherwise:
	 * - ETIMEDOUT - thread was unblocked with ThreadControlBlock::UnblockReason::Timeout;
	 */

	int block(ThreadControlBlockList& container, const ThreadControlBlock::UnblockFunctor* unblockFunctor = {});

	/**
	 * \brief Blocks thread, transferring it to provided container.
	 *
	 * The thread must be on "runnable" list - trying to block thread in other state is an error.
	 *
	 * \param [in] container is a reference to destination container to which the thread will be transferred
	 * \param [in] iterator is the iterator to the thread that will be blocked
	 * \param [in] unblockFunctor is a pointer to ThreadControlBlock::UnblockFunctor which will be executed in
	 * ThreadControlBlock::unblockHook(), default - nullptr (no functor will be executed)
	 *
	 * \return 0 on success, error code otherwise:
	 * - EINVAL - provided thread is not on "runnable" list;
	 * - ETIMEDOUT - thread was unblocked with ThreadControlBlock::UnblockReason::Timeout (possible only when blocking
	 * current thread);
	 */

	int block(ThreadControlBlockList& container, ThreadControlBlockListIterator iterator,
			const ThreadControlBlock::UnblockFunctor* unblockFunctor = {});

	/**
	 * \brief Blocks current thread with timeout, transferring it to provided container.
	 *
	 * \param [in] container is a reference to destination container to which the thread will be transferred
	 * \param [in] timePoint is the time point at which the thread will be unblocked (if not already unblocked)
	 * \param [in] unblockFunctor is a pointer to ThreadControlBlock::UnblockFunctor which will be executed in
	 * ThreadControlBlock::unblockHook(), default - nullptr (no functor will be executed)
	 *
	 * \return 0 on success, error code otherwise:
	 * - ETIMEDOUT - thread was unblocked because timePoint was reached;
	 */

	int blockUntil(ThreadControlBlockList& container, TickClock::time_point timePoint,
			const ThreadControlBlock::UnblockFunctor* unblockFunctor = {});

	/**
	 * \return number of context switches
	 */

	uint64_t getContextSwitchCount() const;

	/**
	 * \return reference to currently active ThreadControlBlock
	 */

	ThreadControlBlock& getCurrentThreadControlBlock() const
	{
		return *currentThreadControlBlock_;
	}

	/**
	 * \return reference to internal MutexControlBlockListAllocator::Pool object
	 */

	MutexControlBlockListAllocator::Pool& getMutexControlBlockListAllocatorPool()
	{
		return mutexControlBlockListAllocatorPool_;
	}

	/**
	 * \return const reference to internal MutexControlBlockListAllocator:Pool object
	 */

	const MutexControlBlockListAllocator::Pool& getMutexControlBlockListAllocatorPool() const
	{
		return mutexControlBlockListAllocatorPool_;
	}

	/**
	 * \return reference to internal SoftwareTimerControlBlockSupervisor object
	 */

	SoftwareTimerControlBlockSupervisor& getSoftwareTimerSupervisor()
	{
		return softwareTimerControlBlockSupervisor_;
	}

	/**
	 * \return const reference to internal SoftwareTimerControlBlockSupervisor object
	 */

	const SoftwareTimerControlBlockSupervisor& getSoftwareTimerSupervisor() const
	{
		return softwareTimerControlBlockSupervisor_;
	}

	/**
	 * \return const reference to internal ThreadControlBlockListAllocator object
	 */

	const ThreadControlBlockListAllocator& getThreadControlBlockListAllocator() const
	{
		return threadControlBlockListAllocator_;
	}

	/**
	 * \return current value of tick count
	 */

	uint64_t getTickCount() const;

	/**
	 * \brief Scheduler's initialization
	 *
	 * \attention This must be called after constructor, before enabling any scheduling. Priority of main thread must
	 * be higher than priority of idle thread
	 *
	 * \param [in] mainThread is a reference to main thread
	 */

	void initialize(MainThread& mainThread);

	/**
	 * \brief Requests context switch if it is needed.
	 *
	 * \attention This function must be called with interrupt masking enabled.
	 */

	void maybeRequestContextSwitch() const;

	/**
	 * \brief Removes current thread from Scheduler's control.
	 *
	 * Thread's state is changed to "terminated" and it's terminationHook() is called.
	 *
	 * \note This function can be used only after thread's function returns an all cleanup is done.
	 *
	 * \param [in] terminationHook is a pointer to member function of ThreadBase that will be called from within lock
	 * zone just before forced context switch
	 *
	 * \return 0 on success, error code otherwise:
	 * - EINVAL - provided thread is not on "runnable" list and cannot be removed/terminated;
	 */

	int remove(void (ThreadBase::*terminationHook)());

	/**
	 * \brief Resumes suspended thread.
	 *
	 * The thread must be on the "suspended" list - trying to resume thread that is not suspended is an error.
	 *
	 * \param [in] iterator is the iterator to the thread that will be resumed
	 *
	 * \return 0 on success, error code otherwise:
	 * - EINVAL - provided thread is not on "suspended" list;
	 */

	int resume(ThreadControlBlockListIterator iterator);

	/**
	 * \brief Suspends current thread.
	 *
	 * \return 0 on success, error code otherwise
	 */

	int suspend();

	/**
	 * \brief Suspends thread.
	 *
	 * The thread must be on "runnable" list - trying to suspend thread in other state is an error.
	 *
	 * \param [in] iterator is the iterator to the thread that will be suspended
	 *
	 * \return 0 on success, error code otherwise:
	 * - EINVAL - provided thread is not on "runnable" list;
	 */

	int suspend(ThreadControlBlockListIterator iterator);

	/**
	 * \brief Called by architecture-specific code to do final context switch.
	 *
	 * Current task is suspended and the next available task is started.
	 *
	 * \param [in] stackPointer is the current value of current thread's stack pointer
	 *
	 * \return new thread's stack pointer
	 */

	void* switchContext(void* stackPointer);

	/**
	 * \brief Handler of "tick" interrupt.
	 *
	 * \note this must not be called by user code
	 *
	 * \return true if context switch is required, false otherwise
	 */

	bool tickInterruptHandler();

	/**
	 * \brief Unblocks provided thread, transferring it from it's current container to "runnable" container.
	 *
	 * Current container of the thread is obtained with ThreadControlBlock::getList().
	 *
	 * \param [in] iterator is the iterator which points to unblocked thread
	 */

	void unblock(ThreadControlBlockListIterator iterator);

	/**
	 * \brief Yields time slot of the scheduler to next thread.
	 */

	void yield();

private:

	/**
	 * \brief Adds new ThreadControlBlock to scheduler.
	 *
	 * Internal version - without interrupt masking and call to Scheduler::maybeRequestContextSwitch()
	 *
	 * \param [in] threadControlBlock is a reference to added ThreadControlBlock object
	 */

	void addInternal(ThreadControlBlock& threadControlBlock);

	/**
	 * \brief Blocks thread, transferring it to provided container.
	 *
	 * Internal version - without interrupt masking and forced context switch.
	 *
	 * \param [in] container is a reference to destination container to which the thread will be transferred
	 * \param [in] iterator is the iterator to the thread that will be blocked
	 * \param [in] unblockFunctor is a pointer to ThreadControlBlock::UnblockFunctor which will be executed in
	 * ThreadControlBlock::unblockHook()
	 *
	 * \return 0 on success, error code otherwise:
	 * - EINVAL - provided thread is not on "runnable" list;
	 */

	int blockInternal(ThreadControlBlockList& container, ThreadControlBlockListIterator iterator,
			const ThreadControlBlock::UnblockFunctor* unblockFunctor);

	/**
	 * \brief Tests whether context switch is required or not.
	 *
	 * Context switch is required in following situations:
	 * - current thread is no longer on "runnable" list,
	 * - current thread is no longer on the beginning of the "runnable" list (because higher-priority thread is
	 * available or current thread was "rotated" due to round-robin scheduling policy).
	 *
	 * \return true if context switch is required
	 */

	bool isContextSwitchRequired() const;

	/**
	 * \brief Unblocks provided thread, transferring it from it's current container to "runnable" container.
	 *
	 * Current container of the thread is obtained with ThreadControlBlock::getList(). Round-robin quantum of thread is
	 * reset.
	 *
	 * \note Internal version - without interrupt masking and yield()
	 *
	 * \param [in] iterator is the iterator which points to unblocked thread
	 * \param [in] unblockReason is the reason of unblocking of the thread, default -
	 * ThreadControlBlock::UnblockReason::UnblockRequest
	 */

	void unblockInternal(ThreadControlBlockListIterator iterator,
			ThreadControlBlock::UnblockReason unblockReason = ThreadControlBlock::UnblockReason::UnblockRequest);

	/// iterator to the currently active ThreadControlBlock
	ThreadControlBlockListIterator currentThreadControlBlock_;

	/// pool instance used by MutexControlBlockListAllocator
	MutexControlBlockListAllocator::Pool mutexControlBlockListAllocatorPool_;

	/// pool instance used by threadControlBlockListAllocator_
	ThreadControlBlockListAllocator::Pool threadControlBlockListAllocatorPool_;

	/// PoolAllocator<> of ThreadControlBlockList
	ThreadControlBlockListAllocator threadControlBlockListAllocator_;

	/// list of ThreadControlBlock elements in "runnable" state, sorted by priority in descending order
	ThreadControlBlockList runnableList_;

	/// list of ThreadControlBlock elements in "suspended" state, sorted by priority in descending order
	ThreadControlBlockList suspendedList_;

	/// internal SoftwareTimerControlBlockSupervisor object
	SoftwareTimerControlBlockSupervisor softwareTimerControlBlockSupervisor_;

	/// number of context switches
	uint64_t contextSwitchCount_;

	/// tick count
	uint64_t tickCount_;
};

}	// namespace scheduler

}	// namespace distortos

#endif	// INCLUDE_DISTORTOS_SCHEDULER_SCHEDULER_HPP_
<|endoftext|>


<commit_before>#include "maze.h"
#include "proceduralmaze.h"

#include <cstdio>
#include <string>
#include <sstream>
#include <cstdlib>
#include <ctime>
#include <cmath>
#include <iostream>

#include "../util/bitmap.h"
#include "../util/log.h"

Maze::Maze(int width, int height, float size) : size(size)
{
	this->height = height % 2 == 0 ? height + 1 : height;
	this->width = width % 2 == 0 ? width + 1 : width;
	ProceduralMaze* procedural_maze = new ProceduralMaze(this->width, this->height);
	procedural_maze->generate();

	std::map<std::tuple<int, int>, Tile> grid = procedural_maze->getGrid();
	this->tiles = new Tile[this->height * this->width];
	for (int x = 0; x < this->width; ++x) {
		for (int y = 0; y < this->height; ++y) {
			std::tuple<int, int> pos = std::make_tuple(x, y);
			this->tiles[x + this->width*y] = grid[pos];
		}
	}
}

Maze::Maze(const char* bmp, float size) : size(size)
{
	std::string str(path);
	str += bmp;

	RGB* image;
	UINT32 w, h;
	FILE* f = fopen(str.c_str(), "rb");

	if (!f) {
		throw std::runtime_error("File " + str + " does not exist");
	}

	if (readSingleImageBMP(f, &image, &w, &h)) {
		return;
	}

	width = static_cast<int>(w);
	height = static_cast<int>(h);
	tiles = new Tile[width * height];
	for (int i = 0; i < width * height; i++) {
		bool r = image[i].red && 0xFF;
		bool g = image[i].green && 0xFF;
		bool b = image[i].blue && 0xFF;

		if (!(r || g || b)) {
			tiles[i] = Tile::WALL;
			walls.push_back(glm::vec3(x(i), 0, y(i)));
		} else if (r && g && b) {
			tiles[i] = Tile::EMPTY;
		} else if (!r && !g && b) {
			tiles[i] = Tile::ENTRY;
			entry = glm::vec3(x(i), 0, y(i));
		} else if (r && !g && !b) {
			tiles[i] = Tile::EXIT;
			exit = glm::vec3(x(i), 0, y(i));
		}
	}
	fclose(f);
}

void Maze::init(Program* program)
{
	wall = new Cube(program, "resources/wall_brick.jpg");
	floor = new Cube(program, "resources/floor_brick.jpg");
}

Maze::~Maze()
{
}

void Maze::draw(Program* program)
{
	wall->bind(program);
	for (const glm::vec3 pos : walls) {
		glm::mat4 transform;
		transform = glm::scale(transform, size * glm::vec3(0.9999f, 0.9999f, 0.9999f));
		transform = glm::translate(transform, size * glm::vec3(pos));
		program->setMat4(transform, "transform");
		wall->draw();
	}
	floor->bind(program);
	for (int i = 0; i < width * height; i++)
	{
		glm::mat4 transform;
		transform = glm::scale(transform, size * glm::vec3(0.9999f, 0.9999f, 0.9999f));
		transform = glm::translate(transform, size * glm::vec3(x(i), -1.0f, y(i)));
		program->setMat4(transform, "transform");
		floor->draw();
	}

}

Tile* Maze::copyBoard()
{
	Tile* cpy = new Tile[width * height];
	std::memcpy(cpy, tiles, sizeof(Tile) * width * height);
	return cpy;
}

glm::vec3 Maze::getEntryPosition()
{
	return entry + glm::vec3(size / 2, PLAYER_HEIGHT, size / 2);
}

inline float max(float x, float y)
{
	return x > y ? x : y;
}

bool Maze::checkCollision(glm::vec3 current, glm::vec3& position)
{
	int cur_x = static_cast<int>(floorf(current.x / size));
	int cur_z = static_cast<int>(floorf(current.z / size));

	int pos_x = cur_x, pos_z = cur_z;

	glm::vec3 direction = position - current;

	Direction dir_x = Direction::UNKNOWN, dir_z = Direction::UNKNOWN;

	if (direction.x > 0) {
		dir_x = Direction::EAST;
		pos_x = static_cast<int>(floorf((position.x + PLAYER_OFFSET) / size));
	}
	if (direction.x < 0) {
		dir_x = Direction::WEST;
		pos_x = static_cast<int>(floorf((position.x - PLAYER_OFFSET) / size));
	}
	if (direction.z > 0) {
		dir_z = Direction::NORTH;
		pos_z = static_cast<int>(floorf((position.z + PLAYER_OFFSET) / size));
	}
	if (direction.z < 0) {
		dir_z = Direction::SOUTH;
		pos_z = static_cast<int>(floorf((position.z - PLAYER_OFFSET) / size));
	}

	if (dir_x == Direction::UNKNOWN && dir_z == Direction::UNKNOWN) {
		return false;
	}

	bool collide = false;

	float x1 = size, z1 = size;
	float x2 = size, z2 = size;

	if (dir_x == Direction::EAST && pos_x - cur_x > 0 && tiles[i(cur_x + 1, cur_z)]) {
		x1 = ((cur_x + 1) * size - PLAYER_OFFSET) - current.x;

		if (x1 * x1 < MIN_RESPONSE && direction.x * direction.x < MIN_COLLISION)
			z1 = direction.z * RESPONSE;
		else
			z1 = (x1 * (position.z - current.z)) / max(position.x - current.x, MIN_DST);
		collide = true;
	}
	else if (dir_x == Direction::WEST && pos_x - cur_x < 0 && tiles[i(cur_x - 1, cur_z)]) {
		x1 = ((cur_x)* size + PLAYER_OFFSET) - current.x;

		if (x1 * x1 < MIN_RESPONSE && direction.x * direction.x < MIN_COLLISION)
			z1 = direction.z * RESPONSE;
		else
			z1 = (x1 * (position.z - current.z)) / max(position.x - current.x, MIN_DST);
		collide = true;
	}

	if (dir_z == Direction::NORTH && pos_z - cur_z > 0 && tiles[i(cur_x, cur_z + 1)]) {
		z2 = ((cur_z + 1) * size - PLAYER_OFFSET) - current.z;

		if (z2 * z2 < MIN_RESPONSE && direction.z * direction.z < MIN_COLLISION * 0.75)
			x2 = direction.x * RESPONSE;
		else
			x2 = (z2 * (position.x - current.x)) / max(position.z - current.z, MIN_DST);
		collide = true;
	}
	else if (dir_z == Direction::SOUTH && pos_z - cur_z < 0 && tiles[i(cur_x, cur_z - 1)]) {
		z2 = ((cur_z)* size + PLAYER_OFFSET) - current.z;

		if (z2 * z2 < MIN_RESPONSE && direction.z * direction.z < MIN_COLLISION)
			x2 = direction.x * RESPONSE;
		else
			x2 = (z2 * (position.x - current.x)) / max(position.z - current.z, MIN_DST);
		collide = true;
	}

	if (!collide) {
		return collide;
	}

	if (x1 * x1 + z1 * z1 < x2 * x2 + z2 * z2) {
		position = current + glm::vec3(x1, 0, z1);
	}
	else {
		position = current + glm::vec3(x2, 0, z2);
	}

	return collide;
}
<commit_msg>Code readability changes<commit_after>#include "maze.h"
#include "proceduralmaze.h"

#include <cstdio>
#include <string>
#include <sstream>
#include <cstdlib>
#include <ctime>
#include <cmath>
#include <iostream>

#include "../util/bitmap.h"
#include "../util/log.h"

Maze::Maze(int width, int height, float size) : size(size)
{
	this->height = height % 2 == 0 ? height + 1 : height;
	this->width = width % 2 == 0 ? width + 1 : width;
	ProceduralMaze* procedural_maze = new ProceduralMaze(this->width, this->height);
	procedural_maze->generate();

	std::map<std::tuple<int, int>, Tile> grid = procedural_maze->getGrid();
	this->tiles = new Tile[this->height * this->width];
	for (int x = 0; x < this->width; ++x) {
		for (int y = 0; y < this->height; ++y) {
			std::tuple<int, int> pos = std::make_tuple(x, y);
			this->tiles[x + this->width*y] = grid[pos];
		}
	}
}

Maze::Maze(const char* bmp, float size) : size(size)
{
	std::string str(path);
	str += bmp;

	RGB* image;
	UINT32 w, h;
	FILE* f = fopen(str.c_str(), "rb");

	if (!f) {
		throw std::runtime_error("File " + str + " does not exist");
	}

	if (readSingleImageBMP(f, &image, &w, &h)) {
		return;
	}

	width = static_cast<int>(w);
	height = static_cast<int>(h);
	tiles = new Tile[width * height];
	for (int i = 0; i < width * height; i++) {
		bool r = image[i].red && 0xFF;
		bool g = image[i].green && 0xFF;
		bool b = image[i].blue && 0xFF;

		if (!(r || g || b)) {
			tiles[i] = Tile::WALL;
			walls.push_back(glm::vec3(x(i), 0, y(i)));
		} else if (r && g && b) {
			tiles[i] = Tile::EMPTY;
		} else if (!r && !g && b) {
			tiles[i] = Tile::ENTRY;
			entry = glm::vec3(x(i), 0, y(i));
		} else if (r && !g && !b) {
			tiles[i] = Tile::EXIT;
			exit = glm::vec3(x(i), 0, y(i));
		}
	}
	fclose(f);
}

void Maze::init(Program* program)
{
	wall = new Cube(program, "resources/wall_brick.jpg");
	floor = new Cube(program, "resources/floor_brick.jpg");
}

Maze::~Maze()
{
}

void Maze::draw(Program* program)
{
	wall->bind(program);
	for (const glm::vec3 pos : walls) {
		glm::mat4 transform;
		transform = glm::scale(transform, size * glm::vec3(0.9999f, 0.9999f, 0.9999f));
		transform = glm::translate(transform, size * glm::vec3(pos));
		program->setMat4(transform, "transform");
		wall->draw();
	}

	floor->bind(program);
	for (int i = 0; i < width * height; i++)
	{
		glm::mat4 transform;
		transform = glm::scale(transform, size * glm::vec3(0.9999f, 0.9999f, 0.9999f));
		transform = glm::translate(transform, size * glm::vec3(x(i), -1.0f, y(i)));
		program->setMat4(transform, "transform");
		floor->draw();
	}

}

Tile* Maze::copyBoard()
{
	Tile* cpy = new Tile[width * height];
	std::memcpy(cpy, tiles, sizeof(Tile) * width * height);
	return cpy;
}

glm::vec3 Maze::getEntryPosition()
{
	return entry + glm::vec3(size / 2, PLAYER_HEIGHT, size / 2);
}

inline float max(float x, float y)
{
	return x > y ? x : y;
}

bool Maze::checkCollision(glm::vec3 current, glm::vec3& position)
{
	int cur_x = static_cast<int>(floorf(current.x / size));
	int cur_z = static_cast<int>(floorf(current.z / size));

	int pos_x = cur_x, pos_z = cur_z;

	glm::vec3 direction = position - current;

	Direction dir_x = Direction::UNKNOWN, dir_z = Direction::UNKNOWN;

	if (direction.x > 0) {
		dir_x = Direction::EAST;
		pos_x = static_cast<int>(floorf((position.x + PLAYER_OFFSET) / size));
	}

	if (direction.x < 0) {
		dir_x = Direction::WEST;
		pos_x = static_cast<int>(floorf((position.x - PLAYER_OFFSET) / size));
	}

	if (direction.z > 0) {
		dir_z = Direction::NORTH;
		pos_z = static_cast<int>(floorf((position.z + PLAYER_OFFSET) / size));
	}

	if (direction.z < 0) {
		dir_z = Direction::SOUTH;
		pos_z = static_cast<int>(floorf((position.z - PLAYER_OFFSET) / size));
	}

	if (dir_x == Direction::UNKNOWN && dir_z == Direction::UNKNOWN) {
		return false;
	}

	bool collide = false;

	float x1 = size, z1 = size;
	float x2 = size, z2 = size;

	if (dir_x == Direction::EAST && pos_x - cur_x > 0 && tiles[i(cur_x + 1, cur_z)]) {
		x1 = ((cur_x + 1) * size - PLAYER_OFFSET) - current.x;
		if (x1 * x1 < MIN_RESPONSE && direction.x * direction.x < MIN_COLLISION) {
			z1 = direction.z * RESPONSE;
		} else {
			z1 = (x1 * (position.z - current.z)) / max(position.x - current.x, MIN_DST);
		}

		collide = true;
	} else if (dir_x == Direction::WEST && pos_x - cur_x < 0 && tiles[i(cur_x - 1, cur_z)]) {
		x1 = ((cur_x)* size + PLAYER_OFFSET) - current.x;
		if (x1 * x1 < MIN_RESPONSE && direction.x * direction.x < MIN_COLLISION) {
			z1 = direction.z * RESPONSE;
		} else {
			z1 = (x1 * (position.z - current.z)) / max(position.x - current.x, MIN_DST);
		}

		collide = true;
	}

	if (dir_z == Direction::NORTH && pos_z - cur_z > 0 && tiles[i(cur_x, cur_z + 1)]) {
		z2 = ((cur_z + 1) * size - PLAYER_OFFSET) - current.z;
		if (z2 * z2 < MIN_RESPONSE && direction.z * direction.z < MIN_COLLISION * 0.75) {
			x2 = direction.x * RESPONSE;
		} else {
			x2 = (z2 * (position.x - current.x)) / max(position.z - current.z, MIN_DST);
		}

		collide = true;
	} else if (dir_z == Direction::SOUTH && pos_z - cur_z < 0 && tiles[i(cur_x, cur_z - 1)]) {
		z2 = ((cur_z)* size + PLAYER_OFFSET) - current.z;
		if (z2 * z2 < MIN_RESPONSE && direction.z * direction.z < MIN_COLLISION) {
			x2 = direction.x * RESPONSE;
		} else {
			x2 = (z2 * (position.x - current.x)) / max(position.z - current.z, MIN_DST);
		}

		collide = true;
	}

	if (!collide) {
		return collide;
	}

	if (x1 * x1 + z1 * z1 < x2 * x2 + z2 * z2) {
		position = current + glm::vec3(x1, 0, z1);
	} else {
		position = current + glm::vec3(x2, 0, z2);
	}

	return collide;
}
<|endoftext|>