<commit_before>
#include "snow_core.h"
#include "snow_io.h"
#include "common/snow_event_queue.h"


#include <string>
#include <vector>

#include <windows.h>

namespace snow {

    extern double timestamp();

    namespace io {

        static eventqueue_t filewatch_queue;

        class FileWatcherThread {

          public:
            bool running;
            std::string path;
            HANDLE handle;
            HANDLE thread;
            OVERLAPPED overlap;
            BYTE* buffer;
            size_t buffer_size;
            CRITICAL_SECTION critical;

            static DWORD WINAPI run_thread( void *watcher );

            FileWatcherThread(const std::string &_path) {

                running = false;
                path = std::string(_path);
                buffer_size = 1024;
                buffer = new BYTE[buffer_size];

                    //I spitballed this 2048 spin count from reading some posts online
                int _spincount = 2048;
                #ifndef DEBUG
                    ::InitializeCriticalSectionEx(&critical, _spincount, CRITICAL_SECTION_NO_DEBUG_INFO);
                #else
                    ::InitializeCriticalSectionEx(&critical, _spincount, 0);
                #endif

                handle = ::CreateFile(
                    path.c_str(),
                    FILE_LIST_DIRECTORY,
                    FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
                    NULL,
                    OPEN_EXISTING,
                    FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
                    NULL
                );

                if(handle != INVALID_HANDLE_VALUE) {

                    ZeroMemory(&overlap, sizeof(overlap));
                    overlap.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);

                    DWORD threadid;
                    running = true;
                    thread = CreateThread(NULL, 0, &run_thread, this, 0, &threadid);

                } //!invalid handle

            } //construct

            ~FileWatcherThread() {

                running = false;

                ::LeaveCriticalSection(&critical);
                ::DeleteCriticalSection(&critical);

                ::CancelIo(handle);
                ::CloseHandle(handle);
                ::CloseHandle(thread);

            } //~

        }; //class FileWatcherThread


        DWORD WINAPI FileWatcherThread::run_thread( void *_watcher ) {

            FileWatcherThread *watcher = (FileWatcherThread*)_watcher;


            while(watcher->running) {

                ReadDirectoryChangesW(
                    watcher->handle, watcher->buffer, watcher->buffer_size, TRUE,
                    FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE,
                    NULL, &watcher->overlap, NULL
                );

                WaitForSingleObject(watcher->overlap.hEvent, INFINITE);

                    int seek = 0;

                    while(seek < watcher->buffer_size) {

                        PFILE_NOTIFY_INFORMATION notifier = PFILE_NOTIFY_INFORMATION(watcher->buffer + seek);

                        WCHAR szwFileName[MAX_PATH];
                        int ulCount = notifier->FileNameLength/2;
                        wcsncpy(szwFileName, notifier->FileName, ulCount);
                        szwFileName[ulCount] = L'\0';

                        std::wstring widepath(szwFileName);
                        std::string path(widepath.begin(), widepath.end());

                        FileWatchEventType _event_type = fe_unknown;

                            switch( notifier->Action ) {

                                case FILE_ACTION_ADDED:{
                                    _event_type = fe_create;
                                    break;
                                }

                                case FILE_ACTION_REMOVED:{
                                    _event_type = fe_remove;
                                    break;
                                }

                                case FILE_ACTION_MODIFIED:{
                                    _event_type = fe_modify;
                                    break;
                                }

                                case FILE_ACTION_RENAMED_OLD_NAME:{
                                    _event_type = fe_remove;
                                    break;
                                }

                                case FILE_ACTION_RENAMED_NEW_NAME:{
                                    _event_type = fe_create;
                                    break;
                                }

                            } //switch

                            if(_event_type != fe_unknown) {

                                // put into queue
                                event_node_t* node = new event_node_t;
                                node->event = new FileWatchEvent( _event_type, snow::timestamp(), (watcher->path+"/"+path) );
                                eventqueue_push(&filewatch_queue, node);

                            }

                        seek += notifier->NextEntryOffset;

                        if(notifier->NextEntryOffset == 0) {
                            break;
                        }

                    } //seek < buffer size

                } //while running

            return 0;

        } //run_thread

        std::vector<std::string> watched_paths;
        std::vector<FileWatcherThread*> watchers;

        bool init_filewatch() {

            snow::log("/ snow / initialized file watch ok");

            return true;

        } //init_filewatch

