<commit_before>#ifndef _paintown_thread_h
#define _paintown_thread_h

#ifdef USE_SDL
#include <SDL_thread.h>
#include <SDL_mutex.h>
#else
#include <pthread.h>
#include <semaphore.h>
#endif

#include "exceptions/exception.h"
#include "util/load_exception.h"
#include "util/token_exception.h"
#include "mugen/exception.h"
#include "../debug.h"

namespace Util{

/* Either uses pthreads or SDL_thread */
namespace Thread{
#ifdef USE_SDL
    typedef SDL_mutex* Lock;
    typedef SDL_Thread* Id;
    typedef int (*ThreadFunction)(void*);
    typedef SDL_semaphore* Semaphore;
#else
    typedef pthread_mutex_t Lock;
    typedef pthread_t Id;
    typedef sem_t Semaphore;
    typedef void * (*ThreadFunction)(void*);
#endif

    void initializeLock(Lock * lock);

    void initializeSemaphore(Semaphore * semaphore, unsigned int value);
    void destroySemaphore(Semaphore * semaphore);
    void semaphoreDecrease(Semaphore * semaphore);
    void semaphoreIncrease(Semaphore * semaphore);

    int acquireLock(Lock * lock);
    int releaseLock(Lock * lock);
    void destroyLock(Lock * lock);
    bool createThread(Id * thread, void * attributes, ThreadFunction function, void * arg);
    void joinThread(Id thread);
    void cancelThread(Id thread);
}

class WaitThread{
public:
    /* does not start a new thread yet */
    WaitThread();

    /* starts a thread */
    WaitThread(Thread::ThreadFunction thread, void * arg);

    /* starts a thread */
    void start(Thread::ThreadFunction thread, void * arg);

    bool isRunning();
    void kill();

    virtual ~WaitThread();

public:
    /* actually runs the thread */
    void doRun();

protected:
    Thread::Lock doneLock;
    Thread::Id thread;
    volatile bool done;
    void * arg;
    Thread::ThreadFunction function;
};

/* wraps a boolean with lock/unlock while checking/setting it */
class ThreadBoolean{
public:
    ThreadBoolean(volatile bool & what, Thread::Lock & lock);

    bool get();
    void set(bool value);

protected:
    volatile bool & what;
    Thread::Lock & lock;
};

/* Computes stuff in a separate thread and gives it back when you ask for it.
 * As soon as the future is created a thread will start executing and compute
 * whatever it is that the class is supposed to do. You can then call `get'
 * on the future object to get the result. If the thread is still executing
 * then `get' will block until the future completes. If the future has already
 * completed then `get' will return immediately with the computed value.
 * The use case is computing something that has to be used later:
 *  Future future; // might take a while to compute
 *  do_stuff_that_takes_a_while(); // future might finish sometime in here
 *  Object o = future.get(); // future is already done
 *
 * TODO: handle exceptions
 */
template<class X>
class Future{
protected:
    /* WARNING: hack to find out the type of the exception */
    enum ExceptionType{
        None,
        Load,
        Token,
        Base,
        Mugen
    };

public:
    Future():
    thing(0),
    exception(__FILE__, __LINE__),
    haveException(None){
        /* future will increase the count */
        Thread::initializeSemaphore(&future, 0);
    }

    virtual ~Future(){
        if (thread != NULL){
            Thread::joinThread(thread);
        }
        Thread::destroySemaphore(&future);
    }

    virtual X get(){
        X out;
        Thread::semaphoreDecrease(&future);
        switch (haveException){
            case None : break;
            case Load : throw LoadException(__FILE__, __LINE__, exception, "Failed in future");
            case Mugen : throw MugenException(exception.getTrace());
            case Token: throw TokenException(exception);
            default : throw Exception::Base(__FILE__, __LINE__, exception);
        }
        out = thing;
        Thread::semaphoreIncrease(&future);
        return out;
    }