        void start_filewatch(){

            // create our queue
            eventqueue_create((eventqueue_t*)&filewatch_queue);

            if(watched_paths.size() == 0) {
                return;
            }<commit_msg>fixed crash concerning initialization of queue when not watching anything<commit_after>
#include "snow_core.h"
#include "snow_io.h"
#include "common/snow_event_queue.h"


#include <string>
#include <vector>

#include <windows.h>

namespace snow {

    extern double timestamp();

    namespace io {

        static eventqueue_t filewatch_queue;

        class FileWatcherThread {

          public:
            bool running;
            std::string path;
            HANDLE handle;
            HANDLE thread;
            OVERLAPPED overlap;
            BYTE* buffer;
            size_t buffer_size;
            CRITICAL_SECTION critical;

            static DWORD WINAPI run_thread( void *watcher );

            FileWatcherThread(const std::string &_path) {

                running = false;
                path = std::string(_path);
                buffer_size = 1024;
                buffer = new BYTE[buffer_size];

                    //I spitballed this 2048 spin count from reading some posts online
                int _spincount = 2048;
                #ifndef DEBUG
                    ::InitializeCriticalSectionEx(&critical, _spincount, CRITICAL_SECTION_NO_DEBUG_INFO);
                #else
                    ::InitializeCriticalSectionEx(&critical, _spincount, 0);
                #endif

                handle = ::CreateFile(
                    path.c_str(),
                    FILE_LIST_DIRECTORY,
                    FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
                    NULL,
                    OPEN_EXISTING,
                    FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
                    NULL
                );

                if(handle != INVALID_HANDLE_VALUE) {

                    ZeroMemory(&overlap, sizeof(overlap));
                    overlap.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);

                    DWORD threadid;
                    running = true;
                    thread = CreateThread(NULL, 0, &run_thread, this, 0, &threadid);

                } //!invalid handle

            } //construct

            ~FileWatcherThread() {

                running = false;

                ::LeaveCriticalSection(&critical);
                ::DeleteCriticalSection(&critical);

                ::CancelIo(handle);
                ::CloseHandle(handle);
                ::CloseHandle(thread);

            } //~

        }; //class FileWatcherThread


        DWORD WINAPI FileWatcherThread::run_thread( void *_watcher ) {

            FileWatcherThread *watcher = (FileWatcherThread*)_watcher;


            while(watcher->running) {

                ReadDirectoryChangesW(
                    watcher->handle, watcher->buffer, watcher->buffer_size, TRUE,
                    FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE,
                    NULL, &watcher->overlap, NULL
                );

                WaitForSingleObject(watcher->overlap.hEvent, INFINITE);

                    int seek = 0;

                    while(seek < watcher->buffer_size) {

                        PFILE_NOTIFY_INFORMATION notifier = PFILE_NOTIFY_INFORMATION(watcher->buffer + seek);

                        WCHAR szwFileName[MAX_PATH];
                        int ulCount = notifier->FileNameLength/2;
                        wcsncpy(szwFileName, notifier->FileName, ulCount);
                        szwFileName[ulCount] = L'\0';

                        std::wstring widepath(szwFileName);
                        std::string path(widepath.begin(), widepath.end());

                        FileWatchEventType _event_type = fe_unknown;

                            switch( notifier->Action ) {

                                case FILE_ACTION_ADDED:{
                                    _event_type = fe_create;
                                    break;
                                }

                                case FILE_ACTION_REMOVED:{
                                    _event_type = fe_remove;
                                    break;
                                }

                                case FILE_ACTION_MODIFIED:{
                                    _event_type = fe_modify;
                                    break;
                                }

                                case FILE_ACTION_RENAMED_OLD_NAME:{
                                    _event_type = fe_remove;
                                    break;
                                }

                                case FILE_ACTION_RENAMED_NEW_NAME:{
                                    _event_type = fe_create;
                                    break;
                                }

                            } //switch

                            if(_event_type != fe_unknown) {

                                // put into queue
                                event_node_t* node = new event_node_t;
                                node->event = new FileWatchEvent( _event_type, snow::timestamp(), (watcher->path+"/"+path) );
                                eventqueue_push(&filewatch_queue, node);

                            }

                        seek += notifier->NextEntryOffset;

                        if(notifier->NextEntryOffset == 0) {
                            break;
                        }

                    } //seek < buffer size

                } //while running

            return 0;

        } //run_thread

        std::vector<std::string> watched_paths;
        std::vector<FileWatcherThread*> watchers;

        bool init_filewatch() {

            snow::log("/ snow / initialized file watch ok");

            // create our queue
            eventqueue_create((eventqueue_t*)&filewatch_queue);

            return true;

        } //init_filewatch

        void start_filewatch(){

            if(watched_paths.size() == 0) {
                return;
            }
{'fraction_non_alphanumeric': 0.07515233581584292, 'fraction_numerical': 0.0035545023696682463, 'mean_word_length': 1.0952127659574469, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 43, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 22, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6436204', 'n_tokens_mistral': 3026, 'n_tokens_neox': 2672, 'n_words': 529}