    virtual void start(){
        if (!Thread::createThread(&thread, NULL, (Thread::ThreadFunction) runit, this)){
            Global::debug(0) << "Could not create future thread. Blocking until its done" << std::endl;
            get();
            // throw Exception::Base(__FILE__, __LINE__);
        }
    }
<commit_msg>invoke the compute through the normal interface<commit_after>#ifndef _paintown_thread_h
#define _paintown_thread_h

#ifdef USE_SDL
#include <SDL_thread.h>
#include <SDL_mutex.h>
#else
#include <pthread.h>
#include <semaphore.h>
#endif

#include "exceptions/exception.h"
#include "util/load_exception.h"
#include "util/token_exception.h"
#include "mugen/exception.h"
#include "../debug.h"

namespace Util{

/* Either uses pthreads or SDL_thread */
namespace Thread{
#ifdef USE_SDL
    typedef SDL_mutex* Lock;
    typedef SDL_Thread* Id;
    typedef int (*ThreadFunction)(void*);
    typedef SDL_semaphore* Semaphore;
#else
    typedef pthread_mutex_t Lock;
    typedef pthread_t Id;
    typedef sem_t Semaphore;
    typedef void * (*ThreadFunction)(void*);
#endif

    void initializeLock(Lock * lock);

    void initializeSemaphore(Semaphore * semaphore, unsigned int value);
    void destroySemaphore(Semaphore * semaphore);
    void semaphoreDecrease(Semaphore * semaphore);
    void semaphoreIncrease(Semaphore * semaphore);

    int acquireLock(Lock * lock);
    int releaseLock(Lock * lock);
    void destroyLock(Lock * lock);
    bool createThread(Id * thread, void * attributes, ThreadFunction function, void * arg);
    void joinThread(Id thread);
    void cancelThread(Id thread);
}

class WaitThread{
public:
    /* does not start a new thread yet */
    WaitThread();

    /* starts a thread */
    WaitThread(Thread::ThreadFunction thread, void * arg);

    /* starts a thread */
    void start(Thread::ThreadFunction thread, void * arg);

    bool isRunning();
    void kill();

    virtual ~WaitThread();

public:
    /* actually runs the thread */
    void doRun();

protected:
    Thread::Lock doneLock;
    Thread::Id thread;
    volatile bool done;
    void * arg;
    Thread::ThreadFunction function;
};

/* wraps a boolean with lock/unlock while checking/setting it */
class ThreadBoolean{
public:
    ThreadBoolean(volatile bool & what, Thread::Lock & lock);

    bool get();
    void set(bool value);

protected:
    volatile bool & what;
    Thread::Lock & lock;
};

/* Computes stuff in a separate thread and gives it back when you ask for it.
 * As soon as the future is created a thread will start executing and compute
 * whatever it is that the class is supposed to do. You can then call `get'
 * on the future object to get the result. If the thread is still executing
 * then `get' will block until the future completes. If the future has already
 * completed then `get' will return immediately with the computed value.
 * The use case is computing something that has to be used later:
 *  Future future; // might take a while to compute
 *  do_stuff_that_takes_a_while(); // future might finish sometime in here
 *  Object o = future.get(); // future is already done
 *
 * TODO: handle exceptions
 */
template<class X>
class Future{
protected:
    /* WARNING: hack to find out the type of the exception */
    enum ExceptionType{
        None,
        Load,
        Token,
        Base,
        Mugen
    };

public:
    Future():
    thing(0),
    exception(__FILE__, __LINE__),
    haveException(None){
        /* future will increase the count */
        Thread::initializeSemaphore(&future, 0);
    }

    virtual ~Future(){
        if (thread != NULL){
            Thread::joinThread(thread);
        }
        Thread::destroySemaphore(&future);
    }

    virtual X get(){
        X out;
        Thread::semaphoreDecrease(&future);
        switch (haveException){
            case None : break;
            case Load : throw LoadException(__FILE__, __LINE__, exception, "Failed in future");
            case Mugen : throw MugenException(exception.getTrace());
            case Token: throw TokenException(exception);
            default : throw Exception::Base(__FILE__, __LINE__, exception);
        }
        out = thing;
        Thread::semaphoreIncrease(&future);
        return out;
    }

    virtual void start(){
        if (!Thread::createThread(&thread, NULL, (Thread::ThreadFunction) runit, this)){
            Global::debug(0) << "Could not create future thread. Blocking until its done" << std::endl;
            runit(this);
            // throw Exception::Base(__FILE__, __LINE__);
        }
    }

{'fraction_non_alphanumeric': 0.10281257385960765, 'fraction_numerical': 0.0007090522335145356, 'mean_word_length': 3.047345767575323, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3346941', 'n_tokens_mistral': 2430, 'n_tokens_neox': 2367, 'n_words': 816}