├── .clang-format ├── .clang-tidy ├── .dir-locals.el ├── .gitignore ├── .travis.yml ├── .vscode ├── c_cpp_properties.json ├── launch.json ├── settings.json └── tasks.json ├── CMakeLists.txt ├── LICENSE ├── README.md ├── cmake └── jet_live_setup.cmake ├── example ├── CMakeLists.txt └── src │ ├── ExampleListener.cpp │ ├── ExampleListener.hpp │ ├── SimpleCommandInterpreter.cpp │ ├── SimpleCommandInterpreter.hpp │ └── main.cpp ├── libs ├── .clang-format ├── Catch2 │ ├── LICENSE.txt │ ├── README.md │ └── catch.hpp ├── ELFIO │ ├── AUTHORS │ ├── COPYING │ └── elfio │ │ ├── elf_types.hpp │ │ ├── elfio.hpp │ │ ├── elfio_dump.hpp │ │ ├── elfio_dynamic.hpp │ │ ├── elfio_header.hpp │ │ ├── elfio_note.hpp │ │ ├── elfio_relocation.hpp │ │ ├── elfio_section.hpp │ │ ├── elfio_segment.hpp │ │ ├── elfio_strings.hpp │ │ ├── elfio_symbols.hpp │ │ └── elfio_utils.hpp ├── argh │ ├── LICENSE │ ├── README.md │ ├── argh.h │ └── include │ │ └── argh.h ├── efsw │ ├── LICENSE │ ├── README.md │ ├── include │ │ └── efsw │ │ │ ├── efsw.h │ │ │ └── efsw.hpp │ └── src │ │ └── efsw │ │ ├── Debug.cpp │ │ ├── Debug.hpp │ │ ├── DirWatcherGeneric.cpp │ │ ├── DirWatcherGeneric.hpp │ │ ├── DirectorySnapshot.cpp │ │ ├── DirectorySnapshot.hpp │ │ ├── DirectorySnapshotDiff.cpp │ │ ├── DirectorySnapshotDiff.hpp │ │ ├── FileInfo.cpp │ │ ├── FileInfo.hpp │ │ ├── FileSystem.cpp │ │ ├── FileSystem.hpp │ │ ├── FileWatcher.cpp │ │ ├── FileWatcherCWrapper.cpp │ │ ├── FileWatcherFSEvents.cpp │ │ ├── FileWatcherFSEvents.hpp │ │ ├── FileWatcherGeneric.cpp │ │ ├── FileWatcherGeneric.hpp │ │ ├── FileWatcherImpl.cpp │ │ ├── FileWatcherImpl.hpp │ │ ├── FileWatcherInotify.cpp │ │ ├── FileWatcherInotify.hpp │ │ ├── FileWatcherKqueue.cpp │ │ ├── FileWatcherKqueue.hpp │ │ ├── FileWatcherWin32.cpp │ │ ├── FileWatcherWin32.hpp │ │ ├── Lock.hpp │ │ ├── Log.cpp │ │ ├── Mutex.cpp │ │ ├── Mutex.hpp │ │ ├── String.cpp │ │ ├── String.hpp │ │ ├── System.cpp │ │ ├── System.hpp │ │ ├── Thread.cpp │ │ ├── Thread.hpp │ │ ├── Utf.hpp │ │ ├── Utf.inl │ │ ├── Watcher.cpp │ │ ├── Watcher.hpp │ │ ├── WatcherFSEvents.cpp │ │ ├── WatcherFSEvents.hpp │ │ ├── WatcherGeneric.cpp │ │ ├── WatcherGeneric.hpp │ │ ├── WatcherInotify.cpp │ │ ├── WatcherInotify.hpp │ │ ├── WatcherKqueue.cpp │ │ ├── WatcherKqueue.hpp │ │ ├── WatcherWin32.cpp │ │ ├── WatcherWin32.hpp │ │ ├── base.hpp │ │ ├── inotify-nosys.h │ │ ├── platform │ │ ├── platformimpl.hpp │ │ ├── posix │ │ │ ├── FileSystemImpl.cpp │ │ │ ├── FileSystemImpl.hpp │ │ │ ├── MutexImpl.cpp │ │ │ ├── MutexImpl.hpp │ │ │ ├── SystemImpl.cpp │ │ │ ├── SystemImpl.hpp │ │ │ ├── ThreadImpl.cpp │ │ │ └── ThreadImpl.hpp │ │ └── win │ │ │ ├── FileSystemImpl.cpp │ │ │ ├── FileSystemImpl.hpp │ │ │ ├── MutexImpl.cpp │ │ │ ├── MutexImpl.hpp │ │ │ ├── SystemImpl.cpp │ │ │ ├── SystemImpl.hpp │ │ │ ├── ThreadImpl.cpp │ │ │ └── ThreadImpl.hpp │ │ └── sophist.h ├── json │ ├── LICENSE.MIT │ ├── README.md │ └── json.hpp ├── subhook │ ├── LICENSE.txt │ ├── README.md │ ├── subhook.c │ ├── subhook.h │ ├── subhook_private.h │ ├── subhook_unix.c │ ├── subhook_windows.c │ └── subhook_x86.c ├── teenypath │ ├── LICENSE │ ├── README.md │ ├── include │ │ └── teenypath.h │ └── src │ │ └── teenypath.cpp ├── tiny-process-library │ ├── LICENSE │ ├── README.md │ ├── process.cpp │ ├── process.hpp │ ├── process_unix.cpp │ └── process_win.cpp ├── utils │ ├── small_vector │ │ ├── LICENSE.txt │ │ └── small_vector.hpp │ └── utils.hpp ├── whereami │ ├── LICENSE.MIT │ ├── README.md │ └── src │ │ ├── whereami.c │ │ └── whereami.h └── xxHash │ ├── LICENSE │ ├── README.md │ ├── xxh3.h │ ├── xxhash.c │ └── xxhash.h ├── src └── jet │ └── live │ ├── AsyncEventQueue.cpp │ ├── AsyncEventQueue.hpp │ ├── BuildConfig.cpp │ ├── BuildConfig.hpp │ ├── CodeReloadPipeline.cpp │ ├── CodeReloadPipeline.hpp │ ├── CompileCommandsCompilationUnitsParser.cpp │ ├── CompileCommandsCompilationUnitsParser.hpp │ ├── Compiler.cpp │ ├── Compiler.hpp │ ├── DataTypes.hpp │ ├── DefaultProgramInfoLoader.hpp │ ├── DefaultSymbolsFilter.cpp │ ├── DefaultSymbolsFilter.hpp │ ├── DepfileDependenciesHandler.cpp │ ├── DepfileDependenciesHandler.hpp │ ├── FileWatcher.cpp │ ├── FileWatcher.hpp │ ├── FunctionsHookingStep.cpp │ ├── FunctionsHookingStep.hpp │ ├── ICodeReloadPipelineStep.hpp │ ├── ICompilationUnitsParser.hpp │ ├── IDependenciesHandler.hpp │ ├── IEvent.hpp │ ├── ILiveListener.hpp │ ├── IProgramInfoLoader.hpp │ ├── ISymbolsFilter.hpp │ ├── LinkTimeRelocationsStep.cpp │ ├── LinkTimeRelocationsStep.hpp │ ├── Live.cpp │ ├── Live.hpp │ ├── LiveConfig.hpp │ ├── LiveContext.hpp │ ├── SignalReloader.cpp │ ├── SignalReloader.hpp │ ├── StaticsCopyStep.cpp │ ├── StaticsCopyStep.hpp │ ├── Status.hpp │ ├── Utility.cpp │ ├── Utility.hpp │ ├── _linux │ ├── ElfProgramInfoLoader.cpp │ ├── ElfProgramInfoLoader.hpp │ └── Utility.cpp │ ├── _macos │ ├── MachoProgramInfoLoader.cpp │ ├── MachoProgramInfoLoader.hpp │ └── Utility.cpp │ └── events │ ├── FileChangedEvent.hpp │ ├── LogEvent.hpp │ └── TryReloadEvent.hpp ├── tests ├── .clang-format ├── CMakeLists.txt └── src │ ├── Globals.hpp │ ├── Stacktrace.cpp │ ├── Stacktrace.hpp │ ├── TestListener.cpp │ ├── TestListener.hpp │ ├── WaitForReload.cpp │ ├── WaitForReload.hpp │ ├── bad │ ├── LambdaFunctionWithCapturesBadCase2_test.cpp │ └── LambdaFunctionWithCapturesBadCase_test.cpp │ ├── good │ ├── ClassInstanceMethod_test.cpp │ ├── ClassStaticMethod_test.cpp │ ├── ClassVirtualMethod_test.cpp │ ├── CommonSection_test.cpp │ ├── ExternGlobalVariableAddress_test.cpp │ ├── ExternGlobalVariable_test.cpp │ ├── FailedCompilationCrash_test.cpp │ ├── GlobalFreeFunction_test.cpp │ ├── GlobalVariableAddress_test.cpp │ ├── GlobalVariable_test.cpp │ ├── InternalLinkageFunction_test.cpp │ ├── LambdaFunctionWithCapturesGoodCase_test.cpp │ ├── LambdaFunctionWithCaptures_test.cpp │ ├── LambdaFunction_test.cpp │ ├── LostModification_test.cpp │ ├── MacosFunctionOutOfScope_test.cpp │ ├── ModifyFileDuringReload_test.cpp │ ├── MultipleDefinitions_test.cpp │ ├── NewCompilationUnit_test.cpp │ ├── NewHeaderDependency_test.cpp │ ├── OneFrameCompileReload_test.cpp │ ├── ReloadAfterFailedCompilation_test.cpp │ ├── ReloadOnSignal_test.cpp │ ├── SeveralReloads_test.cpp │ ├── StaticFunctionLocalVariableAddress_test.cpp │ ├── StaticFunctionLocalVariable_test.cpp │ ├── StaticInternalVariableAddress_test.cpp │ ├── StaticInternalVariable_test.cpp │ ├── StaticVariableAddress_test.cpp │ ├── StaticVariableSameName_test.cpp │ ├── StaticVariable_test.cpp │ ├── UndefinedSymbolDeep_test.cpp │ └── UndefinedSymbol_test.cpp │ ├── main.cpp │ └── utility │ ├── ClassInstanceMethod.cpp │ ├── ClassInstanceMethod.hpp │ ├── ClassStaticMethod.cpp │ ├── ClassStaticMethod.hpp │ ├── ClassVirtualMethod.cpp │ ├── ClassVirtualMethod.hpp │ ├── CommonSection.c │ ├── CommonSection.h │ ├── ExternGlobalVariable.cpp │ ├── ExternGlobalVariable.hpp │ ├── ExternGlobalVariableAddress.cpp │ ├── ExternGlobalVariableAddress.hpp │ ├── FailedCompilationCrash.cpp │ ├── FailedCompilationCrash.hpp │ ├── GlobalFreeFunction.cpp │ ├── GlobalFreeFunction.hpp │ ├── GlobalVariable.cpp │ ├── GlobalVariable.hpp │ ├── GlobalVariableAddress.cpp │ ├── GlobalVariableAddress.hpp │ ├── IClassVirtualMethod.hpp │ ├── InternalLinkageFunction.cpp │ ├── InternalLinkageFunction.hpp │ ├── LambdaFunction.cpp │ ├── LambdaFunction.hpp │ ├── LambdaFunctionWithCaptures.cpp │ ├── LambdaFunctionWithCaptures.hpp │ ├── LambdaFunctionWithCapturesBadCase.cpp │ ├── LambdaFunctionWithCapturesBadCase.hpp │ ├── LambdaFunctionWithCapturesBadCase2.cpp │ ├── LambdaFunctionWithCapturesBadCase2.hpp │ ├── LambdaFunctionWithCapturesGoodCase.cpp │ ├── LambdaFunctionWithCapturesGoodCase.hpp │ ├── LostModification.cpp │ ├── LostModification.hpp │ ├── LostModification2.cpp │ ├── LostModification2.hpp │ ├── MacosFunctionOutOfScope.cpp │ ├── MacosFunctionOutOfScope.hpp │ ├── ModifyFileDuringReload.cpp │ ├── ModifyFileDuringReload.hpp │ ├── MultipleDefinitions.cpp │ ├── MultipleDefinitions.hpp │ ├── MultipleDefinitions │ ├── MultipleDefinitions1.cpp │ ├── MultipleDefinitions1.hpp │ ├── MultipleDefinitions2.cpp │ └── MultipleDefinitions2.hpp │ ├── NewCompilationUnit.cpp │ ├── NewCompilationUnit.hpp │ ├── NewCompilationUnit │ ├── NewCompilationUnit2.cpp │ └── NewCompilationUnit2.hpp │ ├── NewHeaderDependency.cpp │ ├── NewHeaderDependency.hpp │ ├── NewHeaderDependency │ └── NewHeaderDependency2.hpp │ ├── OneFrameCompileReload.cpp │ ├── OneFrameCompileReload.hpp │ ├── ReloadAfterFailedCompilation1.cpp │ ├── ReloadAfterFailedCompilation1.hpp │ ├── ReloadAfterFailedCompilation2.cpp │ ├── ReloadAfterFailedCompilation2.hpp │ ├── ReloadOnSignal.cpp │ ├── ReloadOnSignal.hpp │ ├── SeveralReloads.cpp │ ├── SeveralReloads.hpp │ ├── StaticFunctionLocalVariable.cpp │ ├── StaticFunctionLocalVariable.hpp │ ├── StaticFunctionLocalVariableAddress.cpp │ ├── StaticFunctionLocalVariableAddress.hpp │ ├── StaticInternalVariable.cpp │ ├── StaticInternalVariable.hpp │ ├── StaticInternalVariableAddress.cpp │ ├── StaticInternalVariableAddress.hpp │ ├── StaticVariable.cpp │ ├── StaticVariable.hpp │ ├── StaticVariableAddress.cpp │ ├── StaticVariableAddress.hpp │ ├── StaticVariableSameName1.cpp │ ├── StaticVariableSameName1.hpp │ ├── StaticVariableSameName2.cpp │ ├── StaticVariableSameName2.hpp │ ├── UndefinedSymbol.cpp │ ├── UndefinedSymbol.hpp │ ├── UndefinedSymbol2.cpp │ ├── UndefinedSymbol2.hpp │ ├── UndefinedSymbolDeep.cpp │ ├── UndefinedSymbolDeep.hpp │ └── UndefinedSymbolDeep │ ├── UndefinedSymbolDeep1.cpp │ ├── UndefinedSymbolDeep1.hpp │ ├── UndefinedSymbolDeep2.cpp │ └── UndefinedSymbolDeep2.hpp └── tools ├── format └── format.sh ├── tests └── test_runner.py └── tidy ├── run-clang-tidy.py └── tidy.py /.dir-locals.el: -------------------------------------------------------------------------------- 1 | ;;; Directory Local Variables 2 | ;;; For more information see (info "(emacs) Directory Variables") 3 | 4 | ((nil 5 | (my/project-app-name . "example"))) 6 | 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | tidy_report 3 | build 4 | compile_commands.json -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: cpp 2 | 3 | matrix: 4 | include: 5 | - name: "Linux clang" 6 | os: linux 7 | compiler: clang 8 | dist: xenial 9 | env: 10 | - CC=clang-7 11 | - CXX=clang++-7 12 | - CC_FOR_BUILD=clang-7 13 | - CXX_FOR_BUILD=clang++-7 14 | - LD=lld-7 15 | before_script: 16 | - curl https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - 17 | - echo "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-7 main" | sudo tee -a /etc/apt/sources.list 18 | - sudo apt-get update -qq 19 | - sudo apt-get install clang-7 lld-7 -y 20 | script: 21 | - sudo mv /usr/bin/ld /usr/bin/ld.old && sudo ln -s /usr/bin/lld-7 /usr/bin/ld 22 | - mkdir build && cd build 23 | - cmake -DCMAKE_BUILD_TYPE=Debug -DJET_LIVE_BUILD_TESTS=ON .. 24 | - make -j4 25 | - ../tools/tests/test_runner.py -b . -d tests -s ../tests 26 | 27 | 28 | - name: "Linux gcc" 29 | os: linux 30 | dist: xenial 31 | compiler: gcc-8 32 | addons: 33 | apt: 34 | sources: 35 | - ubuntu-toolchain-r-test 36 | packages: 37 | - gcc-8 38 | - g++-8 39 | env: 40 | - CC=gcc-8 41 | - CXX=g++-8 42 | - CC_FOR_BUILD=gcc-8 43 | - CXX_FOR_BUILD=g++-8 44 | - LD=ld 45 | script: 46 | - mkdir build && cd build 47 | - cmake -DCMAKE_BUILD_TYPE=Debug -DJET_LIVE_BUILD_TESTS=ON .. 48 | - make -j4 49 | - ../tools/tests/test_runner.py -b . -d tests -s ../tests 50 | 51 | 52 | - name: "macOS make" 53 | os: osx 54 | osx_image: xcode11.2 55 | compiler: clang 56 | script: 57 | - mkdir build && cd build 58 | - cmake -DCMAKE_BUILD_TYPE=Debug -DJET_LIVE_BUILD_TESTS=ON .. 59 | - make -j4 60 | - ../tools/tests/test_runner.py -b . -d tests -s ../tests 61 | 62 | 63 | - name: "macOS xcodebuild" 64 | os: osx 65 | osx_image: xcode11.2 66 | compiler: clang 67 | env: 68 | - BUILD_TOOL=xcodebuild 69 | before_script: 70 | - gem install xcpretty 71 | script: 72 | - mkdir build && cd build 73 | - cmake -DCMAKE_BUILD_TYPE=Debug -DJET_LIVE_BUILD_TESTS=ON -G Xcode .. 74 | - xcodebuild -alltargets -quiet 75 | - ../tools/tests/test_runner.py -b . -d tests/Debug -s ../tests 76 | -------------------------------------------------------------------------------- /.vscode/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "ddovod", 5 | "includePath": [ 6 | "${workspaceFolder}/**" 7 | ], 8 | "defines": [], 9 | "compilerPath": "/usr/bin/c++", 10 | "cStandard": "c11", 11 | "cppStandard": "c++17", 12 | "intelliSenseMode": "clang-x64", 13 | "compileCommands": "${workspaceFolder}/build/compile_commands.json" 14 | } 15 | ], 16 | "version": 4 17 | } 18 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "type": "lldb", 6 | "request": "launch", 7 | "terminal" : "integrated", 8 | "name": "Debug", 9 | "program": "${workspaceFolder}/build/example/example", 10 | "cwd": "${workspaceFolder}/build", 11 | "preLaunchTask": "build" 12 | } 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "cctype": "cpp", 4 | "cmath": "cpp", 5 | "cstdint": "cpp", 6 | "cstdio": "cpp", 7 | "cstdlib": "cpp", 8 | "cwchar": "cpp", 9 | "cwctype": "cpp", 10 | "type_traits": "cpp", 11 | "__config": "cpp", 12 | "cstddef": "cpp", 13 | "exception": "cpp", 14 | "initializer_list": "cpp", 15 | "new": "cpp", 16 | "stdexcept": "cpp", 17 | "typeinfo": "cpp", 18 | "iosfwd": "cpp" 19 | } 20 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "label": "build", 6 | "type": "shell", 7 | "command": "cd ${workspaceFolder}/build && make -j4" 8 | } 9 | ] 10 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 David Dovodov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /cmake/jet_live_setup.cmake: -------------------------------------------------------------------------------- 1 | 2 | set(JET_LIVE_CONFIGURED ON) 3 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # enables compile_commands.json generation 4 | if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug") 5 | message(FATAL_ERROR "jet-live works correctly only on Debug configuration") 6 | endif() 7 | 8 | # -MD - needed to generate depfiles to track dependencies between files. 9 | # -falign-functions=16 - needed to keep enough space between functions to make each function "patchable", so 10 | # with this flag each function size will be not less than 16 bytes. 11 | message("Generator: ${CMAKE_GENERATOR}") 12 | message("Build dir: ${CMAKE_BINARY_DIR}") 13 | if (NOT CMAKE_GENERATOR STREQUAL "Xcode") 14 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -MD ") 15 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -MD ") 16 | endif() 17 | 18 | if (CMAKE_CXX_COMPILER_ID MATCHES "GNU") 19 | # Not all recent versions of clang support this flag. 20 | # But looks like clang already aligns functions on the 16 bytes border by default. 21 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -falign-functions=16 ") 22 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -falign-functions=16 ") 23 | endif() 24 | 25 | # -Wl,-export-dynamic - needed to make dynamic linker happy when the shared lib 26 | # with new code will be loaded into the process' address space. 27 | # -Wl,-export_dynamic - same semantics, but for macos. 28 | # -Wl,-flat_namespace - disables "Two-Level Namespace" feature 29 | # -Wl,-rename_section,__TEXT,__text,__JET_TEXT,__text 30 | # - moves __TEXT.__text section to the new section __JET_TEXT,__text. 31 | # With this flag __JET_TEXT.__text will contain executable code. 32 | # This is a workaround to overcome macOS 10.15 strictness to 33 | # the __TEXT segment access rights. 34 | # -Wl,-segprot,__JET_TEXT,rwx,rwx 35 | # - sets minimum and maximum access rights for the __JET_TEXT segment. 36 | if (UNIX AND NOT APPLE) 37 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-export-dynamic ") 38 | elseif (UNIX AND APPLE) 39 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-export_dynamic -Wl,-flat_namespace -Wl,-rename_section,__TEXT,__text,__JET_TEXT,__text -Wl,-segprot,__JET_TEXT,rwx,rwx ") 40 | else() 41 | message(FATAL_ERROR "Platform is not supported") 42 | endif() 43 | -------------------------------------------------------------------------------- /example/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | cmake_minimum_required(VERSION 3.6) 3 | project(example) 4 | 5 | add_executable(example "") 6 | target_sources(example 7 | PRIVATE 8 | src/main.cpp 9 | src/ExampleListener.cpp 10 | src/SimpleCommandInterpreter.cpp 11 | ) 12 | target_include_directories(example 13 | PRIVATE 14 | src 15 | ) 16 | find_package(Threads REQUIRED) 17 | target_link_libraries(example 18 | PRIVATE 19 | jet-live 20 | Threads::Threads 21 | ) 22 | set_target_properties(example 23 | PROPERTIES 24 | CXX_STANDARD 11 25 | ) 26 | target_compile_options(example 27 | PRIVATE 28 | $<$:-fno-rtti> 29 | $<$:-fno-exceptions> 30 | $<$:-Wall> 31 | $<$:-Wall> 32 | $<$:-Wextra> 33 | $<$:-Wextra> 34 | $<$:-Wpedantic> 35 | $<$:-Wpedantic> 36 | $<$:-Wshadow> 37 | $<$:-Wshadow> 38 | $<$:-Wconversion> 39 | $<$:-Wconversion> 40 | ) 41 | if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") 42 | target_compile_options(example 43 | PRIVATE 44 | $<$:-Wvexing-parse> 45 | $<$:-Wvexing-parse> 46 | ) 47 | endif() 48 | -------------------------------------------------------------------------------- /example/src/ExampleListener.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "ExampleListener.hpp" 3 | #include 4 | 5 | ExampleListener::ExampleListener(std::function&& codePreLoadCallback, 6 | std::function&& codePostLoadCallback) 7 | : m_codePreLoadCallback(std::move(codePreLoadCallback)) 8 | , m_codePostLoadCallback(std::move(codePostLoadCallback)) 9 | { 10 | } 11 | 12 | void ExampleListener::onLog(jet::LogSeverity severity, const std::string& message) 13 | { 14 | std::string severityString; 15 | switch (severity) { 16 | case jet::LogSeverity::kInfo: severityString.append("[I]"); break; 17 | case jet::LogSeverity::kWarning: severityString.append("[W]"); break; 18 | case jet::LogSeverity::kError: severityString.append("[E]"); break; 19 | default: return; // Skipping debug messages, they are too verbose 20 | } 21 | std::cout << severityString << ": " << message << std::endl; 22 | } 23 | 24 | void ExampleListener::onCodePreLoad() 25 | { 26 | m_codePreLoadCallback(); 27 | } 28 | 29 | void ExampleListener::onCodePostLoad() 30 | { 31 | m_codePostLoadCallback(); 32 | } 33 | -------------------------------------------------------------------------------- /example/src/ExampleListener.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | #include 6 | 7 | class ExampleListener : public jet::ILiveListener 8 | { 9 | public: 10 | ExampleListener(std::function&& codePreLoadCallback, std::function&& codePostLoadCallback); 11 | void onLog(jet::LogSeverity severity, const std::string& message) override; 12 | void onCodePreLoad() override; 13 | void onCodePostLoad() override; 14 | 15 | private: 16 | std::function m_codePreLoadCallback; 17 | std::function m_codePostLoadCallback; 18 | }; 19 | -------------------------------------------------------------------------------- /example/src/SimpleCommandInterpreter.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "SimpleCommandInterpreter.hpp" 3 | 4 | SimpleCommandInterpreter::SimpleCommandInterpreter(int currentCommandsCounter) 5 | : m_currentCommandsCounter(currentCommandsCounter) 6 | { 7 | } 8 | 9 | int SimpleCommandInterpreter::getCurrentCommandsCounter() const 10 | { 11 | return m_currentCommandsCounter; 12 | } 13 | 14 | std::string SimpleCommandInterpreter::runCommand(const std::string& command) 15 | { 16 | auto totalCommands = std::to_string(++m_currentCommandsCounter); 17 | std::string result; 18 | 19 | // Implement your commands here 20 | if (command == "Hello") { 21 | result = "Hi there!"; 22 | } else { 23 | result = "Sorry, I don't know what '" + command 24 | + "' means. Fix it in runtime in 'SimpleCommandInterpreter::runCommand'"; 25 | } 26 | 27 | return "ttl: " + totalCommands + " > " + result; 28 | } 29 | -------------------------------------------------------------------------------- /example/src/SimpleCommandInterpreter.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | 6 | class SimpleCommandInterpreter 7 | { 8 | public: 9 | explicit SimpleCommandInterpreter(int currentCommandsCounter = 0); 10 | int getCurrentCommandsCounter() const; 11 | std::string runCommand(const std::string& command); 12 | 13 | private: 14 | int m_currentCommandsCounter = 0; 15 | }; 16 | -------------------------------------------------------------------------------- /example/src/main.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "ExampleListener.hpp" 10 | #include "SimpleCommandInterpreter.hpp" 11 | 12 | std::mutex g_inputMutex; 13 | std::string g_inputCommand; 14 | std::atomic_bool g_runloopContinue{true}; 15 | std::unique_ptr g_commandInterpreter = jet::make_unique(); 16 | int g_tempCommandsCounter = 0; 17 | 18 | void preLoadCallback() 19 | { 20 | // If you're changing the layout of SimpleCommandInterpreter class, uncomment next lines 21 | g_tempCommandsCounter = g_commandInterpreter->getCurrentCommandsCounter(); 22 | g_commandInterpreter.reset(); 23 | } 24 | 25 | void postLoadCallback() 26 | { 27 | // If you're changing the layout of SimpleCommandInterpreter class, uncomment next line 28 | g_commandInterpreter = jet::make_unique(g_tempCommandsCounter); 29 | } 30 | 31 | std::string getNextCommand() 32 | { 33 | std::string cmd; 34 | { 35 | std::lock_guard lock(g_inputMutex); 36 | cmd = g_inputCommand; 37 | g_inputCommand.clear(); 38 | } 39 | return cmd; 40 | } 41 | 42 | int main() 43 | { 44 | auto listener = jet::make_unique(preLoadCallback, postLoadCallback); 45 | jet::LiveConfig config; 46 | config.workerThreadsCount = 2; 47 | auto live = jet::make_unique(std::move(listener), config); 48 | 49 | while (!live->isInitialized()) { 50 | std::this_thread::sleep_for(std::chrono::milliseconds(100)); 51 | live->update(); 52 | } 53 | live->update(); 54 | 55 | // Polling input in background 56 | std::thread inputThread{[] { 57 | std::string command; 58 | while (g_runloopContinue) { 59 | std::getline(std::cin, command); 60 | { 61 | std::lock_guard lock(g_inputMutex); 62 | g_inputCommand = command; 63 | } 64 | } 65 | }}; 66 | 67 | // Simple 60hz runloop 68 | std::cout << "Enter command" << std::endl << "Available commands: 'exit', 'reload', 'hello'" << std::endl; 69 | while (g_runloopContinue) { 70 | live->update(); 71 | std::this_thread::sleep_for(std::chrono::milliseconds(16)); 72 | 73 | auto cmd = getNextCommand(); 74 | if (!cmd.empty()) { 75 | if (cmd == "reload") { 76 | live->tryReload(); 77 | } else if (cmd == "exit") { 78 | g_runloopContinue = false; 79 | } else { 80 | std::cout << g_commandInterpreter->runCommand(cmd) << std::endl; 81 | } 82 | } 83 | } 84 | 85 | std::cout << "Press enter" << std::endl; 86 | inputThread.join(); 87 | 88 | return 0; 89 | } 90 | -------------------------------------------------------------------------------- /libs/.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | DisableFormat: true 3 | SortIncludes: false 4 | ... 5 | -------------------------------------------------------------------------------- /libs/Catch2/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Boost Software License - Version 1.0 - August 17th, 2003 2 | 3 | Permission is hereby granted, free of charge, to any person or organization 4 | obtaining a copy of the software and accompanying documentation covered by 5 | this license (the "Software") to use, reproduce, display, distribute, 6 | execute, and transmit the Software, and to prepare derivative works of the 7 | Software, and to permit third-parties to whom the Software is furnished to 8 | do so, all subject to the following: 9 | 10 | The copyright notices in the Software and this entire statement, including 11 | the above license grant, this restriction and the following disclaimer, 12 | must be included in all copies of the Software, in whole or in part, and 13 | all derivative works of the Software, unless such copies or derivative 14 | works are solely in the form of machine-executable object code generated by 15 | a source language processor. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 20 | SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 21 | FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /libs/Catch2/README.md: -------------------------------------------------------------------------------- 1 | 2 | ![catch logo](artwork/catch2-logo-small.png) 3 | 4 | [![Github Releases](https://img.shields.io/github/release/catchorg/catch2.svg)](https://github.com/catchorg/catch2/releases) 5 | [![Build Status](https://travis-ci.org/catchorg/Catch2.svg?branch=master)](https://travis-ci.org/catchorg/Catch2) 6 | [![Build status](https://ci.appveyor.com/api/projects/status/github/catchorg/Catch2?svg=true)](https://ci.appveyor.com/project/catchorg/catch2) 7 | [![codecov](https://codecov.io/gh/catchorg/Catch2/branch/master/graph/badge.svg)](https://codecov.io/gh/catchorg/Catch2) 8 | [![Try online](https://img.shields.io/badge/try-online-blue.svg)](https://wandbox.org/permlink/7lDqHmzKQxA2eaM0) 9 | [![Join the chat in Discord: https://discord.gg/4CWS9zD](https://img.shields.io/badge/Discord-Chat!-brightgreen.svg)](https://discord.gg/4CWS9zD) 10 | 11 | 12 | The latest version of the single header can be downloaded directly using this link 13 | 14 | ## Catch2 is released! 15 | 16 | If you've been using an earlier version of Catch, please see the 17 | Breaking Changes section of [the release notes](https://github.com/catchorg/Catch2/releases/tag/v2.0.1) 18 | before moving to Catch2. You might also like to read [this blog post](http://www.levelofindirection.com/journal/2017/11/3/catch2-released.html) for more details. 19 | 20 | ## What's the Catch? 21 | 22 | Catch2 stands for C++ Automated Test Cases in a Header and is a 23 | multi-paradigm test framework for C++. which also supports Objective-C 24 | (and maybe C). 25 | It is primarily distributed as a single header file, although certain 26 | extensions may require additional headers. 27 | 28 | ## How to use it 29 | This documentation comprises these three parts: 30 | 31 | * [Why do we need yet another C++ Test Framework?](docs/why-catch.md#top) 32 | * [Tutorial](docs/tutorial.md#top) - getting started 33 | * [Reference section](docs/Readme.md#top) - all the details 34 | 35 | ## More 36 | * Issues and bugs can be raised on the [Issue tracker on GitHub](https://github.com/catchorg/Catch2/issues) 37 | * For discussion or questions please use [the dedicated Google Groups forum](https://groups.google.com/forum/?fromgroups#!forum/catch-forum) or our [Discord](https://discord.gg/4CWS9zD) 38 | * See [who else is using Catch2](docs/opensource-users.md#top) 39 | -------------------------------------------------------------------------------- /libs/ELFIO/AUTHORS: -------------------------------------------------------------------------------- 1 | ELFIO library implemented by 2 | Serge Lamikhov-Center 3 | -------------------------------------------------------------------------------- /libs/ELFIO/COPYING: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (C) 2001-2011 by Serge Lamikhov-Center 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /libs/argh/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016, Adi Shavit 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, 8 | this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | * Neither the name of nor the names of its contributors may be used to 13 | endorse or promote products derived from this software without specific 14 | prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 20 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 | POSSIBILITY OF SUCH DAMAGE. 27 | -------------------------------------------------------------------------------- /libs/argh/include/argh.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #if defined(__clang__) 5 | # pragma clang diagnostic push 6 | # pragma clang diagnostic ignored "-Wsign-conversion" 7 | #elif defined(__GNUC__) 8 | # pragma GCC diagnostic push 9 | # pragma GCC diagnostic ignored "-Wsign-conversion" 10 | #endif 11 | 12 | #include "../argh.h" 13 | 14 | #if defined(__clang__) 15 | # pragma clang diagnostic pop 16 | #elif defined(__GNUC__) 17 | # pragma GCC diagnostic pop 18 | #endif 19 | -------------------------------------------------------------------------------- /libs/efsw/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 Martín Lucas Golini 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | 21 | This software is a fork of the "simplefilewatcher" by James Wynn (james@jameswynn.com) 22 | http://code.google.com/p/simplefilewatcher/ also MIT licensed. -------------------------------------------------------------------------------- /libs/efsw/src/efsw/Debug.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #ifdef EFSW_COMPILER_MSVC 5 | #define WIN32_LEAN_AND_MEAN 6 | #include 7 | #include 8 | #endif 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | namespace efsw { 15 | 16 | #ifdef DEBUG 17 | 18 | void efREPORT_ASSERT( const char * File, int Line, const char * Exp ) 19 | { 20 | #ifdef EFSW_COMPILER_MSVC 21 | _CrtDbgReport( _CRT_ASSERT, File, Line, "", Exp); 22 | 23 | DebugBreak(); 24 | #else 25 | std::cout << "ASSERT: " << Exp << " file: " << File << " line: " << Line << std::endl; 26 | 27 | #if defined(EFSW_COMPILER_GCC) && defined(EFSW_32BIT) && !defined(EFSW_ARM) 28 | asm("int3"); 29 | #else 30 | assert( false ); 31 | #endif 32 | #endif 33 | } 34 | 35 | void efPRINT( const char * format, ... ) 36 | { 37 | char buf[2048]; 38 | va_list args; 39 | 40 | va_start( args, format ); 41 | 42 | #ifdef EFSW_COMPILER_MSVC 43 | _vsnprintf_s( buf, sizeof( buf ), sizeof( buf ) / sizeof( buf[0]), format, args ); 44 | #else 45 | vsnprintf( buf, sizeof( buf ) / sizeof( buf[0]), format, args ); 46 | #endif 47 | 48 | va_end( args ); 49 | 50 | #ifdef EFSW_COMPILER_MSVC 51 | OutputDebugStringA( buf ); 52 | #else 53 | std::cout << buf; 54 | #endif 55 | } 56 | 57 | void efPRINTC( unsigned int cond, const char * format, ...) 58 | { 59 | if ( 0 == cond ) 60 | return; 61 | 62 | char buf[2048]; 63 | va_list args; 64 | 65 | va_start( args, format ); 66 | 67 | #ifdef EFSW_COMPILER_MSVC 68 | _vsnprintf_s( buf, efARRAY_SIZE( buf ), efARRAY_SIZE( buf ), format, args ); 69 | #else 70 | vsnprintf( buf, sizeof( buf ) / sizeof( buf[0]), format, args ); 71 | #endif 72 | 73 | va_end( args ); 74 | 75 | #ifdef EFSW_COMPILER_MSVC 76 | OutputDebugStringA( buf ); 77 | #else 78 | std::cout << buf; 79 | #endif 80 | } 81 | 82 | #endif 83 | 84 | } 85 | 86 | -------------------------------------------------------------------------------- /libs/efsw/src/efsw/Debug.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EFSW_DEBUG_HPP 2 | #define EFSW_DEBUG_HPP 3 | 4 | #include 5 | 6 | namespace efsw { 7 | 8 | #ifdef DEBUG 9 | 10 | void efREPORT_ASSERT( const char * File, const int Line, const char * Exp ); 11 | 12 | #define efASSERT( expr ) if ( !(expr) ) { efREPORT_ASSERT( __FILE__, __LINE__, #expr ); } 13 | #define efASSERTM( expr, msg ) if ( !(expr) ) { efREPORT_ASSERT( __FILE__, __LINE__, #msg ); } 14 | 15 | void efPRINT ( const char * format, ... ); 16 | void efPRINTC ( unsigned int cond, const char * format, ... ); 17 | 18 | #else 19 | 20 | #define efASSERT( expr ) 21 | #define efASSERTM( expr, msg ) 22 | 23 | #ifndef EFSW_COMPILER_MSVC 24 | #define efPRINT( format, args... ) {} 25 | #define efPRINTC( cond, format, args... ) {} 26 | #else 27 | #define efPRINT 28 | #define efPRINTC 29 | #endif 30 | 31 | #endif 32 | 33 | #ifdef EFSW_VERBOSE 34 | #define efDEBUG efPRINT 35 | #define efDEBUGC efPRINTC 36 | #else 37 | 38 | #ifndef EFSW_COMPILER_MSVC 39 | #define efDEBUG( format, args... ) {} 40 | #define efDEBUGC( cond, format, args... ) {} 41 | #else 42 | #define efDEBUG 43 | #define efDEBUGC 44 | #endif 45 | 46 | #endif 47 | 48 | } 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /libs/efsw/src/efsw/DirWatcherGeneric.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EFSW_DIRWATCHERGENERIC_HPP 2 | #define EFSW_DIRWATCHERGENERIC_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace efsw { 10 | 11 | class DirWatcherGeneric 12 | { 13 | public: 14 | typedef std::map DirWatchMap; 15 | 16 | DirWatcherGeneric * Parent; 17 | WatcherGeneric * Watch; 18 | DirectorySnapshot DirSnap; 19 | DirWatchMap Directories; 20 | bool Recursive; 21 | 22 | DirWatcherGeneric( DirWatcherGeneric * parent, WatcherGeneric * ws, const std::string& directory, bool recursive, bool reportNewFiles = false ); 23 | 24 | ~DirWatcherGeneric(); 25 | 26 | void watch( bool reportOwnChange = false ); 27 | 28 | void watchDir( std::string& dir ); 29 | 30 | static bool isDir( const std::string& directory ); 31 | 32 | bool pathInWatches( std::string path ); 33 | 34 | void addChilds( bool reportNewFiles = true ); 35 | 36 | DirWatcherGeneric * findDirWatcher( std::string dir ); 37 | 38 | DirWatcherGeneric * findDirWatcherFast( std::string dir ); 39 | protected: 40 | bool Deleted; 41 | 42 | DirWatcherGeneric * createDirectory( std::string newdir ); 43 | 44 | void removeDirectory( std::string dir ); 45 | 46 | void moveDirectory( std::string oldDir, std::string newDir ); 47 | 48 | void resetDirectory( std::string directory ); 49 | 50 | void handleAction( const std::string& filename, unsigned long action, std::string oldFilename = ""); 51 | }; 52 | 53 | } 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /libs/efsw/src/efsw/DirectorySnapshot.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EFSW_DIRECTORYSNAPSHOT_HPP 2 | #define EFSW_DIRECTORYSNAPSHOT_HPP 3 | 4 | #include 5 | 6 | namespace efsw { 7 | 8 | class DirectorySnapshot 9 | { 10 | public: 11 | FileInfo DirectoryInfo; 12 | FileInfoMap Files; 13 | 14 | void setDirectoryInfo( std::string directory ); 15 | 16 | DirectorySnapshot(); 17 | 18 | DirectorySnapshot( std::string directory ); 19 | 20 | ~DirectorySnapshot(); 21 | 22 | void init( std::string directory ); 23 | 24 | bool exists(); 25 | 26 | DirectorySnapshotDiff scan(); 27 | 28 | FileInfoMap::iterator nodeInFiles( FileInfo& fi ); 29 | 30 | void addFile( std::string path ); 31 | 32 | void removeFile( std::string path ); 33 | 34 | void moveFile( std::string oldPath, std::string newPath ); 35 | 36 | void updateFile( std::string path ); 37 | protected: 38 | void initFiles(); 39 | 40 | void deleteAll( DirectorySnapshotDiff &Diff ); 41 | }; 42 | 43 | } 44 | 45 | #endif 46 | 47 | -------------------------------------------------------------------------------- /libs/efsw/src/efsw/DirectorySnapshotDiff.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace efsw { 4 | 5 | void DirectorySnapshotDiff::clear() 6 | { 7 | FilesCreated.clear(); 8 | FilesModified.clear(); 9 | FilesMoved.clear(); 10 | FilesDeleted.clear(); 11 | DirsCreated.clear(); 12 | DirsModified.clear(); 13 | DirsMoved.clear(); 14 | DirsDeleted.clear(); 15 | } 16 | 17 | bool DirectorySnapshotDiff::changed() 18 | { 19 | return !FilesCreated.empty() || 20 | !FilesModified.empty() || 21 | !FilesMoved.empty() || 22 | !FilesDeleted.empty() || 23 | !DirsCreated.empty() || 24 | !DirsModified.empty() || 25 | !DirsMoved.empty() || 26 | !DirsDeleted.empty(); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /libs/efsw/src/efsw/DirectorySnapshotDiff.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EFSW_DIRECTORYSNAPSHOTDIFF_HPP 2 | #define EFSW_DIRECTORYSNAPSHOTDIFF_HPP 3 | 4 | #include 5 | 6 | namespace efsw { 7 | 8 | class DirectorySnapshotDiff 9 | { 10 | public: 11 | FileInfoList FilesDeleted; 12 | FileInfoList FilesCreated; 13 | FileInfoList FilesModified; 14 | MovedList FilesMoved; 15 | FileInfoList DirsDeleted; 16 | FileInfoList DirsCreated; 17 | FileInfoList DirsModified; 18 | MovedList DirsMoved; 19 | bool DirChanged; 20 | 21 | void clear(); 22 | 23 | bool changed(); 24 | }; 25 | 26 | #define DiffIterator( FileInfoListName ) it = Diff.FileInfoListName.begin(); \ 27 | for ( ; it != Diff.FileInfoListName.end(); it++ ) 28 | 29 | #define DiffMovedIterator( MovedListName ) mit = Diff.MovedListName.begin(); \ 30 | for ( ; mit != Diff.MovedListName.end(); mit++ ) 31 | 32 | } 33 | 34 | #endif 35 | 36 | -------------------------------------------------------------------------------- /libs/efsw/src/efsw/FileInfo.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EFSW_FILEINFO_HPP 2 | #define EFSW_FILEINFO_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace efsw { 10 | 11 | class FileInfo 12 | { 13 | public: 14 | static bool exists( const std::string& filePath ); 15 | 16 | static bool isLink( const std::string& filePath ); 17 | 18 | static bool inodeSupported(); 19 | 20 | FileInfo(); 21 | 22 | FileInfo( const std::string& filepath ); 23 | 24 | FileInfo( const std::string& filepath, bool linkInfo ); 25 | 26 | bool operator==( const FileInfo& Other ) const; 27 | 28 | bool operator!=( const FileInfo& Other ) const; 29 | 30 | FileInfo& operator=( const FileInfo& Other ); 31 | 32 | bool isDirectory() const; 33 | 34 | bool isRegularFile() const; 35 | 36 | bool isReadable() const; 37 | 38 | bool sameInode( const FileInfo& Other ) const; 39 | 40 | bool isLink() const; 41 | 42 | std::string linksTo(); 43 | 44 | bool exists(); 45 | 46 | void getInfo(); 47 | 48 | void getRealInfo(); 49 | 50 | std::string Filepath; 51 | Uint64 ModificationTime; 52 | Uint64 Size; 53 | Uint32 OwnerId; 54 | Uint32 GroupId; 55 | Uint32 Permissions; 56 | Uint64 Inode; 57 | }; 58 | 59 | typedef std::map FileInfoMap; 60 | typedef std::list FileInfoList; 61 | typedef std::list< std::pair< std::string, FileInfo> > MovedList; 62 | 63 | } 64 | 65 | #endif 66 | 67 | -------------------------------------------------------------------------------- /libs/efsw/src/efsw/FileSystem.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EFSW_FILESYSTEM_HPP 2 | #define EFSW_FILESYSTEM_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace efsw { 9 | 10 | class FileSystem 11 | { 12 | public: 13 | static bool isDirectory( const std::string& path ); 14 | 15 | static FileInfoMap filesInfoFromPath( std::string path ); 16 | 17 | static char getOSSlash(); 18 | 19 | static bool slashAtEnd( std::string& dir ); 20 | 21 | static void dirAddSlashAtEnd( std::string& dir ); 22 | 23 | static void dirRemoveSlashAtEnd( std::string& dir ); 24 | 25 | static std::string fileNameFromPath( std::string filepath ); 26 | 27 | static std::string pathRemoveFileName( std::string filepath ); 28 | 29 | static void realPath( std::string curdir, std::string& path ); 30 | 31 | static std::string getLinkRealPath( std::string dir, std::string& curPath ); 32 | 33 | static std::string precomposeFileName(const std::string& name); 34 | 35 | static bool isRemoteFS( const std::string& directory ); 36 | 37 | static bool changeWorkingDirectory( const std::string & path ); 38 | 39 | static std::string getCurrentWorkingDirectory(); 40 | }; 41 | 42 | } 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /libs/efsw/src/efsw/FileWatcherGeneric.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EFSW_FILEWATCHERGENERIC_HPP 2 | #define EFSW_FILEWATCHERGENERIC_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace efsw 10 | { 11 | 12 | /// Implementation for Generic File Watcher. 13 | /// @class FileWatcherGeneric 14 | class FileWatcherGeneric : public FileWatcherImpl 15 | { 16 | public: 17 | typedef std::list WatchList; 18 | 19 | FileWatcherGeneric( FileWatcher * parent ); 20 | 21 | virtual ~FileWatcherGeneric(); 22 | 23 | /// Add a directory watch 24 | /// On error returns WatchID with Error type. 25 | WatchID addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive); 26 | 27 | /// Remove a directory watch. This is a brute force lazy search O(nlogn). 28 | void removeWatch(const std::string& directory); 29 | 30 | /// Remove a directory watch. This is a map lookup O(logn). 31 | void removeWatch(WatchID watchid); 32 | 33 | /// Updates the watcher. Must be called often. 34 | void watch(); 35 | 36 | /// Handles the action 37 | void handleAction(Watcher * watch, const std::string& filename, unsigned long action, std::string oldFilename = ""); 38 | 39 | /// @return Returns a list of the directories that are being watched 40 | std::list directories(); 41 | protected: 42 | Thread * mThread; 43 | 44 | /// The last watchid 45 | WatchID mLastWatchID; 46 | 47 | /// Map of WatchID to WatchStruct pointers 48 | WatchList mWatches; 49 | 50 | Mutex mWatchesLock; 51 | 52 | bool pathInWatches( const std::string& path ); 53 | private: 54 | void run(); 55 | }; 56 | 57 | } 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /libs/efsw/src/efsw/FileWatcherImpl.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | namespace efsw { 6 | 7 | FileWatcherImpl::FileWatcherImpl( FileWatcher * parent ) : 8 | mFileWatcher( parent ), 9 | mInitOK( false ), 10 | mIsGeneric( false ) 11 | { 12 | System::maxFD(); 13 | } 14 | 15 | FileWatcherImpl::~FileWatcherImpl() 16 | { 17 | } 18 | 19 | bool FileWatcherImpl::initOK() 20 | { 21 | return mInitOK; 22 | } 23 | 24 | bool FileWatcherImpl::linkAllowed( const std::string& curPath, const std::string& link ) 25 | { 26 | return ( mFileWatcher->followSymlinks() && mFileWatcher->allowOutOfScopeLinks() ) || -1 != String::strStartsWith( curPath, link ); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /libs/efsw/src/efsw/FileWatcherImpl.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EFSW_FILEWATCHERIMPL_HPP 2 | #define EFSW_FILEWATCHERIMPL_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace efsw { 11 | 12 | class FileWatcherImpl 13 | { 14 | public: 15 | FileWatcherImpl( FileWatcher * parent ); 16 | 17 | virtual ~FileWatcherImpl(); 18 | 19 | /// Add a directory watch 20 | /// On error returns WatchID with Error type. 21 | virtual WatchID addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive) = 0; 22 | 23 | /// Remove a directory watch. This is a brute force lazy search O(nlogn). 24 | virtual void removeWatch(const std::string& directory) = 0; 25 | 26 | /// Remove a directory watch. This is a map lookup O(logn). 27 | virtual void removeWatch(WatchID watchid) = 0; 28 | 29 | /// Updates the watcher. Must be called often. 30 | virtual void watch() = 0; 31 | 32 | /// Handles the action 33 | virtual void handleAction(Watcher * watch, const std::string& filename, unsigned long action, std::string oldFilename = "") = 0; 34 | 35 | /// @return Returns a list of the directories that are being watched 36 | virtual std::list directories() = 0; 37 | 38 | /// @return true if the backend init successfully 39 | virtual bool initOK(); 40 | 41 | /// @return If the link is allowed according to the current path and the state of out scope links 42 | virtual bool linkAllowed( const std::string& curPath, const std::string& link ); 43 | 44 | /// Search if a directory already exists in the watches 45 | virtual bool pathInWatches( const std::string& path ) = 0; 46 | 47 | FileWatcher * mFileWatcher; 48 | bool mInitOK; 49 | bool mIsGeneric; 50 | }; 51 | 52 | } 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /libs/efsw/src/efsw/FileWatcherInotify.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EFSW_FILEWATCHERLINUX_HPP 2 | #define EFSW_FILEWATCHERLINUX_HPP 3 | 4 | #include 5 | 6 | #if EFSW_PLATFORM == EFSW_PLATFORM_INOTIFY 7 | 8 | #include 9 | #include 10 | 11 | namespace efsw 12 | { 13 | 14 | /// Implementation for Linux based on inotify. 15 | /// @class FileWatcherInotify 16 | class FileWatcherInotify : public FileWatcherImpl 17 | { 18 | public: 19 | /// type for a map from WatchID to WatchStruct pointer 20 | typedef std::map WatchMap; 21 | 22 | FileWatcherInotify( FileWatcher * parent ); 23 | 24 | virtual ~FileWatcherInotify(); 25 | 26 | /// Add a directory watch 27 | /// On error returns WatchID with Error type. 28 | WatchID addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive); 29 | 30 | /// Remove a directory watch. This is a brute force lazy search O(nlogn). 31 | void removeWatch(const std::string& directory); 32 | 33 | /// Remove a directory watch. This is a map lookup O(logn). 34 | void removeWatch(WatchID watchid); 35 | 36 | /// Updates the watcher. Must be called often. 37 | void watch(); 38 | 39 | /// Handles the action 40 | void handleAction(Watcher * watch, const std::string& filename, unsigned long action, std::string oldFilename = ""); 41 | 42 | /// @return Returns a list of the directories that are being watched 43 | std::list directories(); 44 | protected: 45 | /// Map of WatchID to WatchStruct pointers 46 | WatchMap mWatches; 47 | 48 | /// User added watches 49 | WatchMap mRealWatches; 50 | 51 | /// inotify file descriptor 52 | int mFD; 53 | 54 | Thread * mThread; 55 | 56 | Mutex mWatchesLock; 57 | 58 | WatchID addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive, WatcherInotify * parent = NULL ); 59 | 60 | bool pathInWatches( const std::string& path ); 61 | private: 62 | void run(); 63 | 64 | void removeWatchLocked(WatchID watchid); 65 | 66 | void checkForNewWatcher( Watcher* watch, std::string fpath ); 67 | 68 | Watcher * watcherContainsDirectory( std::string dir ); 69 | }; 70 | 71 | } 72 | 73 | #endif 74 | 75 | #endif 76 | -------------------------------------------------------------------------------- /libs/efsw/src/efsw/FileWatcherKqueue.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EFSW_FILEWATCHEROSX_HPP 2 | #define EFSW_FILEWATCHEROSX_HPP 3 | 4 | #include 5 | 6 | #if EFSW_PLATFORM == EFSW_PLATFORM_KQUEUE || EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS 7 | 8 | #include 9 | 10 | namespace efsw 11 | { 12 | 13 | /// Implementation for OSX based on kqueue. 14 | /// @class FileWatcherKqueue 15 | class FileWatcherKqueue : public FileWatcherImpl 16 | { 17 | friend class WatcherKqueue; 18 | public: 19 | FileWatcherKqueue( FileWatcher * parent ); 20 | 21 | virtual ~FileWatcherKqueue(); 22 | 23 | /// Add a directory watch 24 | /// On error returns WatchID with Error type. 25 | WatchID addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive); 26 | 27 | /// Remove a directory watch. This is a brute force lazy search O(nlogn). 28 | void removeWatch(const std::string& directory); 29 | 30 | /// Remove a directory watch. This is a map lookup O(logn). 31 | void removeWatch(WatchID watchid); 32 | 33 | /// Updates the watcher. Must be called often. 34 | void watch(); 35 | 36 | /// Handles the action 37 | void handleAction(Watcher* watch, const std::string& filename, unsigned long action, std::string oldFilename = ""); 38 | 39 | /// @return Returns a list of the directories that are being watched 40 | std::list directories(); 41 | protected: 42 | /// Map of WatchID to WatchStruct pointers 43 | WatchMap mWatches; 44 | 45 | /// time out data 46 | struct timespec mTimeOut; 47 | 48 | /// WatchID allocator 49 | int mLastWatchID; 50 | 51 | Thread * mThread; 52 | 53 | Mutex mWatchesLock; 54 | 55 | std::list mRemoveList; 56 | 57 | long mFileDescriptorCount; 58 | 59 | bool mAddingWatcher; 60 | 61 | bool isAddingWatcher() const; 62 | 63 | bool pathInWatches( const std::string& path ); 64 | 65 | void addFD(); 66 | 67 | void removeFD(); 68 | 69 | bool availablesFD(); 70 | private: 71 | void run(); 72 | }; 73 | 74 | } 75 | 76 | #endif 77 | 78 | #endif 79 | -------------------------------------------------------------------------------- /libs/efsw/src/efsw/FileWatcherWin32.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EFSW_FILEWATCHERWIN32_HPP 2 | #define EFSW_FILEWATCHERWIN32_HPP 3 | 4 | #include 5 | 6 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | namespace efsw 13 | { 14 | 15 | /// Implementation for Win32 based on ReadDirectoryChangesW. 16 | /// @class FileWatcherWin32 17 | class FileWatcherWin32 : public FileWatcherImpl 18 | { 19 | public: 20 | /// type for a map from WatchID to WatcherWin32 pointer 21 | typedef std::set Watches; 22 | 23 | FileWatcherWin32( FileWatcher * parent ); 24 | 25 | virtual ~FileWatcherWin32(); 26 | 27 | /// Add a directory watch 28 | /// On error returns WatchID with Error type. 29 | WatchID addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive); 30 | 31 | /// Remove a directory watch. This is a brute force lazy search O(nlogn). 32 | void removeWatch(const std::string& directory); 33 | 34 | /// Remove a directory watch. This is a map lookup O(logn). 35 | void removeWatch(WatchID watchid); 36 | 37 | /// Updates the watcher. Must be called often. 38 | void watch(); 39 | 40 | /// Handles the action 41 | void handleAction(Watcher* watch, const std::string& filename, unsigned long action, std::string oldFilename = ""); 42 | 43 | /// @return Returns a list of the directories that are being watched 44 | std::list directories(); 45 | protected: 46 | Watches mWatches; 47 | Watches mWatchesRemoved; 48 | Watches mWatchesNew; 49 | 50 | /// The last watchid 51 | WatchID mLastWatchID; 52 | 53 | Thread * mThread; 54 | 55 | Mutex mWatchesLock; 56 | 57 | bool pathInWatches( const std::string& path ); 58 | 59 | WatcherStructWin32* pathInWatchesRemoved( const std::string& path ); 60 | 61 | /// Remove all directory watches. 62 | void removeAllWatches(); 63 | 64 | /// Remove needed directory watches. 65 | void removeWatches(); 66 | 67 | void removeWatch(WatcherStructWin32* watch); 68 | private: 69 | void run(); 70 | }; 71 | 72 | } 73 | 74 | #endif 75 | 76 | #endif 77 | -------------------------------------------------------------------------------- /libs/efsw/src/efsw/Lock.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EFSW_LOCK_HPP 2 | #define EFSW_LOCK_HPP 3 | 4 | #include 5 | 6 | namespace efsw { 7 | 8 | /** Simple mutex class */ 9 | class Lock { 10 | public: 11 | explicit Lock( Mutex& mutex ) : 12 | mMutex( mutex ) 13 | { 14 | mMutex.lock(); 15 | } 16 | 17 | ~Lock() 18 | { 19 | mMutex.unlock(); 20 | } 21 | private: 22 | Mutex& mMutex; 23 | }; 24 | 25 | } 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /libs/efsw/src/efsw/Log.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace efsw { namespace Errors { 4 | 5 | static std::string LastError; 6 | 7 | std::string Log::getLastErrorLog() 8 | { 9 | return LastError; 10 | } 11 | 12 | Error Log::createLastError( Error err, std::string log ) 13 | { 14 | switch ( err ) 15 | { 16 | case FileNotFound: LastError = "File not found ( " + log + " )"; break; 17 | case FileRepeated: LastError = "File reapeated in watches ( " + log + " )"; break; 18 | case FileOutOfScope: LastError = "Symlink file out of scope ( " + log + " )"; break; 19 | case FileRemote: LastError = "File is located in a remote file system, use a generic watcher. ( " + log + " )"; break; 20 | case Unspecified: 21 | default: LastError = log; 22 | } 23 | 24 | return err; 25 | } 26 | 27 | }} 28 | -------------------------------------------------------------------------------- /libs/efsw/src/efsw/Mutex.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | namespace efsw { 5 | 6 | Mutex::Mutex() : 7 | mMutexImpl( new Platform::MutexImpl() ) 8 | { 9 | } 10 | 11 | Mutex::~Mutex() 12 | { 13 | efSAFE_DELETE( mMutexImpl ); 14 | } 15 | 16 | void Mutex::lock() 17 | { 18 | mMutexImpl->lock(); 19 | } 20 | 21 | void Mutex::unlock() 22 | { 23 | mMutexImpl->unlock(); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /libs/efsw/src/efsw/Mutex.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EFSW_MUTEX_HPP 2 | #define EFSW_MUTEX_HPP 3 | 4 | #include 5 | 6 | namespace efsw { 7 | 8 | namespace Platform { class MutexImpl; } 9 | 10 | /** Simple mutex class */ 11 | class Mutex { 12 | public: 13 | Mutex(); 14 | 15 | ~Mutex(); 16 | 17 | /** Lock the mutex */ 18 | void lock(); 19 | 20 | /** Unlock the mutex */ 21 | void unlock(); 22 | private: 23 | Platform::MutexImpl * mMutexImpl; 24 | }; 25 | 26 | } 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /libs/efsw/src/efsw/System.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | namespace efsw { 5 | 6 | void System::sleep( const unsigned long& ms ) 7 | { 8 | Platform::System::sleep( ms ); 9 | } 10 | 11 | std::string System::getProcessPath() 12 | { 13 | return Platform::System::getProcessPath(); 14 | } 15 | 16 | void System::maxFD() 17 | { 18 | Platform::System::maxFD(); 19 | } 20 | 21 | Uint64 System::getMaxFD() 22 | { 23 | return Platform::System::getMaxFD(); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /libs/efsw/src/efsw/System.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EFSW_SYSTEM_HPP 2 | #define EFSW_SYSTEM_HPP 3 | 4 | #include 5 | 6 | namespace efsw { 7 | 8 | class System 9 | { 10 | public: 11 | /// Sleep for x milliseconds 12 | static void sleep( const unsigned long& ms ); 13 | 14 | /// @return The process binary path 15 | static std::string getProcessPath(); 16 | 17 | /// Maximize the number of file descriptors allowed per process in the current OS 18 | static void maxFD(); 19 | 20 | /// @return The number of supported file descriptors for the process 21 | static Uint64 getMaxFD(); 22 | }; 23 | 24 | } 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /libs/efsw/src/efsw/Thread.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | namespace efsw { 5 | 6 | Thread::Thread() : 7 | mThreadImpl(NULL), 8 | mEntryPoint(NULL) 9 | { 10 | } 11 | 12 | Thread::~Thread() 13 | { 14 | wait(); 15 | 16 | efSAFE_DELETE( mEntryPoint ); 17 | } 18 | 19 | void Thread::launch() 20 | { 21 | wait(); 22 | 23 | mThreadImpl = new Platform::ThreadImpl( this ); 24 | } 25 | 26 | void Thread::wait() 27 | { 28 | if ( mThreadImpl ) 29 | { 30 | mThreadImpl->wait(); 31 | 32 | efSAFE_DELETE( mThreadImpl ); 33 | } 34 | } 35 | 36 | void Thread::terminate() 37 | { 38 | if ( mThreadImpl ) 39 | { 40 | mThreadImpl->terminate(); 41 | 42 | efSAFE_DELETE( mThreadImpl ); 43 | } 44 | } 45 | 46 | void Thread::run() 47 | { 48 | mEntryPoint->run(); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /libs/efsw/src/efsw/Thread.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EFSW_THREAD_HPP 2 | #define EFSW_THREAD_HPP 3 | 4 | #include 5 | 6 | namespace efsw { 7 | 8 | namespace Platform { class ThreadImpl; } 9 | namespace Private { struct ThreadFunc; } 10 | 11 | /** @brief Thread manager class */ 12 | class Thread { 13 | public: 14 | typedef void (*FuncType)(void*); 15 | 16 | template 17 | Thread( F function ); 18 | 19 | template 20 | Thread( F function, A argument ); 21 | 22 | template 23 | Thread( void(C::*function)(), C* object ); 24 | 25 | virtual ~Thread(); 26 | 27 | /** Launch the thread */ 28 | virtual void launch(); 29 | 30 | /** Wait the thread until end */ 31 | void wait(); 32 | 33 | /** Terminate the thread */ 34 | void terminate(); 35 | protected: 36 | Thread(); 37 | private: 38 | friend class Platform::ThreadImpl; 39 | 40 | /** The virtual function to run in the thread */ 41 | virtual void run(); 42 | 43 | Platform::ThreadImpl * mThreadImpl; ///< OS-specific implementation of the thread 44 | Private::ThreadFunc * mEntryPoint; ///< Abstraction of the function to run 45 | }; 46 | 47 | //! NOTE: Taken from SFML2 threads 48 | namespace Private { 49 | 50 | // Base class for abstract thread functions 51 | struct ThreadFunc 52 | { 53 | virtual ~ThreadFunc() {} 54 | virtual void run() = 0; 55 | }; 56 | 57 | // Specialization using a functor (including free functions) with no argument 58 | template 59 | struct ThreadFunctor : ThreadFunc 60 | { 61 | ThreadFunctor(T functor) : m_functor(functor) {} 62 | virtual void run() {m_functor();} 63 | T m_functor; 64 | }; 65 | 66 | // Specialization using a functor (including free functions) with one argument 67 | template 68 | struct ThreadFunctorWithArg : ThreadFunc 69 | { 70 | ThreadFunctorWithArg(F function, A arg) : m_function(function), m_arg(arg) {} 71 | virtual void run() {m_function(m_arg);} 72 | F m_function; 73 | A m_arg; 74 | }; 75 | 76 | // Specialization using a member function 77 | template 78 | struct ThreadMemberFunc : ThreadFunc 79 | { 80 | ThreadMemberFunc(void(C::*function)(), C* object) : m_function(function), m_object(object) {} 81 | virtual void run() {(m_object->*m_function)();} 82 | void(C::*m_function)(); 83 | C* m_object; 84 | }; 85 | 86 | } 87 | 88 | template 89 | Thread::Thread(F functor) : 90 | mThreadImpl (NULL), 91 | mEntryPoint( new Private::ThreadFunctor(functor) ) 92 | { 93 | } 94 | 95 | template 96 | Thread::Thread(F function, A argument) : 97 | mThreadImpl(NULL), 98 | mEntryPoint( new Private::ThreadFunctorWithArg(function, argument) ) 99 | { 100 | } 101 | 102 | template 103 | Thread::Thread(void(C::*function)(), C* object) : 104 | mThreadImpl(NULL), 105 | mEntryPoint( new Private::ThreadMemberFunc(function, object) ) 106 | { 107 | } 108 | 109 | } 110 | 111 | #endif 112 | -------------------------------------------------------------------------------- /libs/efsw/src/efsw/Watcher.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace efsw { 4 | 5 | Watcher::Watcher() : 6 | ID(0), 7 | Directory(""), 8 | Listener(NULL), 9 | Recursive(false) 10 | { 11 | } 12 | 13 | Watcher::Watcher( WatchID id, std::string directory, FileWatchListener * listener, bool recursive ) : 14 | ID( id ), 15 | Directory( directory ), 16 | Listener( listener ), 17 | Recursive( recursive ) 18 | { 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /libs/efsw/src/efsw/Watcher.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EFSW_WATCHERIMPL_HPP 2 | #define EFSW_WATCHERIMPL_HPP 3 | 4 | #include 5 | #include 6 | 7 | namespace efsw { 8 | 9 | /** @brief Base Watcher class */ 10 | class Watcher 11 | { 12 | public: 13 | Watcher(); 14 | 15 | Watcher( WatchID id, std::string directory, FileWatchListener * listener, bool recursive ); 16 | 17 | virtual ~Watcher() {} 18 | 19 | virtual void watch() {} 20 | 21 | WatchID ID; 22 | std::string Directory; 23 | FileWatchListener * Listener; 24 | bool Recursive; 25 | std::string OldFileName; 26 | }; 27 | 28 | } 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /libs/efsw/src/efsw/WatcherFSEvents.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EFSW_WATCHERINOTIFY_HPP 2 | #define EFSW_WATCHERINOTIFY_HPP 3 | 4 | #include 5 | 6 | #if EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | namespace efsw { 16 | 17 | class FileWatcherFSEvents; 18 | 19 | class FSEvent 20 | { 21 | public: 22 | FSEvent( std::string path, long flags, Uint64 id ) : 23 | Path( path ), 24 | Flags( flags ), 25 | Id ( id ) 26 | { 27 | } 28 | 29 | std::string Path; 30 | long Flags; 31 | Uint64 Id; 32 | }; 33 | 34 | class WatcherFSEvents : public Watcher 35 | { 36 | public: 37 | WatcherFSEvents(); 38 | 39 | WatcherFSEvents( WatchID id, std::string directory, FileWatchListener * listener, bool recursive, WatcherFSEvents * parent = NULL ); 40 | 41 | ~WatcherFSEvents(); 42 | 43 | void init(); 44 | 45 | void initAsync(); 46 | 47 | void handleActions( std::vector & events ); 48 | 49 | void process(); 50 | 51 | FileWatcherFSEvents * FWatcher; 52 | 53 | FSEventStreamRef FSStream; 54 | protected: 55 | void handleAddModDel( const Uint32 &flags, const std::string &path, std::string &dirPath, std::string &filePath ); 56 | 57 | WatcherGeneric * WatcherGen; 58 | 59 | bool initializedAsync; 60 | 61 | std::set DirsChanged; 62 | 63 | void sendFileAction( WatchID watchid, const std::string& dir, const std::string& filename, Action action, std::string oldFilename = "" ); 64 | }; 65 | 66 | } 67 | 68 | #endif 69 | 70 | #endif 71 | -------------------------------------------------------------------------------- /libs/efsw/src/efsw/WatcherGeneric.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | namespace efsw 6 | { 7 | 8 | WatcherGeneric::WatcherGeneric( WatchID id, const std::string& directory, FileWatchListener * fwl, FileWatcherImpl * fw, bool recursive ) : 9 | Watcher( id, directory, fwl, recursive ), 10 | WatcherImpl( fw ), 11 | DirWatch( NULL ) 12 | { 13 | FileSystem::dirAddSlashAtEnd( Directory ); 14 | 15 | DirWatch = new DirWatcherGeneric( NULL, this, directory, recursive, false ); 16 | 17 | DirWatch->addChilds( false ); 18 | } 19 | 20 | WatcherGeneric::~WatcherGeneric() 21 | { 22 | efSAFE_DELETE( DirWatch ); 23 | } 24 | 25 | void WatcherGeneric::watch() 26 | { 27 | DirWatch->watch(); 28 | } 29 | 30 | void WatcherGeneric::watchDir( std::string dir ) 31 | { 32 | DirWatch->watchDir( dir ); 33 | } 34 | 35 | bool WatcherGeneric::pathInWatches( std::string path ) 36 | { 37 | return DirWatch->pathInWatches( path ); 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /libs/efsw/src/efsw/WatcherGeneric.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EFSW_WATCHERGENERIC_HPP 2 | #define EFSW_WATCHERGENERIC_HPP 3 | 4 | #include 5 | 6 | namespace efsw 7 | { 8 | 9 | class DirWatcherGeneric; 10 | 11 | class WatcherGeneric : public Watcher 12 | { 13 | public: 14 | FileWatcherImpl * WatcherImpl; 15 | DirWatcherGeneric * DirWatch; 16 | 17 | WatcherGeneric( WatchID id, const std::string& directory, FileWatchListener * fwl, FileWatcherImpl * fw, bool recursive ); 18 | 19 | ~WatcherGeneric(); 20 | 21 | void watch(); 22 | 23 | void watchDir( std::string dir ); 24 | 25 | bool pathInWatches( std::string path ); 26 | }; 27 | 28 | } 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /libs/efsw/src/efsw/WatcherInotify.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace efsw { 4 | 5 | WatcherInotify::WatcherInotify() : 6 | Watcher(), 7 | Parent( NULL ) 8 | { 9 | } 10 | 11 | WatcherInotify::WatcherInotify( WatchID id, std::string directory, FileWatchListener * listener, bool recursive, WatcherInotify * parent ) : 12 | Watcher( id, directory, listener, recursive ), 13 | Parent( parent ), 14 | DirInfo( directory ) 15 | { 16 | } 17 | 18 | bool WatcherInotify::inParentTree( WatcherInotify * parent ) 19 | { 20 | WatcherInotify * tNext = Parent; 21 | 22 | while ( NULL != tNext ) 23 | { 24 | if ( tNext == parent ) 25 | { 26 | return true; 27 | } 28 | 29 | tNext = tNext->Parent; 30 | } 31 | 32 | return false; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /libs/efsw/src/efsw/WatcherInotify.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EFSW_WATCHERINOTIFY_HPP 2 | #define EFSW_WATCHERINOTIFY_HPP 3 | 4 | #include 5 | #include 6 | 7 | namespace efsw { 8 | 9 | class WatcherInotify : public Watcher 10 | { 11 | public: 12 | WatcherInotify(); 13 | 14 | WatcherInotify( WatchID id, std::string directory, FileWatchListener * listener, bool recursive, WatcherInotify * parent = NULL ); 15 | 16 | bool inParentTree( WatcherInotify * parent ); 17 | 18 | WatcherInotify * Parent; 19 | 20 | FileInfo DirInfo; 21 | }; 22 | 23 | } 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /libs/efsw/src/efsw/WatcherKqueue.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EFSW_WATCHEROSX_HPP 2 | #define EFSW_WATCHEROSX_HPP 3 | 4 | #include 5 | 6 | #if EFSW_PLATFORM == EFSW_PLATFORM_KQUEUE || EFSW_PLATFORM == EFSW_PLATFORM_FSEVENTS 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | namespace efsw 15 | { 16 | 17 | class FileWatcherKqueue; 18 | class WatcherKqueue; 19 | 20 | typedef struct kevent KEvent; 21 | 22 | /// type for a map from WatchID to WatcherKqueue pointer 23 | typedef std::map WatchMap; 24 | 25 | class WatcherKqueue : public Watcher 26 | { 27 | public: 28 | WatcherKqueue( WatchID watchid, const std::string& dirname, FileWatchListener* listener, bool recursive, FileWatcherKqueue * watcher, WatcherKqueue * parent = NULL ); 29 | 30 | virtual ~WatcherKqueue(); 31 | 32 | void addFile( const std::string& name, bool emitEvents = true ); 33 | 34 | void removeFile( const std::string& name, bool emitEvents = true ); 35 | 36 | // called when the directory is actually changed 37 | // means a file has been added or removed 38 | // rescans the watched directory adding/removing files and sending notices 39 | void rescan(); 40 | 41 | void handleAction( const std::string& filename, efsw::Action action, const std::string& oldFilename = "" ); 42 | 43 | void handleFolderAction( std::string filename, efsw::Action action, const std::string& oldFilename = "" ); 44 | 45 | void addAll(); 46 | 47 | void removeAll(); 48 | 49 | WatchID watchingDirectory( std::string dir ); 50 | 51 | void watch(); 52 | 53 | WatchID addWatch(const std::string& directory, FileWatchListener* watcher, bool recursive, WatcherKqueue * parent); 54 | 55 | void removeWatch (WatchID watchid ); 56 | 57 | bool initOK(); 58 | 59 | int lastErrno(); 60 | protected: 61 | WatchMap mWatches; 62 | int mLastWatchID; 63 | 64 | // index 0 is always the directory 65 | std::vector mChangeList; 66 | size_t mChangeListCount; 67 | DirectorySnapshot mDirSnap; 68 | 69 | /// The descriptor for the kqueue 70 | int mKqueue; 71 | 72 | FileWatcherKqueue * mWatcher; 73 | 74 | WatcherKqueue * mParent; 75 | 76 | bool mInitOK; 77 | int mErrno; 78 | 79 | bool pathInWatches( const std::string& path ); 80 | 81 | bool pathInParent( const std::string& path ); 82 | 83 | Watcher * findWatcher( const std::string path ); 84 | 85 | void moveDirectory( std::string oldPath, std::string newPath, bool emitEvents = true ); 86 | 87 | void sendDirChanged(); 88 | }; 89 | 90 | } 91 | 92 | #endif 93 | 94 | #endif 95 | -------------------------------------------------------------------------------- /libs/efsw/src/efsw/WatcherWin32.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EFSW_WATCHERWIN32_HPP 2 | #define EFSW_WATCHERWIN32_HPP 3 | 4 | #include 5 | #include 6 | 7 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 8 | 9 | #include 10 | 11 | #ifdef EFSW_COMPILER_MSVC 12 | #pragma comment(lib, "comctl32.lib") 13 | #pragma comment(lib, "user32.lib") 14 | #pragma comment(lib, "ole32.lib") 15 | 16 | // disable secure warnings 17 | #pragma warning (disable: 4996) 18 | #endif 19 | 20 | namespace efsw 21 | { 22 | 23 | class WatcherWin32; 24 | 25 | /// Internal watch data 26 | struct WatcherStructWin32 27 | { 28 | OVERLAPPED Overlapped; 29 | WatcherWin32 * Watch; 30 | }; 31 | 32 | class cLastModifiedEvent 33 | { 34 | public: 35 | cLastModifiedEvent() {} 36 | FileInfo file; 37 | std::string fileName; 38 | }; 39 | 40 | bool RefreshWatch(WatcherStructWin32* pWatch); 41 | 42 | void CALLBACK WatchCallback(DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped); 43 | 44 | void DestroyWatch(WatcherStructWin32* pWatch); 45 | 46 | WatcherStructWin32* CreateWatch(LPCWSTR szDirectory, bool recursive, DWORD NotifyFilter); 47 | 48 | class WatcherWin32 : public Watcher 49 | { 50 | public: 51 | WatcherWin32() : 52 | Struct( NULL ), 53 | DirHandle( NULL ), 54 | lParam( 0 ), 55 | NotifyFilter( 0 ), 56 | StopNow( false ), 57 | Watch( NULL ), 58 | DirName( NULL ) 59 | { 60 | } 61 | 62 | WatcherStructWin32 * Struct; 63 | HANDLE DirHandle; 64 | BYTE mBuffer[63 * 1024]; // do NOT make this bigger than 64K because it will fail if the folder being watched is on the network! (see http://msdn.microsoft.com/en-us/library/windows/desktop/aa365465(v=vs.85).aspx) 65 | LPARAM lParam; 66 | DWORD NotifyFilter; 67 | bool StopNow; 68 | FileWatcherImpl* Watch; 69 | char* DirName; 70 | cLastModifiedEvent LastModifiedEvent; 71 | }; 72 | 73 | } 74 | 75 | #endif 76 | 77 | #endif 78 | -------------------------------------------------------------------------------- /libs/efsw/src/efsw/platform/platformimpl.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EFSW_PLATFORMIMPL_HPP 2 | #define EFSW_PLATFORMIMPL_HPP 3 | 4 | #include 5 | 6 | #if defined( EFSW_PLATFORM_POSIX ) 7 | #include 8 | #include 9 | #include 10 | #include 11 | #elif EFSW_PLATFORM == EFSW_PLATFORM_WIN32 12 | #include 13 | #include 14 | #include 15 | #include 16 | #else 17 | #error Thread, Mutex, and System not implemented for this platform. 18 | #endif 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /libs/efsw/src/efsw/platform/posix/FileSystemImpl.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EFSW_FILESYSTEMIMPLPOSIX_HPP 2 | #define EFSW_FILESYSTEMIMPLPOSIX_HPP 3 | 4 | #include 5 | #include 6 | 7 | #if defined( EFSW_PLATFORM_POSIX ) 8 | 9 | namespace efsw { namespace Platform { 10 | 11 | class FileSystem 12 | { 13 | public: 14 | static FileInfoMap filesInfoFromPath( const std::string& path ); 15 | 16 | static char getOSSlash(); 17 | 18 | static bool isDirectory( const std::string& path ); 19 | 20 | static bool isRemoteFS( const std::string& directory ); 21 | 22 | static bool changeWorkingDirectory( const std::string & path ); 23 | 24 | static std::string getCurrentWorkingDirectory(); 25 | }; 26 | 27 | }} 28 | 29 | #endif 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /libs/efsw/src/efsw/platform/posix/MutexImpl.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #if defined( EFSW_PLATFORM_POSIX ) 4 | 5 | namespace efsw { namespace Platform { 6 | 7 | MutexImpl::MutexImpl() 8 | { 9 | pthread_mutexattr_t attributes; 10 | pthread_mutexattr_init(&attributes); 11 | pthread_mutexattr_settype(&attributes, PTHREAD_MUTEX_RECURSIVE); 12 | pthread_mutex_init(&mMutex, &attributes); 13 | } 14 | 15 | MutexImpl::~MutexImpl() 16 | { 17 | pthread_mutex_destroy(&mMutex); 18 | } 19 | 20 | void MutexImpl::lock() 21 | { 22 | pthread_mutex_lock(&mMutex); 23 | } 24 | 25 | void MutexImpl::unlock() 26 | { 27 | pthread_mutex_unlock(&mMutex); 28 | } 29 | 30 | }} 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /libs/efsw/src/efsw/platform/posix/MutexImpl.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EFSW_MUTEXIMPLPOSIX_HPP 2 | #define EFSW_MUTEXIMPLPOSIX_HPP 3 | 4 | #include 5 | 6 | #if defined( EFSW_PLATFORM_POSIX ) 7 | 8 | #include 9 | 10 | namespace efsw { namespace Platform { 11 | 12 | class MutexImpl 13 | { 14 | public: 15 | MutexImpl(); 16 | 17 | ~MutexImpl(); 18 | 19 | void lock(); 20 | 21 | void unlock(); 22 | private: 23 | pthread_mutex_t mMutex; 24 | }; 25 | 26 | }} 27 | 28 | #endif 29 | 30 | #endif 31 | 32 | -------------------------------------------------------------------------------- /libs/efsw/src/efsw/platform/posix/SystemImpl.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EFSW_SYSTEMIMPLPOSIX_HPP 2 | #define EFSW_SYSTEMIMPLPOSIX_HPP 3 | 4 | #include 5 | 6 | #if defined( EFSW_PLATFORM_POSIX ) 7 | 8 | namespace efsw { namespace Platform { 9 | 10 | class System 11 | { 12 | public: 13 | static void sleep( const unsigned long& ms ); 14 | 15 | static std::string getProcessPath(); 16 | 17 | static void maxFD(); 18 | 19 | static Uint64 getMaxFD(); 20 | }; 21 | 22 | }} 23 | 24 | #endif 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /libs/efsw/src/efsw/platform/posix/ThreadImpl.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #if defined( EFSW_PLATFORM_POSIX ) 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | namespace efsw { namespace Platform { 11 | 12 | ThreadImpl::ThreadImpl( Thread * owner ) : 13 | mIsActive(false) 14 | { 15 | mIsActive = pthread_create( &mThread, NULL, &ThreadImpl::entryPoint, owner ) == 0; 16 | 17 | if ( !mIsActive ) 18 | { 19 | efDEBUG( "Failed to create thread\n" ); 20 | } 21 | } 22 | 23 | void ThreadImpl::wait() 24 | { 25 | // Wait for the thread to finish, no timeout 26 | if ( mIsActive ) 27 | { 28 | assert( pthread_equal( pthread_self(), mThread ) == 0 ); 29 | 30 | pthread_join( mThread, NULL ); 31 | 32 | mIsActive = false; // Reset the thread state 33 | } 34 | } 35 | 36 | void ThreadImpl::terminate() 37 | { 38 | if ( mIsActive ) 39 | { 40 | #if !defined( __ANDROID__ ) && !defined( ANDROID ) 41 | pthread_cancel( mThread ); 42 | #else 43 | pthread_kill( mThread , SIGUSR1 ); 44 | #endif 45 | 46 | mIsActive = false; 47 | } 48 | } 49 | 50 | void * ThreadImpl::entryPoint( void * userData ) 51 | { 52 | // The Thread instance is stored in the user data 53 | Thread * owner = static_cast( userData ); 54 | 55 | // Tell the thread to handle cancel requests immediatly 56 | #ifdef PTHREAD_CANCEL_ASYNCHRONOUS 57 | pthread_setcanceltype( PTHREAD_CANCEL_ASYNCHRONOUS, NULL ); 58 | #endif 59 | 60 | // Forward to the owner 61 | owner->run(); 62 | 63 | return NULL; 64 | } 65 | 66 | }} 67 | 68 | #endif 69 | -------------------------------------------------------------------------------- /libs/efsw/src/efsw/platform/posix/ThreadImpl.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EFSW_THREADIMPLPOSIX_HPP 2 | #define EFSW_THREADIMPLPOSIX_HPP 3 | 4 | #include 5 | 6 | #if defined( EFSW_PLATFORM_POSIX ) 7 | 8 | #include 9 | 10 | namespace efsw { 11 | 12 | class Thread; 13 | 14 | namespace Platform { 15 | 16 | class ThreadImpl 17 | { 18 | public: 19 | ThreadImpl( Thread * owner ); 20 | 21 | void wait(); 22 | 23 | void terminate(); 24 | protected: 25 | static void * entryPoint( void* userData ); 26 | 27 | pthread_t mThread; 28 | bool mIsActive; 29 | }; 30 | 31 | }} 32 | 33 | #endif 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /libs/efsw/src/efsw/platform/win/FileSystemImpl.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EFSW_FILESYSTEMIMPLWIN_HPP 2 | #define EFSW_FILESYSTEMIMPLWIN_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 9 | 10 | namespace efsw { namespace Platform { 11 | 12 | class FileSystem 13 | { 14 | public: 15 | static FileInfoMap filesInfoFromPath( const std::string& path ); 16 | 17 | static char getOSSlash(); 18 | 19 | static bool isDirectory( const std::string& path ); 20 | 21 | static bool isRemoteFS( const std::string& directory ); 22 | 23 | static bool changeWorkingDirectory( const std::string & path ); 24 | 25 | static std::string getCurrentWorkingDirectory(); 26 | }; 27 | 28 | }} 29 | 30 | #endif 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /libs/efsw/src/efsw/platform/win/MutexImpl.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 4 | 5 | namespace efsw { namespace Platform { 6 | 7 | MutexImpl::MutexImpl() 8 | { 9 | InitializeCriticalSection(&mMutex); 10 | } 11 | 12 | MutexImpl::~MutexImpl() 13 | { 14 | DeleteCriticalSection(&mMutex); 15 | } 16 | 17 | void MutexImpl::lock() 18 | { 19 | EnterCriticalSection(&mMutex); 20 | } 21 | 22 | void MutexImpl::unlock() 23 | { 24 | LeaveCriticalSection(&mMutex); 25 | } 26 | 27 | }} 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /libs/efsw/src/efsw/platform/win/MutexImpl.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EFSW_MUTEXIMPLWIN_HPP 2 | #define EFSW_MUTEXIMPLWIN_HPP 3 | 4 | #include 5 | 6 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 7 | 8 | #ifndef WIN32_LEAN_AND_MEAN 9 | #define WIN32_LEAN_AND_MEAN 10 | #endif 11 | #include 12 | 13 | namespace efsw { namespace Platform { 14 | 15 | class MutexImpl 16 | { 17 | public: 18 | MutexImpl(); 19 | 20 | ~MutexImpl(); 21 | 22 | void lock(); 23 | 24 | void unlock(); 25 | private: 26 | CRITICAL_SECTION mMutex; 27 | }; 28 | 29 | }} 30 | 31 | #endif 32 | 33 | #endif 34 | 35 | -------------------------------------------------------------------------------- /libs/efsw/src/efsw/platform/win/SystemImpl.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 5 | 6 | #ifndef WIN32_LEAN_AND_MEAN 7 | #define WIN32_LEAN_AND_MEAN 8 | #endif 9 | #include 10 | #include 11 | 12 | namespace efsw { namespace Platform { 13 | 14 | void System::sleep( const unsigned long& ms ) 15 | { 16 | ::Sleep( ms ); 17 | } 18 | 19 | std::string System::getProcessPath() 20 | { 21 | // Get path to executable: 22 | WCHAR szDrive[_MAX_DRIVE]; 23 | WCHAR szDir[_MAX_DIR]; 24 | WCHAR szFilename[_MAX_DIR]; 25 | WCHAR szExt[_MAX_DIR]; 26 | std::wstring dllName( _MAX_DIR, 0 ); 27 | 28 | GetModuleFileNameW(0, &dllName[0], _MAX_PATH); 29 | 30 | #ifdef EFSW_COMPILER_MSVC 31 | _wsplitpath_s( dllName.c_str(), szDrive, _MAX_DRIVE, szDir, _MAX_DIR, szFilename, _MAX_DIR, szExt, _MAX_DIR ); 32 | #else 33 | _wsplitpath( dllName.c_str(), szDrive, szDir, szFilename, szExt); 34 | #endif 35 | 36 | return String( szDrive ).toUtf8() + String( szDir ).toUtf8(); 37 | } 38 | 39 | void System::maxFD() 40 | { 41 | } 42 | 43 | Uint64 System::getMaxFD() 44 | { // Number of ReadDirectory per thread 45 | return 60; 46 | } 47 | 48 | }} 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /libs/efsw/src/efsw/platform/win/SystemImpl.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EFSW_SYSTEMIMPLWIN_HPP 2 | #define EFSW_SYSTEMIMPLWIN_HPP 3 | 4 | #include 5 | 6 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 7 | 8 | namespace efsw { namespace Platform { 9 | 10 | class System 11 | { 12 | public: 13 | static void sleep( const unsigned long& ms ); 14 | 15 | static std::string getProcessPath(); 16 | 17 | static void maxFD(); 18 | 19 | static Uint64 getMaxFD(); 20 | }; 21 | 22 | }} 23 | 24 | #endif 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /libs/efsw/src/efsw/platform/win/ThreadImpl.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 6 | 7 | #include 8 | 9 | namespace efsw { namespace Platform { 10 | 11 | ThreadImpl::ThreadImpl( Thread *owner ) 12 | { 13 | mThread = reinterpret_cast( _beginthreadex( NULL, 0, &ThreadImpl::entryPoint, owner, 0, &mThreadId ) ); 14 | 15 | if ( !mThread ) 16 | { 17 | efDEBUG( "Failed to create thread\n" ); 18 | } 19 | } 20 | 21 | ThreadImpl::~ThreadImpl() 22 | { 23 | if ( mThread ) 24 | { 25 | CloseHandle( mThread ); 26 | } 27 | } 28 | 29 | void ThreadImpl::wait() 30 | { 31 | // Wait for the thread to finish, no timeout 32 | if ( mThread ) 33 | { 34 | assert( mThreadId != GetCurrentThreadId() ); // A thread cannot wait for itself! 35 | 36 | WaitForSingleObject( mThread, INFINITE ); 37 | } 38 | } 39 | 40 | void ThreadImpl::terminate() 41 | { 42 | if ( mThread ) 43 | { 44 | TerminateThread( mThread, 0 ); 45 | } 46 | } 47 | 48 | unsigned int __stdcall ThreadImpl::entryPoint( void * userData ) 49 | { 50 | // The Thread instance is stored in the user data 51 | Thread * owner = static_cast( userData ); 52 | 53 | // Forward to the owner 54 | owner->run(); 55 | 56 | // Optional, but it is cleaner 57 | _endthreadex(0); 58 | 59 | return 0; 60 | } 61 | 62 | }} 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /libs/efsw/src/efsw/platform/win/ThreadImpl.hpp: -------------------------------------------------------------------------------- 1 | #ifndef EFSW_THREADIMPLWIN_HPP 2 | #define EFSW_THREADIMPLWIN_HPP 3 | 4 | #include 5 | 6 | #if EFSW_PLATFORM == EFSW_PLATFORM_WIN32 7 | 8 | #ifndef WIN32_LEAN_AND_MEAN 9 | #define WIN32_LEAN_AND_MEAN 10 | #endif 11 | #include 12 | #include 13 | 14 | namespace efsw { 15 | 16 | class Thread; 17 | 18 | namespace Platform { 19 | 20 | class ThreadImpl 21 | { 22 | public: 23 | ThreadImpl( Thread * owner ); 24 | 25 | ~ThreadImpl(); 26 | 27 | void wait(); 28 | 29 | void terminate(); 30 | protected: 31 | static unsigned int __stdcall entryPoint(void* userData); 32 | 33 | HANDLE mThread; 34 | unsigned int mThreadId; 35 | }; 36 | 37 | }} 38 | 39 | #endif 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /libs/json/LICENSE.MIT: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2013-2019 Niels Lohmann 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /libs/subhook/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012-2018 Zeex 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, 8 | this list of conditions and the following disclaimer. 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 14 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 17 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 19 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 20 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 21 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 22 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 23 | POSSIBILITY OF SUCH DAMAGE. 24 | -------------------------------------------------------------------------------- /libs/subhook/subhook.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012-2018 Zeex 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 18 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #include "subhook.h" 28 | #include "subhook_private.h" 29 | 30 | subhook_disasm_handler_t subhook_disasm_handler = NULL; 31 | 32 | SUBHOOK_EXPORT void *SUBHOOK_API subhook_get_src(subhook_t hook) { 33 | if (hook == NULL) { 34 | return NULL; 35 | } 36 | return hook->src; 37 | } 38 | 39 | SUBHOOK_EXPORT void *SUBHOOK_API subhook_get_dst(subhook_t hook) { 40 | if (hook == NULL) { 41 | return NULL; 42 | } 43 | return hook->dst; 44 | } 45 | 46 | SUBHOOK_EXPORT void *SUBHOOK_API subhook_get_trampoline(subhook_t hook) { 47 | if (hook == NULL) { 48 | return NULL; 49 | } 50 | return hook->trampoline; 51 | } 52 | 53 | SUBHOOK_EXPORT int SUBHOOK_API subhook_is_installed(subhook_t hook) { 54 | if (hook == NULL) { 55 | return false; 56 | } 57 | return hook->installed; 58 | } 59 | 60 | SUBHOOK_EXPORT void SUBHOOK_API subhook_set_disasm_handler( 61 | subhook_disasm_handler_t handler) { 62 | subhook_disasm_handler = handler; 63 | } 64 | 65 | #ifndef SUBHOOK_SEPARATE_SOURCE_FILES 66 | 67 | #if defined SUBHOOK_WINDOWS 68 | #include "subhook_windows.c" 69 | #elif defined SUBHOOK_UNIX 70 | #include "subhook_unix.c" 71 | #endif 72 | 73 | #if defined SUBHOOK_X86 || defined SUBHOOK_X86_64 74 | #include "subhook_x86.c" 75 | #endif 76 | 77 | #endif 78 | -------------------------------------------------------------------------------- /libs/subhook/subhook_private.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012-2018 Zeex 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 18 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #ifndef SUBHOOK_PRIVATE_H 28 | #define SUBHOOK_PRIVATE_H 29 | 30 | #include 31 | 32 | #ifndef true 33 | #define true 1 34 | #endif 35 | #ifndef false 36 | #define false 0 37 | #endif 38 | 39 | struct subhook_struct { 40 | int installed; 41 | void *src; 42 | void *dst; 43 | subhook_flags_t flags; 44 | void *code; 45 | void *trampoline; 46 | size_t jmp_size; 47 | size_t trampoline_size; 48 | size_t trampoline_len; 49 | }; 50 | 51 | void *subhook_unprotect(void *address, size_t size); 52 | 53 | #endif /* SUBHOOK_PRIVATE_H */ 54 | -------------------------------------------------------------------------------- /libs/subhook/subhook_unix.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012-2018 Zeex 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 18 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | void *subhook_unprotect(void *address, size_t size) { 32 | long pagesize; 33 | 34 | pagesize = sysconf(_SC_PAGESIZE); 35 | address = (void *)((long)address & ~(pagesize - 1)); 36 | 37 | if (mprotect(address, size, PROT_READ | PROT_WRITE | PROT_EXEC) == 0) { 38 | return address; 39 | } else { 40 | return NULL; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /libs/subhook/subhook_windows.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2012-2018 Zeex 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright notice, 9 | * this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 18 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #include 28 | #include 29 | 30 | void *subhook_unprotect(void *address, size_t size) { 31 | DWORD old; 32 | 33 | if (VirtualProtect(address, size, PAGE_EXECUTE_READWRITE, &old) != 0) { 34 | return address; 35 | } else { 36 | return NULL; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /libs/teenypath/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Tableau 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /libs/teenypath/README.md: -------------------------------------------------------------------------------- 1 | # TeenyPath 2 | [![As-Is](https://img.shields.io/badge/Support%20Level-As--Is-e8762c.svg)](https://www.tableau.com/support-levels-it-and-developer-tools) [![Build Status](https://travis-ci.org/tableau/teenypath.svg?branch=master)](https://travis-ci.org/tableau/teenypath) 3 | 4 | TeenyPath is a small (single file) cross-platform (Windows, Apple, Linux) filesystem abstraction for C++. 5 | 6 | * [Why TeenyPath?](#why-teenypath) 7 | * [Demo](#demo) 8 | * [Get started](#get-started) 9 | * [Prerequisites](#prerequisites) 10 | * [Compilation](#compilation) 11 | * [Link against](#link-against) 12 | * [Support](#support) 13 | * [Contributions](#contributions) 14 | 15 | # Why TeenyPath? 16 | 17 | TeenyPath lets you avoid using a gigantic library (Boost, Qt, the not-fully-done filesystem.h in future C++ standards) to write cross-platform code which has to touch the filesystem. 18 | 19 | # Demo/Samples 20 | 21 | ```cpp 22 | using namespace TeenyPath; 23 | 24 | const path cwd = current_path(); 25 | assert(cwd.is_directory()); 26 | assert(!cwd.is_symlink()); 27 | assert(!cwd.is_regular_file()); 28 | ``` 29 | 30 | # Get started 31 | 32 | This section describes how to compile and link against TeenyPath. 33 | 34 | ## Prerequistes 35 | 36 | To work with TeenyPath, you need the following: 37 | 38 | * A C++ compiler (clang, gcc, msvc). 39 | * A C++ linker (lld, ld, link.exe). 40 | * [CMake](https://cmake.org). 41 | 42 | ## Compilation 43 | 44 | ``` 45 | cmake -H. -B./build 46 | cmake --build build 47 | ``` 48 | 49 | ## Link against 50 | 51 | Add `-I/path/to/teenypath.h` to your compilation command, and add `-L/path/to/libteenypath.so` to your command line options for linking. 52 | 53 | # Support 54 | 55 | TeenyPath is made available AS-IS with no support. Any bugs that you discover should be filed in the TeenyPath [issue tracker](/issues). 56 | 57 | # Contributions 58 | 59 | Code contributions and improvements by the community are welcomed! 60 | See the LICENSE file for current open-source licensing and use information. 61 | 62 | Before we can accept pull requests from contributors, we require a signed [Contributor License Agreement (CLA)](http://tableau.github.io/contributing.html), 63 | -------------------------------------------------------------------------------- /libs/teenypath/include/teenypath.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace TeenyPath { 7 | 8 | class path { 9 | public: 10 | path() {} 11 | path(const std::string& s); 12 | path(const std::wstring& s); 13 | path(const char* s); 14 | path(const wchar_t* s); 15 | 16 | bool exists() const; 17 | bool is_absolute() const; 18 | bool is_directory() const; 19 | bool is_empty() const; 20 | // Checks if the path has any references to "." or ".." 21 | bool is_lexically_normal() const; 22 | bool is_regular_file() const; 23 | // Checks if the path is rooted to a UNC root "//", Unix root "/", or, 24 | // for Windows only, a Windows root "x:/" 25 | bool is_root() const; 26 | bool is_symlink() const; 27 | 28 | std::string extension() const; 29 | std::string filename() const; 30 | std::string string() const; 31 | 32 | // These are used to convert the Windows-style '\\' to '/' and back. 33 | std::string generic_string() const; 34 | std::string native_string() const; 35 | 36 | std::wstring wfilename() const; 37 | std::wstring wstring() const; 38 | 39 | // Will resolve references to "." or "..". Will not resolve symlinks. 40 | path lexically_normalized() const; 41 | path parent_path() const; 42 | // Will take a relative path or absolute path with symlinks and resolve 43 | // all "." and ".." and symlinks to get the real path on disk. 44 | path resolve_absolute() const; 45 | path trim_trailing_slashes() const; 46 | 47 | void replace_extension(const std::string& new_extension); 48 | 49 | path& operator/=(const path& p); 50 | path& operator/=(const std::string& s); 51 | 52 | private: 53 | std::string m_path; 54 | 55 | path get_root() const; 56 | std::vector split() const; 57 | }; 58 | 59 | path operator/(const path& lhs, const path& rhs); 60 | path operator/(const path& lhs, const std::string& rhs); 61 | path operator/(const path& lhs, const char* rhs); 62 | bool operator==(const path& lhs, const path& rhs); 63 | 64 | std::string joinPathList(const std::vector& pathList); 65 | std::vector splitPathList(const std::string& pathList); 66 | std::vector ls(const path& p); 67 | } 68 | -------------------------------------------------------------------------------- /libs/tiny-process-library/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015-2018 Ole Christian Eidheim 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /libs/tiny-process-library/README.md: -------------------------------------------------------------------------------- 1 | # tiny-process-library 2 | A small platform independent library making it simple to create and stop new processes in C++, as well as writing to stdin and reading from stdout and stderr of a new process. 3 | 4 | This library was created for, and is used by the C++ IDE project [juCi++](https://gitlab.com/cppit/jucipp). 5 | 6 | ### Features 7 | * No external dependencies 8 | * Simple to use 9 | * Platform independent 10 | * Creating processes using executables is supported on all platforms 11 | * Creating processes using functions is only possible on Unix-like systems 12 | * Read separately from stdout and stderr using anonymous functions 13 | * Write to stdin 14 | * Kill a running process (SIGTERM is supported on Unix-like systems) 15 | * Correctly closes file descriptors/handles 16 | 17 | ### Usage 18 | See [examples.cpp](examples.cpp). 19 | 20 | ### Get, compile and run 21 | 22 | #### Unix-like systems 23 | ```sh 24 | git clone http://gitlab.com/eidheim/tiny-process-library 25 | cd tiny-process-library 26 | mkdir build 27 | cd build 28 | cmake .. 29 | make 30 | ./examples 31 | ``` 32 | 33 | #### Windows with MSYS2 (https://msys2.github.io/) 34 | ```sh 35 | git clone http://gitlab.com/eidheim/tiny-process-library 36 | cd tiny-process-library 37 | mkdir build 38 | cd build 39 | cmake -G"MSYS Makefiles" .. 40 | make 41 | ./examples 42 | ``` 43 | 44 | ### Coding style 45 | Due to poor lambda support in clang-format, a custom clang-format is used with the following patch applied: 46 | ```diff 47 | diff --git a/lib/Format/ContinuationIndenter.cpp b/lib/Format/ContinuationIndenter.cpp 48 | index bb8efd61a3..e80a487055 100644 49 | --- a/lib/Format/ContinuationIndenter.cpp 50 | +++ b/lib/Format/ContinuationIndenter.cpp 51 | @@ -276,6 +276,8 @@ LineState ContinuationIndenter::getInitialState(unsigned FirstIndent, 52 | } 53 | 54 | bool ContinuationIndenter::canBreak(const LineState &State) { 55 | + if(Style.ColumnLimit==0) 56 | + return true; 57 | const FormatToken &Current = *State.NextToken; 58 | const FormatToken &Previous = *Current.Previous; 59 | assert(&Previous == Current.Previous); 60 | @@ -325,6 +327,8 @@ bool ContinuationIndenter::canBreak(const LineState &State) { 61 | } 62 | 63 | bool ContinuationIndenter::mustBreak(const LineState &State) { 64 | + if(Style.ColumnLimit==0) 65 | + return false; 66 | const FormatToken &Current = *State.NextToken; 67 | const FormatToken &Previous = *Current.Previous; 68 | if (Current.MustBreakBefore || Current.is(TT_InlineASMColon)) 69 | ``` 70 | -------------------------------------------------------------------------------- /libs/tiny-process-library/process.cpp: -------------------------------------------------------------------------------- 1 | #include "process.hpp" 2 | 3 | namespace TinyProcessLib { 4 | 5 | Process::Process(const std::vector &arguments, const string_type &path, 6 | std::function read_stdout, 7 | std::function read_stderr, 8 | bool open_stdin, const Config &config) noexcept 9 | : closed(true), read_stdout(std::move(read_stdout)), read_stderr(std::move(read_stderr)), open_stdin(open_stdin), config(config) { 10 | open(arguments, path); 11 | async_read(); 12 | } 13 | 14 | Process::Process(const string_type &command, const string_type &path, 15 | std::function read_stdout, 16 | std::function read_stderr, 17 | bool open_stdin, const Config &config) noexcept 18 | : closed(true), read_stdout(std::move(read_stdout)), read_stderr(std::move(read_stderr)), open_stdin(open_stdin), config(config) { 19 | open(command, path); 20 | async_read(); 21 | } 22 | 23 | Process::Process(const std::vector &arguments, const string_type &path, 24 | const environment_type &environment, 25 | std::function read_stdout, 26 | std::function read_stderr, 27 | bool open_stdin, const Config &config) noexcept 28 | : closed(true), read_stdout(std::move(read_stdout)), read_stderr(std::move(read_stderr)), open_stdin(open_stdin), config(config) { 29 | open(arguments, path, &environment); 30 | async_read(); 31 | } 32 | 33 | Process::Process(const string_type &command, const string_type &path, 34 | const environment_type &environment, 35 | std::function read_stdout, 36 | std::function read_stderr, 37 | bool open_stdin, const Config &config) noexcept 38 | : closed(true), read_stdout(std::move(read_stdout)), read_stderr(std::move(read_stderr)), open_stdin(open_stdin), config(config) { 39 | open(command, path, &environment); 40 | async_read(); 41 | } 42 | 43 | Process::~Process() noexcept { 44 | close_fds(); 45 | } 46 | 47 | Process::id_type Process::get_id() const noexcept { 48 | return data.id; 49 | } 50 | 51 | bool Process::write(const std::string &data) { 52 | return write(data.c_str(), data.size()); 53 | } 54 | 55 | } // namespace TinyProcessLib 56 | -------------------------------------------------------------------------------- /libs/utils/small_vector/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Chobo Single-Header Libraries 2 | Copyright (c) 2016-2018 Chobolabs Inc. 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /libs/utils/utils.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #if defined(__clang__) 5 | # pragma clang diagnostic push 6 | # pragma clang diagnostic ignored "-Wsign-conversion" 7 | #elif defined(__GNUC__) 8 | # pragma GCC diagnostic push 9 | # pragma GCC diagnostic ignored "-Wsign-conversion" 10 | #endif 11 | 12 | #define CHOBO_SMALL_VECTOR_ERROR_HANDLING 0 // CHOBO_SMALL_VECTOR_ERROR_HANDLING_NONE 13 | #include "small_vector/small_vector.hpp" 14 | 15 | #if defined(__clang__) 16 | # pragma clang diagnostic pop 17 | #elif defined(__GNUC__) 18 | # pragma GCC diagnostic pop 19 | #endif 20 | 21 | namespace jet 22 | { 23 | using namespace chobo; 24 | } 25 | -------------------------------------------------------------------------------- /libs/whereami/LICENSE.MIT: -------------------------------------------------------------------------------- 1 | Copyright Gregory Pakosz 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software is furnished to do so, 8 | subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 15 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 16 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 17 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 18 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 19 | -------------------------------------------------------------------------------- /libs/whereami/src/whereami.h: -------------------------------------------------------------------------------- 1 | // (‑●‑●)> dual licensed under the WTFPL v2 and MIT licenses 2 | // without any warranty. 3 | // by Gregory Pakosz (@gpakosz) 4 | // https://github.com/gpakosz/whereami 5 | 6 | #ifndef WHEREAMI_H 7 | #define WHEREAMI_H 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | #ifndef WAI_FUNCSPEC 14 | #define WAI_FUNCSPEC 15 | #endif 16 | #ifndef WAI_PREFIX 17 | #define WAI_PREFIX(function) wai_##function 18 | #endif 19 | 20 | /** 21 | * Returns the path to the current executable. 22 | * 23 | * Usage: 24 | * - first call `int length = wai_getExecutablePath(NULL, 0, NULL);` to 25 | * retrieve the length of the path 26 | * - allocate the destination buffer with `path = (char*)malloc(length + 1);` 27 | * - call `wai_getExecutablePath(path, length, NULL)` again to retrieve the 28 | * path 29 | * - add a terminal NUL character with `path[length] = '\0';` 30 | * 31 | * @param out destination buffer, optional 32 | * @param capacity destination buffer capacity 33 | * @param dirname_length optional recipient for the length of the dirname part 34 | * of the path. 35 | * 36 | * @return the length of the executable path on success (without a terminal NUL 37 | * character), otherwise `-1` 38 | */ 39 | WAI_FUNCSPEC 40 | int WAI_PREFIX(getExecutablePath)(char* out, int capacity, int* dirname_length); 41 | 42 | /** 43 | * Returns the path to the current module 44 | * 45 | * Usage: 46 | * - first call `int length = wai_getModulePath(NULL, 0, NULL);` to retrieve 47 | * the length of the path 48 | * - allocate the destination buffer with `path = (char*)malloc(length + 1);` 49 | * - call `wai_getModulePath(path, length, NULL)` again to retrieve the path 50 | * - add a terminal NUL character with `path[length] = '\0';` 51 | * 52 | * @param out destination buffer, optional 53 | * @param capacity destination buffer capacity 54 | * @param dirname_length optional recipient for the length of the dirname part 55 | * of the path. 56 | * 57 | * @return the length of the module path on success (without a terminal NUL 58 | * character), otherwise `-1` 59 | */ 60 | WAI_FUNCSPEC 61 | int WAI_PREFIX(getModulePath)(char* out, int capacity, int* dirname_length); 62 | 63 | #ifdef __cplusplus 64 | } 65 | #endif 66 | 67 | #endif // #ifndef WHEREAMI_H 68 | -------------------------------------------------------------------------------- /libs/xxHash/LICENSE: -------------------------------------------------------------------------------- 1 | xxHash Library 2 | Copyright (c) 2012-present, Yann Collet 3 | All rights reserved. 4 | 5 | BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) 6 | 7 | Redistribution and use in source and binary forms, with or without modification, 8 | are permitted provided that the following conditions are met: 9 | 10 | * Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | * Redistributions in binary form must reproduce the above copyright notice, this 14 | list of conditions and the following disclaimer in the documentation and/or 15 | other materials provided with the distribution. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 21 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 24 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | 28 | ---------------------------------------------------- 29 | 30 | xxhsum command line interface 31 | Copyright (c) 2013-present, Yann Collet 32 | All rights reserved. 33 | 34 | GPL v2 License 35 | 36 | This program is free software; you can redistribute it and/or modify 37 | it under the terms of the GNU General Public License as published by 38 | the Free Software Foundation; either version 2 of the License, or 39 | (at your option) any later version. 40 | 41 | This program is distributed in the hope that it will be useful, 42 | but WITHOUT ANY WARRANTY; without even the implied warranty of 43 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 44 | GNU General Public License for more details. 45 | 46 | You should have received a copy of the GNU General Public License along 47 | with this program; if not, write to the Free Software Foundation, Inc., 48 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 49 | -------------------------------------------------------------------------------- /src/jet/live/AsyncEventQueue.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "AsyncEventQueue.hpp" 3 | #include "jet/live/Utility.hpp" 4 | 5 | namespace jet 6 | { 7 | void AsyncEventQueue::addLog(LogSeverity severity, std::string&& message) 8 | { 9 | std::lock_guard lock(m_logQueueMutex); 10 | m_logQueue.push(jet::make_unique(severity, std::move(message))); 11 | } 12 | 13 | LogEvent* AsyncEventQueue::getLogEvent() 14 | { 15 | std::lock_guard lock(m_logQueueMutex); 16 | return m_logQueue.empty() ? nullptr : m_logQueue.front().get(); 17 | } 18 | 19 | void AsyncEventQueue::popLogEvent() 20 | { 21 | std::lock_guard lock(m_logQueueMutex); 22 | if (!m_logQueue.empty()) { 23 | m_logQueue.pop(); 24 | } 25 | } 26 | 27 | void AsyncEventQueue::addEvent(std::unique_ptr&& event) 28 | { 29 | std::lock_guard lock(m_queueMutex); 30 | m_queue.push(std::move(event)); 31 | } 32 | 33 | IEvent* AsyncEventQueue::getEvent() 34 | { 35 | std::lock_guard lock(m_queueMutex); 36 | return m_queue.empty() ? nullptr : m_queue.top().get(); 37 | } 38 | 39 | void AsyncEventQueue::popEvent() 40 | { 41 | std::lock_guard lock(m_queueMutex); 42 | if (!m_queue.empty()) { 43 | m_queue.pop(); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/jet/live/AsyncEventQueue.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | #include 6 | #include 7 | #include "jet/live/IEvent.hpp" 8 | #include "jet/live/ILiveListener.hpp" 9 | #include "jet/live/events/LogEvent.hpp" 10 | 11 | namespace jet 12 | { 13 | class AsyncEventQueue 14 | { 15 | public: 16 | void addLog(LogSeverity severity, std::string&& message); 17 | LogEvent* getLogEvent(); 18 | void popLogEvent(); 19 | 20 | void addEvent(std::unique_ptr&& event); 21 | IEvent* getEvent(); 22 | void popEvent(); 23 | 24 | private: 25 | struct QueueComparator 26 | { 27 | bool operator()(const std::unique_ptr& l, const std::unique_ptr& r) 28 | { 29 | return l->getPriority() < r->getPriority(); 30 | } 31 | }; 32 | template 33 | using queue_t = std::priority_queue, QueueComparator>; 34 | 35 | std::mutex m_logQueueMutex; 36 | std::queue> m_logQueue; 37 | 38 | std::mutex m_queueMutex; 39 | queue_t> m_queue; 40 | }; 41 | } 42 | -------------------------------------------------------------------------------- /src/jet/live/BuildConfig.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "BuildConfig.hpp" 3 | 4 | namespace jet 5 | { 6 | const std::string& getCmakeGenerator() 7 | { 8 | #ifdef JET_LIVE_CMAKE_GENERATOR 9 | static const std::string cmakeGenerator = JET_LIVE_CMAKE_GENERATOR; 10 | #else 11 | #error JET_LIVE_CMAKE_GENERATOR is not defined 12 | static const std::string cmakeGenerator; 13 | #endif 14 | return cmakeGenerator; 15 | } 16 | 17 | const std::string& getCmakeBuildDirectory() 18 | { 19 | #ifdef JET_LIVE_CMAKE_BUILD_DIR 20 | static const std::string cmakeBuildDir = JET_LIVE_CMAKE_BUILD_DIR; 21 | #else 22 | #error JET_LIVE_CMAKE_BUILD_DIR is not defined 23 | static const std::string cmakeBuildDir; 24 | #endif 25 | return cmakeBuildDir; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/jet/live/BuildConfig.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | 6 | namespace jet 7 | { 8 | const std::string& getCmakeGenerator(); 9 | const std::string& getCmakeBuildDirectory(); 10 | } 11 | -------------------------------------------------------------------------------- /src/jet/live/CodeReloadPipeline.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "CodeReloadPipeline.hpp" 3 | #include 4 | 5 | namespace jet 6 | { 7 | void CodeReloadPipeline::addStep(std::unique_ptr&& step) 8 | { 9 | m_steps.emplace_back(std::move(step)); 10 | } 11 | 12 | void CodeReloadPipeline::reload(LiveContext* context, Program* newProgram) 13 | { 14 | assert(newProgram); 15 | 16 | for (const auto& step : m_steps) { 17 | step->reload(context, newProgram); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/jet/live/CodeReloadPipeline.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | #include 6 | #include "jet/live/ICodeReloadPipelineStep.hpp" 7 | 8 | namespace jet 9 | { 10 | struct LiveContext; 11 | struct Program; 12 | class CodeReloadPipeline 13 | { 14 | public: 15 | void addStep(std::unique_ptr&& step); 16 | void reload(LiveContext* context, Program* newProgram); 17 | 18 | private: 19 | std::vector> m_steps; 20 | }; 21 | } 22 | -------------------------------------------------------------------------------- /src/jet/live/CompileCommandsCompilationUnitsParser.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | #include 6 | #include 7 | #include "jet/live/ICompilationUnitsParser.hpp" 8 | 9 | namespace jet 10 | { 11 | /** 12 | * Compilation units parser based on `compile_commands.json` file. 13 | */ 14 | class CompileCommandsCompilationUnitsParser : public ICompilationUnitsParser 15 | { 16 | public: 17 | std::vector getFilesToMonitor() const override; 18 | std::unordered_map parseCompilationUnits(const LiveContext* context) override; 19 | bool updateCompilationUnits(LiveContext* context, 20 | const std::string& filepath, 21 | std::vector* addedCompilationUnits, 22 | std::vector* modifiedCompilationUnits, 23 | std::vector* removedCompilationUnits) override; 24 | 25 | protected: 26 | TeenyPath::path m_compileCommandsPath; 27 | TeenyPath::path m_pbxProjPath; 28 | std::unique_ptr m_runningProcess; 29 | 30 | std::unordered_map parseCompilationUnitsInternal(const LiveContext* context, 31 | const TeenyPath::path& filepath); 32 | 33 | /** 34 | * By default it tries to find `compile_commands.json` in the executable directory 35 | * and all parent directories recursively. 36 | * For custom `compile_commands.json` location you can subclass and override this method. 37 | */ 38 | virtual TeenyPath::path getCompileCommandsPath(const LiveContext* context) const; 39 | 40 | bool isXcodeProject() const; 41 | void createCompileCommandsJsonFromXcodeProject(const LiveContext* context, bool wait); 42 | }; 43 | } 44 | -------------------------------------------------------------------------------- /src/jet/live/DefaultProgramInfoLoader.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #ifdef __linux__ 5 | #include "jet/live/_linux/ElfProgramInfoLoader.hpp" 6 | namespace jet 7 | { 8 | using DefaultProgramInfoLoader = ElfProgramInfoLoader; 9 | } 10 | 11 | #elif __APPLE__ 12 | #include "jet/live/_macos/MachoProgramInfoLoader.hpp" 13 | namespace jet 14 | { 15 | using DefaultProgramInfoLoader = MachoProgramInfoLoader; 16 | } 17 | 18 | #else 19 | #error "Platform is not supported" 20 | #endif 21 | -------------------------------------------------------------------------------- /src/jet/live/DefaultSymbolsFilter.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "DefaultSymbolsFilter.hpp" 3 | #include "jet/live/DataTypes.hpp" 4 | 5 | namespace 6 | { 7 | const std::string& getStringOr(const std::vector& vec, size_t index, const std::string& fallback) 8 | { 9 | return vec.size() <= index ? fallback : vec[index]; 10 | } 11 | } 12 | 13 | namespace jet 14 | { 15 | bool DefaultSymbolsFilter::shouldReloadMachoSymbol(const MachoContext& context, const MachoSymbol& symbol) 16 | { 17 | static const std::string textSectionName = "__text"; 18 | const auto& sectionName = getStringOr(context.sectionNames, symbol.sectionIndex, "?"); 19 | return (symbol.type == MachoSymbolType::kSection && !symbol.weakDef && sectionName == textSectionName); 20 | } 21 | 22 | bool DefaultSymbolsFilter::shouldReloadElfSymbol(const ElfContext& context, const ElfSymbol& symbol) 23 | { 24 | static const std::string textSectionName = ".text"; 25 | const auto& sectionName = getStringOr(context.sectionNames, symbol.sectionIndex, "?"); 26 | return (symbol.type == ElfSymbolType::kFunction && symbol.size != 0 && sectionName == textSectionName); 27 | } 28 | 29 | bool DefaultSymbolsFilter::shouldTransferMachoSymbol(const MachoContext& context, const MachoSymbol& symbol) 30 | { 31 | static const std::string bssSectionName = "__bss"; 32 | static const std::string dataSectionName = "__data"; 33 | static const std::string commonSectionName = "__common"; 34 | const auto& sectionName = getStringOr(context.sectionNames, symbol.sectionIndex, "?"); 35 | return ( 36 | symbol.type == MachoSymbolType::kSection && !symbol.privateExternal && !symbol.weakDef 37 | && (sectionName == bssSectionName || sectionName == dataSectionName || sectionName == commonSectionName)); 38 | } 39 | 40 | bool DefaultSymbolsFilter::shouldTransferElfSymbol(const ElfContext& context, const ElfSymbol& symbol) 41 | { 42 | static const std::string bssSectionName = ".bss"; 43 | static const std::string dataSectionName = ".data"; 44 | const auto& sectionName = getStringOr(context.sectionNames, symbol.sectionIndex, "?"); 45 | return (symbol.type == ElfSymbolType::kObject && symbol.binding == ElfSymbolBinding::kLocal 46 | && symbol.visibility == ElfSymbolVisibility::kDefault 47 | && (sectionName == bssSectionName || sectionName == dataSectionName)); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/jet/live/DefaultSymbolsFilter.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include "jet/live/ISymbolsFilter.hpp" 5 | 6 | namespace jet 7 | { 8 | /** 9 | * Default implementation of symbols filter. 10 | */ 11 | class DefaultSymbolsFilter : public ISymbolsFilter 12 | { 13 | public: 14 | bool shouldReloadMachoSymbol(const MachoContext& context, const MachoSymbol& symbol) override; 15 | bool shouldReloadElfSymbol(const ElfContext& context, const ElfSymbol& symbol) override; 16 | bool shouldTransferMachoSymbol(const MachoContext& context, const MachoSymbol& symbol) override; 17 | bool shouldTransferElfSymbol(const ElfContext& context, const ElfSymbol& symbol) override; 18 | }; 19 | } 20 | -------------------------------------------------------------------------------- /src/jet/live/DepfileDependenciesHandler.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include "jet/live/IDependenciesHandler.hpp" 5 | 6 | namespace jet 7 | { 8 | /** 9 | * Dependencies handler implementation based on compiler generated depfiles. 10 | * For more info please refer to `-MD` compiler option. 11 | */ 12 | class DepfileDependenciesHandler : public IDependenciesHandler 13 | { 14 | public: 15 | std::unordered_set getDependencies(const LiveContext* context, CompilationUnit& cu) override; 16 | }; 17 | } 18 | -------------------------------------------------------------------------------- /src/jet/live/FileWatcher.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | namespace jet 15 | { 16 | /** 17 | * Monitors directories and listens filesystem events. 18 | */ 19 | class FileWatcher 20 | { 21 | public: 22 | enum class Action 23 | { 24 | kAdded, 25 | kMoved, 26 | kModified, 27 | kDeleted 28 | }; 29 | 30 | struct Event 31 | { 32 | Action action; 33 | std::string directory; 34 | std::string filename; 35 | std::string oldFilename; 36 | }; 37 | 38 | /** 39 | * \param directoriesToWatch A list of directories to watch. 40 | * \param callback Function wich is called when file was modified. 41 | * \param filterFunc Function which is called from the background thread, 42 | * it shoudl check if given file should be processed further. 43 | */ 44 | explicit FileWatcher(const std::unordered_set& directoriesToWatch, 45 | std::function&& callback, 46 | std::function&& filterFunc); 47 | ~FileWatcher(); 48 | 49 | void update(); 50 | 51 | void addWatch(const std::string& dir); 52 | 53 | private: 54 | class EfswListener : public efsw::FileWatchListener 55 | { 56 | public: 57 | using callback_t = 58 | std::function; 59 | 60 | explicit EfswListener(const callback_t& callback); 61 | void handleFileAction(efsw::WatchID, 62 | const std::string&, 63 | const std::string&, 64 | efsw::Action, 65 | std::string) override; 66 | 67 | private: 68 | callback_t m_callback; 69 | }; 70 | using time_point_t = std::chrono::time_point; 71 | 72 | std::function m_callback; 73 | std::function m_filterFunction; 74 | std::unordered_map m_modificationTimePoints; 75 | std::unordered_map m_fileHashes; 76 | std::unique_ptr m_fileWatcher; 77 | std::unique_ptr m_efswListener; 78 | std::mutex m_fileEventsMutex; 79 | std::vector m_fileEvents; 80 | std::vector m_watchIds; 81 | const std::chrono::milliseconds m_fileModificationWindowMsec = std::chrono::milliseconds(100); 82 | }; 83 | } 84 | -------------------------------------------------------------------------------- /src/jet/live/FunctionsHookingStep.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "FunctionsHookingStep.hpp" 3 | #include 4 | #include "jet/live/LiveContext.hpp" 5 | #include "jet/live/Utility.hpp" 6 | 7 | namespace jet 8 | { 9 | void FunctionsHookingStep::reload(LiveContext* context, Program* newProgram) 10 | { 11 | context->events->addLog(LogSeverity::kDebug, "Hooking functions..."); 12 | 13 | auto totalFunctions = getTotalFunctions(newProgram->symbols); 14 | size_t hookedFunctions = 0; 15 | for (const auto& syms : newProgram->symbols.functions) { 16 | for (const auto& sym : syms.second) { 17 | void* oldFuncPtr = nullptr; 18 | const auto& progs = context->programs; 19 | for (auto it = progs.rbegin(); it != progs.rend(); it++) { 20 | if (auto foundSym = findFunction(it->symbols, sym.name, sym.hash)) { 21 | oldFuncPtr = reinterpret_cast(foundSym->runtimeAddress); 22 | break; 23 | } 24 | } 25 | if (!oldFuncPtr) { 26 | continue; 27 | } 28 | 29 | auto newFuncPtr = reinterpret_cast(sym.runtimeAddress); 30 | auto hook = subhook_new(oldFuncPtr, newFuncPtr, SUBHOOK_64BIT_OFFSET); 31 | if (auto subhookStatus = subhook_install(hook)) { 32 | context->events->addLog(LogSeverity::kError, 33 | "Cannot hook function: " + sym.name + ", status " + std::to_string(subhookStatus)); 34 | } else { 35 | hookedFunctions++; 36 | } 37 | } 38 | } 39 | 40 | context->events->addLog(LogSeverity::kDebug, 41 | "Done, hooked: " + std::to_string(hookedFunctions) + "/" + std::to_string(totalFunctions)); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/jet/live/FunctionsHookingStep.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include "jet/live/ICodeReloadPipelineStep.hpp" 5 | 6 | namespace jet 7 | { 8 | class FunctionsHookingStep : public ICodeReloadPipelineStep 9 | { 10 | public: 11 | void reload(LiveContext* context, Program* newProgram) override; 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /src/jet/live/ICodeReloadPipelineStep.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | namespace jet 5 | { 6 | struct LiveContext; 7 | struct Program; 8 | class ICodeReloadPipelineStep 9 | { 10 | public: 11 | virtual ~ICodeReloadPipelineStep() {} 12 | virtual void reload(LiveContext* context, Program* newProgram) = 0; 13 | }; 14 | } 15 | -------------------------------------------------------------------------------- /src/jet/live/ICompilationUnitsParser.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | #include 6 | #include "jet/live/DataTypes.hpp" 7 | 8 | namespace jet 9 | { 10 | struct LiveContext; 11 | /** 12 | * Compilation units parser interface. 13 | */ 14 | class ICompilationUnitsParser 15 | { 16 | public: 17 | virtual ~ICompilationUnitsParser() {} 18 | 19 | /** 20 | * Retrieves a vector of paths to files which should be monitored for changes. 21 | */ 22 | virtual std::vector getFilesToMonitor() const = 0; 23 | 24 | /** 25 | * Parses and returns info about all compilation units used to construct this application. 26 | * \return "cu source path" -> "compilation unit" map 27 | */ 28 | virtual std::unordered_map parseCompilationUnits(const LiveContext* context) = 0; 29 | 30 | /** 31 | * Updates compilation units list inside `context` using `filepath`, if this `filepath` is a source of 32 | * compilation units. Fills output vectors with added, modified and removed compilation units. 33 | * \return `true` if update was made, `false` if CU list was not touched. 34 | */ 35 | virtual bool updateCompilationUnits(LiveContext* context, 36 | const std::string& filepath, 37 | std::vector* addedCompilationUnits, 38 | std::vector* modifiedCompilationUnits, 39 | std::vector* removedCompilationUnits) = 0; 40 | }; 41 | } 42 | -------------------------------------------------------------------------------- /src/jet/live/IDependenciesHandler.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | #include "jet/live/DataTypes.hpp" 6 | 7 | namespace jet 8 | { 9 | struct LiveContext; 10 | /** 11 | * Dependencies handler interface. 12 | */ 13 | class IDependenciesHandler 14 | { 15 | public: 16 | virtual ~IDependenciesHandler() {} 17 | 18 | /** 19 | * Finds dependencies of given cu (files which cu depends on). 20 | * \return A set of dependencies file paths. 21 | */ 22 | virtual std::unordered_set getDependencies(const LiveContext* context, CompilationUnit& cu) = 0; 23 | }; 24 | } 25 | -------------------------------------------------------------------------------- /src/jet/live/IEvent.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | namespace jet 5 | { 6 | enum class EventType 7 | { 8 | kUnknown, 9 | kLog, 10 | kFileChanged, 11 | kTryReload, 12 | }; 13 | 14 | class IEvent 15 | { 16 | public: 17 | explicit IEvent(EventType type) 18 | : m_type(type) 19 | { 20 | } 21 | virtual ~IEvent() {} 22 | EventType getType() const { return m_type; } 23 | virtual int getPriority() const = 0; 24 | 25 | private: 26 | EventType m_type = EventType::kUnknown; 27 | }; 28 | } 29 | -------------------------------------------------------------------------------- /src/jet/live/ILiveListener.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | 6 | namespace jet 7 | { 8 | enum class LogSeverity 9 | { 10 | kDebug, 11 | kInfo, 12 | kWarning, 13 | kError 14 | }; 15 | 16 | /** 17 | * Base class for custom delegate. 18 | */ 19 | class ILiveListener 20 | { 21 | public: 22 | virtual ~ILiveListener() {} 23 | 24 | /** 25 | * Called on each log message from the library. 26 | */ 27 | virtual void onLog(LogSeverity, const std::string&) {} 28 | 29 | /** 30 | * Called right before shared library with new code is loaded into the process address space. 31 | */ 32 | virtual void onCodePreLoad() {} 33 | 34 | /** 35 | * Called right after all functions are hooked and state is transferred. 36 | */ 37 | virtual void onCodePostLoad() {} 38 | }; 39 | } 40 | -------------------------------------------------------------------------------- /src/jet/live/IProgramInfoLoader.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | #include 6 | #include "jet/live/DataTypes.hpp" 7 | 8 | namespace jet 9 | { 10 | struct LiveContext; 11 | class IProgramInfoLoader 12 | { 13 | public: 14 | virtual ~IProgramInfoLoader() {} 15 | 16 | /** 17 | * Retrieves executable and shared libraries paths loaded into this process memory. 18 | */ 19 | virtual std::vector getAllLoadedProgramsPaths(const LiveContext* context) const = 0; 20 | 21 | /** 22 | * Retrieves symbols of given program. 23 | * \param context LiveContext pointer. 24 | * \param filepath Path to the program file. Empty string for this executable. 25 | */ 26 | virtual Symbols getProgramSymbols(const LiveContext* context, const std::string& filepath) const = 0; 27 | 28 | /** 29 | * Retrieves a link-time relocations in the `text` 30 | * section which use symbols from `bss` and `data` sections. 31 | * Used to fix static/global variable addresses in new code to 32 | * make them pointing to corresponding variables in old code. 33 | */ 34 | virtual std::vector getLinkTimeRelocations(const LiveContext* context, 35 | const std::vector& objFilePaths) = 0; 36 | 37 | /** 38 | * Retrieves a list of undefined symbol names of the given program. 39 | */ 40 | virtual std::vector getUndefinedSymbolNames(const LiveContext* context, 41 | const std::string filepath) = 0; 42 | 43 | /** 44 | * Retrieves a list of exported symbol names of the given program. 45 | */ 46 | virtual std::vector getExportedSymbolNames(const LiveContext* context, 47 | const std::string filepath) = 0; 48 | }; 49 | } 50 | -------------------------------------------------------------------------------- /src/jet/live/ISymbolsFilter.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | namespace jet 5 | { 6 | struct MachoContext; 7 | struct MachoSymbol; 8 | struct ElfContext; 9 | struct ElfSymbol; 10 | 11 | /** 12 | * Base class for symbols filtering strategy. 13 | */ 14 | class ISymbolsFilter 15 | { 16 | public: 17 | virtual ~ISymbolsFilter() {} 18 | 19 | /** 20 | * Checks if this mach-o symbol should be treated as reloadable function. 21 | * You shoul have some idea about what is mach-o to override use this function. 22 | * Please see implementation for default behaviour. 23 | */ 24 | virtual bool shouldReloadMachoSymbol(const MachoContext& context, const MachoSymbol& symbol) = 0; 25 | 26 | /** 27 | * Checks if this elf symbol should be treated as reloadable function. 28 | * You shoul have some idea about what is elf to override use this function. 29 | * Please see implementation for default behaviour. 30 | */ 31 | virtual bool shouldReloadElfSymbol(const ElfContext& context, const ElfSymbol& symbol) = 0; 32 | 33 | /** 34 | * Checks if this mach-o symbol should be treated as transferrable static variable. 35 | * You shoul have some idea about what is mach-o to override use this function. 36 | * Please see implementation for default behaviour. 37 | */ 38 | virtual bool shouldTransferMachoSymbol(const MachoContext& context, const MachoSymbol& symbol) = 0; 39 | 40 | /** 41 | * Checks if this elf symbol should be treated as transferrable static variable. 42 | * You shoul have some idea about what is elf to override use this function. 43 | * Please see implementation for default behaviour. 44 | */ 45 | virtual bool shouldTransferElfSymbol(const ElfContext& context, const ElfSymbol& symbol) = 0; 46 | }; 47 | } 48 | -------------------------------------------------------------------------------- /src/jet/live/LinkTimeRelocationsStep.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include "jet/live/ICodeReloadPipelineStep.hpp" 5 | 6 | namespace jet 7 | { 8 | class LinkTimeRelocationsStep : public ICodeReloadPipelineStep 9 | { 10 | public: 11 | void reload(LiveContext* context, Program* newProgram) override; 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /src/jet/live/Live.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "jet/live/Compiler.hpp" 11 | #include "jet/live/FileWatcher.hpp" 12 | #include "jet/live/ILiveListener.hpp" 13 | #include "jet/live/LiveConfig.hpp" 14 | #include "jet/live/LiveContext.hpp" 15 | #include "jet/live/Status.hpp" 16 | 17 | namespace jet 18 | { 19 | struct CompilationUnit; 20 | 21 | /** 22 | * Main entry point of the library. 23 | * Ties together all the parts of functionality. 24 | */ 25 | class Live 26 | { 27 | public: 28 | /** 29 | * Initialization is performed in a background thread. 30 | * 31 | */ 32 | Live(std::unique_ptr&& listener = {}, const LiveConfig& config = {}); 33 | ~Live(); 34 | 35 | /** 36 | * Tries to reload changed code. 37 | * It will wait for all pending compilation processes to finish. 38 | * Does nothing if there's no changes. 39 | * Call it only when you're done editing your code. 40 | */ 41 | void tryReload(); 42 | 43 | /** 44 | * Runloop method, should be periodically called by the application. 45 | */ 46 | void update(); 47 | 48 | /** 49 | * Checks if initialization is finished. 50 | */ 51 | bool isInitialized() const; 52 | 53 | /** 54 | * Retrieves status of the library. 55 | */ 56 | Status getStatus() const; 57 | 58 | private: 59 | std::unique_ptr m_context; 60 | std::unique_ptr m_fileWatcher; 61 | std::unique_ptr m_compiler; 62 | int m_recreateFileWatcherAfterTicks = 0; 63 | const int m_recreateFileWatcherMaxTicks = 10; 64 | std::thread m_initThread; 65 | std::atomic_bool m_initialized{false}; 66 | std::atomic_bool m_earlyExit{false}; 67 | 68 | void loadCompilationUnits(); 69 | void loadSymbols(); 70 | void loadExportedSymbols(); 71 | void loadDependencies(); 72 | void setupFileWatcher(); 73 | void updateDependencies(CompilationUnit& cu); 74 | std::unordered_set getDirectoriesToMonitor(); 75 | std::unordered_set getDirectoryFilters(); 76 | 77 | void onFileChanged(const std::string& filepath); 78 | void tryReloadInternal(); 79 | }; 80 | } 81 | -------------------------------------------------------------------------------- /src/jet/live/LiveConfig.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | #include 6 | 7 | namespace jet 8 | { 9 | /** 10 | * Configuration parameters. 11 | */ 12 | struct LiveConfig 13 | { 14 | /** 15 | * The maximum amount of possible worker threads used by the library. 16 | * Usually all these threads are busy compiling new code. 17 | */ 18 | size_t workerThreadsCount = 4; 19 | 20 | /** 21 | * If `true`, also reload code when app receives `SIGUSR1`. 22 | */ 23 | bool reloadOnSignal = true; 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /src/jet/live/LiveContext.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | #include 6 | #include 7 | #include "jet/live/AsyncEventQueue.hpp" 8 | #include "jet/live/CodeReloadPipeline.hpp" 9 | #include "jet/live/ICompilationUnitsParser.hpp" 10 | #include "jet/live/IDependenciesHandler.hpp" 11 | #include "jet/live/ILiveListener.hpp" 12 | #include "jet/live/IProgramInfoLoader.hpp" 13 | #include "jet/live/ISymbolsFilter.hpp" 14 | #include "jet/live/LiveConfig.hpp" 15 | 16 | namespace jet 17 | { 18 | /** 19 | * A bunch of data which is shared between different classes. 20 | */ 21 | struct LiveContext 22 | { 23 | /** Current config. */ 24 | LiveConfig liveConfig; 25 | 26 | /** Current events listener. */ 27 | std::unique_ptr listener; 28 | 29 | /** Current compilation units parser. */ 30 | std::unique_ptr compilationUnitsParser; 31 | 32 | /** Current dependencies handler. */ 33 | std::unique_ptr dependenciesHandler; 34 | 35 | /** Current program info loader. */ 36 | std::unique_ptr programInfoLoader; 37 | 38 | /** Current symbols filter. */ 39 | std::unique_ptr symbolsFilter; 40 | 41 | /** Current code reload pipeline. */ 42 | std::unique_ptr codeReloadPipeline; 43 | 44 | /** Event queue. */ 45 | std::unique_ptr events; 46 | 47 | /** 48 | * All programs which are living in the address space if this process (executables 49 | * and shared libraries) in order of loading. 50 | */ 51 | std::vector programs; 52 | 53 | /** This executable file path. */ 54 | std::string thisExecutablePath; 55 | 56 | /** Current linker type. */ 57 | LinkerType linkerType; 58 | 59 | /** Directories which are monitored for changes. */ 60 | std::unordered_set dirsToMonitor; 61 | 62 | /** Directories that contains all sources we are interested in. */ 63 | std::unordered_set dirFilters; 64 | 65 | /** sourceFilePath -> CompilationUnit map. */ 66 | std::unordered_map compilationUnits; 67 | 68 | /** sourceFilePath -> set of dependency file paths. */ 69 | std::unordered_map> dependencies; 70 | 71 | /** dependency file path -> set of sourceFilePaths. */ 72 | std::unordered_map> inverseDependencies; 73 | 74 | /** exported symbol name -> sourceFilePath. */ 75 | std::unordered_map exportedSymbolNamesInSourceFiles; 76 | }; 77 | } 78 | -------------------------------------------------------------------------------- /src/jet/live/SignalReloader.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "SignalReloader.hpp" 3 | #include 4 | #include 5 | #include "jet/live/Live.hpp" 6 | 7 | namespace 8 | { 9 | jet::Live* livePtr = nullptr; 10 | } 11 | 12 | void signalHandler(int) 13 | { 14 | if (livePtr) { 15 | livePtr->tryReload(); 16 | } 17 | } 18 | 19 | namespace jet 20 | { 21 | void onLiveCreated(Live* live, bool reloadOnSignal) 22 | { 23 | ::livePtr = live; 24 | if (reloadOnSignal) { 25 | signal(SIGUSR1, signalHandler); 26 | } 27 | } 28 | 29 | void onLiveDestroyed() { ::livePtr = nullptr; } 30 | } 31 | -------------------------------------------------------------------------------- /src/jet/live/SignalReloader.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | namespace jet 5 | { 6 | class Live; 7 | 8 | void onLiveCreated(Live* live, bool reloadOnSignal); 9 | void onLiveDestroyed(); 10 | } 11 | -------------------------------------------------------------------------------- /src/jet/live/StaticsCopyStep.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "StaticsCopyStep.hpp" 3 | #include 4 | #include "jet/live/LiveContext.hpp" 5 | #include "jet/live/Utility.hpp" 6 | 7 | namespace jet 8 | { 9 | void StaticsCopyStep::reload(LiveContext* context, Program* newProgram) 10 | { 11 | context->events->addLog(LogSeverity::kDebug, "Copying statics from old code to new one..."); 12 | 13 | auto totalVars = getTotalVariables(newProgram->symbols); 14 | size_t copiedVars = 0; 15 | for (const auto& syms : newProgram->symbols.variables) { 16 | for (const auto& sym : syms.second) { 17 | void* oldVarPtr = nullptr; 18 | size_t oldVarSize = 0; 19 | const auto& progs = context->programs; 20 | for (const auto& prog : progs) { 21 | if (auto foundSym = findVariable(prog.symbols, sym.name, sym.hash)) { 22 | oldVarSize = foundSym->size; 23 | oldVarPtr = reinterpret_cast(foundSym->runtimeAddress); 24 | break; 25 | } 26 | } 27 | if (!oldVarPtr) { 28 | continue; 29 | } 30 | 31 | auto newVarPtr = reinterpret_cast(sym.runtimeAddress); 32 | 33 | // Trying to do our best 34 | memcpy(newVarPtr, oldVarPtr, std::min(sym.size, oldVarSize)); 35 | copiedVars++; 36 | } 37 | } 38 | 39 | context->events->addLog( 40 | LogSeverity::kDebug, "Done, copied: " + std::to_string(copiedVars) + "/" + std::to_string(totalVars)); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/jet/live/StaticsCopyStep.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include "jet/live/ICodeReloadPipelineStep.hpp" 5 | 6 | namespace jet 7 | { 8 | class StaticsCopyStep : public ICodeReloadPipelineStep 9 | { 10 | public: 11 | void reload(LiveContext* context, Program* newProgram) override; 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /src/jet/live/Status.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | #include 6 | 7 | namespace jet 8 | { 9 | struct Status 10 | { 11 | std::set compilingFiles; 12 | std::set successfulFiles; 13 | std::set failedFiles; 14 | }; 15 | } 16 | -------------------------------------------------------------------------------- /src/jet/live/_linux/ElfProgramInfoLoader.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include "jet/live/IProgramInfoLoader.hpp" 5 | 6 | namespace jet 7 | { 8 | /** 9 | * Program info loader implementation for elf. 10 | */ 11 | class ElfProgramInfoLoader : public IProgramInfoLoader 12 | { 13 | public: 14 | std::vector getAllLoadedProgramsPaths(const LiveContext* context) const override; 15 | Symbols getProgramSymbols(const LiveContext* context, const std::string& filepath) const override; 16 | std::vector getLinkTimeRelocations(const LiveContext* context, 17 | const std::vector& objFilePaths) override; 18 | std::vector getUndefinedSymbolNames(const LiveContext* context, 19 | const std::string filepath) override; 20 | std::vector getExportedSymbolNames(const LiveContext* context, 21 | const std::string filepath) override; 22 | }; 23 | } 24 | -------------------------------------------------------------------------------- /src/jet/live/_macos/MachoProgramInfoLoader.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include "jet/live/IProgramInfoLoader.hpp" 5 | 6 | namespace jet 7 | { 8 | /** 9 | * Program info loader implementation for mach-o. 10 | */ 11 | class MachoProgramInfoLoader : public IProgramInfoLoader 12 | { 13 | public: 14 | std::vector getAllLoadedProgramsPaths(const LiveContext* context) const override; 15 | Symbols getProgramSymbols(const LiveContext* context, const std::string& filepath) const override; 16 | std::vector getLinkTimeRelocations(const LiveContext* context, 17 | const std::vector& objFilePaths) override; 18 | std::vector getUndefinedSymbolNames(const LiveContext* context, 19 | const std::string filepath) override; 20 | std::vector getExportedSymbolNames(const LiveContext* context, 21 | const std::string filepath) override; 22 | }; 23 | } 24 | -------------------------------------------------------------------------------- /src/jet/live/events/FileChangedEvent.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | #include "jet/live/IEvent.hpp" 6 | 7 | namespace jet 8 | { 9 | class FileChangedEvent : public IEvent 10 | { 11 | public: 12 | FileChangedEvent(const std::string& filepath) 13 | : IEvent(EventType::kFileChanged) 14 | , m_filepath(filepath) 15 | { 16 | } 17 | const std::string& getFilepath() const { return m_filepath; } 18 | int getPriority() const override { return 20; } 19 | 20 | private: 21 | std::string m_filepath; 22 | }; 23 | } 24 | -------------------------------------------------------------------------------- /src/jet/live/events/LogEvent.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include "jet/live/IEvent.hpp" 5 | #include "jet/live/ILiveListener.hpp" 6 | 7 | namespace jet 8 | { 9 | class LogEvent : public IEvent 10 | { 11 | public: 12 | LogEvent(LogSeverity severity, std::string&& message) 13 | : IEvent(EventType::kLog) 14 | , m_severity(severity) 15 | , m_message(std::move(message)) 16 | { 17 | } 18 | 19 | LogSeverity getSeverity() const { return m_severity; } 20 | const std::string& getMessage() const { return m_message; } 21 | int getPriority() const override { return 0; } 22 | 23 | private: 24 | LogSeverity m_severity; 25 | std::string m_message; 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /src/jet/live/events/TryReloadEvent.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include "jet/live/IEvent.hpp" 5 | 6 | namespace jet 7 | { 8 | class TryReloadEvent : public IEvent 9 | { 10 | public: 11 | TryReloadEvent() 12 | : IEvent(EventType::kTryReload) 13 | { 14 | } 15 | 16 | int getPriority() const override { return 10; } 17 | }; 18 | } 19 | -------------------------------------------------------------------------------- /tests/.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | DisableFormat: true 3 | SortIncludes: false 4 | ... 5 | -------------------------------------------------------------------------------- /tests/src/Globals.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | #include "TestListener.hpp" 6 | 7 | extern TestListener* g_testListenerPtr; 8 | extern jet::Live* g_live; 9 | -------------------------------------------------------------------------------- /tests/src/Stacktrace.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | void setupSignalHandlers(); 5 | -------------------------------------------------------------------------------- /tests/src/TestListener.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "TestListener.hpp" 3 | #include 4 | #include 5 | #include 6 | 7 | void TestListener::setCallbacks(std::function &&codePreLoadCallback, std::function &&codePostLoadCallback) 8 | { 9 | m_codePreLoadCallback = std::move(codePreLoadCallback); 10 | m_codePostLoadCallback = std::move(codePostLoadCallback); 11 | } 12 | 13 | void TestListener::onLog(jet::LogSeverity severity, const std::string &message) 14 | { 15 | using namespace std::chrono; 16 | high_resolution_clock::time_point p = high_resolution_clock::now(); 17 | milliseconds ms = duration_cast(p.time_since_epoch()); 18 | seconds s = duration_cast(ms); 19 | std::time_t t = s.count(); 20 | std::size_t milliSeconds = ms.count() % 1000; 21 | char buf[1024]; 22 | strftime(buf, sizeof(buf), "%F %T", gmtime(&t)); 23 | std::cout << '[' << buf << ':' << milliSeconds << ']'; 24 | 25 | switch (severity) { 26 | case jet::LogSeverity::kDebug: std::cout << "[D] "; break; 27 | case jet::LogSeverity::kInfo: std::cout << "[I] "; break; 28 | case jet::LogSeverity::kWarning: std::cout << "[W] "; break; 29 | case jet::LogSeverity::kError: std::cout << "[E] "; break; 30 | } 31 | std::cout << message << std::endl; 32 | } 33 | 34 | void TestListener::onCodePreLoad() 35 | { 36 | if (m_codePreLoadCallback) { 37 | m_codePreLoadCallback(); 38 | } 39 | } 40 | 41 | void TestListener::onCodePostLoad() 42 | { 43 | if (m_codePostLoadCallback) { 44 | m_codePostLoadCallback(); 45 | } 46 | } 47 | 48 | -------------------------------------------------------------------------------- /tests/src/TestListener.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | #include 6 | 7 | class TestListener : public jet::ILiveListener 8 | { 9 | public: 10 | void onLog(jet::LogSeverity severity, const std::string& message) override; 11 | void onCodePreLoad() override; 12 | void onCodePostLoad() override; 13 | 14 | void setCallbacks(std::function&& codePreLoadCallback, std::function&& codePostLoadCallback); 15 | 16 | private: 17 | std::function m_codePreLoadCallback; 18 | std::function m_codePostLoadCallback; 19 | }; 20 | -------------------------------------------------------------------------------- /tests/src/WaitForReload.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "WaitForReload.hpp" 3 | #include "Globals.hpp" 4 | #include 5 | #include 6 | 7 | void runAfterDelayAndWaitForReload(std::function&& func, int milliseconds) 8 | { 9 | bool cont = true; 10 | int updatesCount = 0; 11 | g_testListenerPtr->setCallbacks(nullptr, [&cont] { 12 | cont = false; 13 | }); 14 | while (cont) { 15 | if (updatesCount == milliseconds / 100) { 16 | func(); 17 | } 18 | g_live->update(); 19 | std::this_thread::sleep_for(std::chrono::milliseconds(100)); 20 | updatesCount++; 21 | if (updatesCount > 100) { 22 | break; 23 | } 24 | } 25 | g_testListenerPtr->setCallbacks(nullptr, nullptr); 26 | } 27 | 28 | void waitForReload(int milliseconds) 29 | { 30 | runAfterDelayAndWaitForReload([] { 31 | g_live->tryReload(); 32 | }, milliseconds); 33 | } 34 | 35 | void waitForReloadWithSignal(int milliseconds) 36 | { 37 | runAfterDelayAndWaitForReload([] { 38 | kill(getpid(), SIGUSR1); 39 | }, milliseconds); 40 | } 41 | -------------------------------------------------------------------------------- /tests/src/WaitForReload.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | 6 | void runAfterDelayAndWaitForReload(std::function&& func, int milliseconds = 1000); 7 | void waitForReload(int milliseconds = 1000); 8 | void waitForReloadWithSignal(int milliseconds = 1000); 9 | -------------------------------------------------------------------------------- /tests/src/bad/LambdaFunctionWithCapturesBadCase2_test.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include "utility/LambdaFunctionWithCapturesBadCase2.hpp" 6 | #include "Globals.hpp" 7 | #include "WaitForReload.hpp" 8 | 9 | TEST_CASE("Reload of lambda function with captured data and another lambda in the file with different signature", "[function]") 10 | { 11 | int v1 = 23; 12 | int v2 = 45; 13 | int sum = v1 + v2; 14 | int mul = v1 * v2; 15 | auto lambda = createLambdaFunctionWithCapturesBadCase2(); 16 | 17 | REQUIRE(lambda(v1, v2) == sum); 18 | 19 | std::cout << "JET_TEST: disable(lamb_capt_diff_sign_bad:1); enable(lamb_capt_diff_sign_bad:2)" << std::endl; 20 | waitForReload(); 21 | 22 | REQUIRE_FALSE(lambda(v1, v2) == mul); // note REQUIRE_FALSE 23 | } 24 | -------------------------------------------------------------------------------- /tests/src/bad/LambdaFunctionWithCapturesBadCase_test.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include "utility/LambdaFunctionWithCapturesBadCase.hpp" 6 | #include "Globals.hpp" 7 | #include "WaitForReload.hpp" 8 | 9 | TEST_CASE("Reload of lambda function with captured data and another lambda in the file, bad case", "[function]") 10 | { 11 | int v1 = 23; 12 | int v2 = 45; 13 | int sum = v1 + v2; 14 | int mul = v1 * v2; 15 | auto lambda = createLambdaFunctionWithCapturesBadCase(); 16 | 17 | REQUIRE(lambda(v1, v2) == sum); 18 | 19 | std::cout << "JET_TEST: disable(lamb_capt_bad:1); enable(lamb_capt_bad:2)" << std::endl; 20 | waitForReload(); 21 | 22 | REQUIRE_FALSE(lambda(v1, v2) == mul); // note REQUIRE_FALSE 23 | } 24 | -------------------------------------------------------------------------------- /tests/src/good/ClassInstanceMethod_test.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include "utility/ClassInstanceMethod.hpp" 6 | #include "Globals.hpp" 7 | #include "WaitForReload.hpp" 8 | 9 | TEST_CASE("Reload of class instance method", "[function]") 10 | { 11 | int v1 = 23; 12 | int v2 = 45; 13 | int sum = v1 + v2; 14 | int mul = v1 * v2; 15 | ClassInstanceMethod ins; 16 | 17 | REQUIRE(ins.computeResult(v1, v2) == sum); 18 | 19 | std::cout << "JET_TEST: disable(cls_ins_meth:1); enable(cls_ins_meth:2)" << std::endl; 20 | waitForReload(); 21 | 22 | REQUIRE(ins.computeResult(v1, v2) == mul); 23 | } 24 | -------------------------------------------------------------------------------- /tests/src/good/ClassStaticMethod_test.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include "utility/ClassStaticMethod.hpp" 6 | #include "Globals.hpp" 7 | #include "WaitForReload.hpp" 8 | 9 | TEST_CASE("Reload of class static method", "[function]") 10 | { 11 | int v1 = 23; 12 | int v2 = 45; 13 | int sum = v1 + v2; 14 | int mul = v1 * v2; 15 | 16 | REQUIRE(ClassStaticMethod::computeResult(v1, v2) == sum); 17 | 18 | std::cout << "JET_TEST: disable(cls_st_meth:1); enable(cls_st_meth:2)" << std::endl; 19 | waitForReload(); 20 | 21 | REQUIRE(ClassStaticMethod::computeResult(v1, v2) == mul); 22 | } 23 | -------------------------------------------------------------------------------- /tests/src/good/ClassVirtualMethod_test.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include "utility/ClassVirtualMethod.hpp" 6 | #include "Globals.hpp" 7 | #include "WaitForReload.hpp" 8 | #include 9 | 10 | TEST_CASE("Reload of class instance virtual method", "[function]") 11 | { 12 | int v1 = 23; 13 | int v2 = 45; 14 | int sum = v1 + v2; 15 | int mul = v1 * v2; 16 | auto ins = jet::make_unique(); 17 | 18 | REQUIRE(ins->computeResult(v1, v2) == sum); 19 | 20 | std::cout << "JET_TEST: disable(cls_virt_meth:1); enable(cls_virt_meth:2)" << std::endl; 21 | waitForReload(); 22 | 23 | REQUIRE(ins->computeResult(v1, v2) == mul); 24 | } 25 | -------------------------------------------------------------------------------- /tests/src/good/CommonSection_test.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | extern "C" { 6 | #include "utility/CommonSection.h" 7 | } 8 | #include "Globals.hpp" 9 | #include "WaitForReload.hpp" 10 | 11 | TEST_CASE("Relocation of global variable from *COM* (__DATA.__common) section", "[variable]") 12 | { 13 | auto beforeReload = getCommonSectionVar(); 14 | auto beforeReloadAddress = getCommonSectionVarAddress(); 15 | REQUIRE(beforeReload == 10); 16 | 17 | std::cout << "JET_TEST: enable(common_sect:1)" << std::endl; 18 | waitForReload(); 19 | 20 | auto afterReload = getCommonSectionVar(); 21 | auto afterReloadAddress = getCommonSectionVarAddress(); 22 | REQUIRE(afterReload == 11); 23 | REQUIRE(beforeReloadAddress == afterReloadAddress); 24 | 25 | *reinterpret_cast(afterReloadAddress) = 20; 26 | auto afterModify = getCommonSectionVar(); 27 | REQUIRE(afterModify == 20); 28 | } 29 | -------------------------------------------------------------------------------- /tests/src/good/ExternGlobalVariableAddress_test.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include "utility/ExternGlobalVariableAddress.hpp" 6 | #include "Globals.hpp" 7 | #include "WaitForReload.hpp" 8 | 9 | int externGlobalVariableCheckingAddress = 10; 10 | 11 | TEST_CASE("Relocation of extern global variable, comparing address", "[variable]") 12 | { 13 | auto oldVariableAddress = getExternGlobalVariableAddress(); 14 | 15 | std::cout << "JET_TEST: disable(extern_glob_var_addr:1)" << std::endl; 16 | waitForReload(); 17 | 18 | auto newVariableAddress = getExternGlobalVariableAddress(); 19 | REQUIRE(oldVariableAddress == newVariableAddress); 20 | } 21 | -------------------------------------------------------------------------------- /tests/src/good/ExternGlobalVariable_test.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include "utility/ExternGlobalVariable.hpp" 6 | #include "Globals.hpp" 7 | #include "WaitForReload.hpp" 8 | 9 | int someExternGlobalVariable = 10; 10 | 11 | TEST_CASE("Relocation of extern global variable", "[variable]") 12 | { 13 | auto beforeReload = getNextGlobal(); 14 | REQUIRE(beforeReload.first == 0); 15 | REQUIRE(beforeReload.second == 10); 16 | 17 | std::cout << "JET_TEST: disable(extern_glob_var:1); enable(extern_glob_var:2)" << std::endl; 18 | waitForReload(); 19 | 20 | auto afterReload = getNextGlobal(); 21 | REQUIRE(afterReload.first == 1); 22 | REQUIRE(afterReload.second == 11); 23 | } 24 | -------------------------------------------------------------------------------- /tests/src/good/FailedCompilationCrash_test.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include "utility/FailedCompilationCrash.hpp" 6 | #include "Globals.hpp" 7 | #include "WaitForReload.hpp" 8 | 9 | TEST_CASE("Crash when trying to reload code after success and then failed compilation", "[common]") 10 | { 11 | int v1 = 23; 12 | int v2 = 45; 13 | int sum = v1 + v2; 14 | int mul = v1 * v2; 15 | 16 | REQUIRE(failedCompilationComputeResult(v1, v2) == sum); 17 | 18 | std::cout << "JET_TEST: disable(failed_comp:1); enable(failed_comp:2)" << std::endl; 19 | // waiting for compilation to finish 20 | int updatesCount = 0; 21 | while (true) { 22 | if (updatesCount == 30) { 23 | break; 24 | } 25 | g_live->update(); 26 | std::this_thread::sleep_for(std::chrono::milliseconds(100)); 27 | updatesCount++; 28 | } 29 | 30 | std::cout << "JET_TEST: disable(failed_comp:2); enable(failed_comp:3)" << std::endl; 31 | waitForReload(); // fail, here should be a crash 32 | REQUIRE(failedCompilationComputeResult(v1, v2) == sum); // still old code 33 | 34 | std::cout << "JET_TEST: disable(failed_comp:3); enable(failed_comp:4)" << std::endl; 35 | waitForReload(); // success 36 | REQUIRE(failedCompilationComputeResult(v1, v2) == mul); // new code 37 | } 38 | -------------------------------------------------------------------------------- /tests/src/good/GlobalFreeFunction_test.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include "utility/GlobalFreeFunction.hpp" 6 | #include "Globals.hpp" 7 | #include "WaitForReload.hpp" 8 | 9 | TEST_CASE("Reload of global free function", "[function]") 10 | { 11 | int v1 = 23; 12 | int v2 = 45; 13 | int sum = v1 + v2; 14 | int mul = v1 * v2; 15 | 16 | REQUIRE(computeResult(v1, v2) == sum); 17 | 18 | std::cout << "JET_TEST: disable(glob_free_func:1); enable(glob_free_func:2)" << std::endl; 19 | waitForReload(); 20 | 21 | REQUIRE(computeResult(v1, v2) == mul); 22 | } 23 | -------------------------------------------------------------------------------- /tests/src/good/GlobalVariableAddress_test.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include "utility/GlobalVariableAddress.hpp" 6 | #include "Globals.hpp" 7 | #include "WaitForReload.hpp" 8 | 9 | TEST_CASE("Relocation of global variable, comparing address", "[variable]") 10 | { 11 | auto oldVariableAddress = getGlobalVariableAddress(); 12 | 13 | std::cout << "JET_TEST: disable(glob_var_addr:1)" << std::endl; 14 | waitForReload(); 15 | 16 | auto newVariableAddress = getGlobalVariableAddress(); 17 | REQUIRE(oldVariableAddress == newVariableAddress); 18 | } 19 | -------------------------------------------------------------------------------- /tests/src/good/GlobalVariable_test.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include "utility/GlobalVariable.hpp" 6 | #include "Globals.hpp" 7 | #include "WaitForReload.hpp" 8 | 9 | TEST_CASE("Relocation of global variable", "[variable]") 10 | { 11 | auto beforeReload = getNextGlobal1(); 12 | REQUIRE(beforeReload.first == 0); 13 | REQUIRE(beforeReload.second == 10); 14 | 15 | std::cout << "JET_TEST: disable(glob_var:1); enable(glob_var:2)" << std::endl; 16 | waitForReload(); 17 | 18 | auto afterReload = getNextGlobal1(); 19 | REQUIRE(afterReload.first == 1); 20 | REQUIRE(afterReload.second == 11); 21 | } 22 | -------------------------------------------------------------------------------- /tests/src/good/InternalLinkageFunction_test.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include "utility/InternalLinkageFunction.hpp" 6 | #include "Globals.hpp" 7 | #include "WaitForReload.hpp" 8 | 9 | TEST_CASE("Reload of function with internal linkage", "[function]") 10 | { 11 | int v1 = 23; 12 | int v2 = 45; 13 | int sum = v1 + v2; 14 | int mul = v1 * v2; 15 | using InternalFunctionPtrT = int (*)(int,int); 16 | auto internalFunctionPtr = reinterpret_cast(getInternalFunctionAddress()); 17 | 18 | REQUIRE(computeResult1(v1, v2) == sum); 19 | REQUIRE((*internalFunctionPtr)(v1, v2) == sum); 20 | 21 | std::cout << "JET_TEST: disable(intern_func:1); enable(intern_func:2)" << std::endl; 22 | waitForReload(); 23 | 24 | REQUIRE(computeResult1(v1, v2) == mul); 25 | REQUIRE((*internalFunctionPtr)(v1, v2) == mul); 26 | } 27 | -------------------------------------------------------------------------------- /tests/src/good/LambdaFunctionWithCapturesGoodCase_test.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include "utility/LambdaFunctionWithCapturesGoodCase.hpp" 6 | #include "Globals.hpp" 7 | #include "WaitForReload.hpp" 8 | 9 | TEST_CASE("Reload of lambda function with captured data and another lamda in this file, good case", "[function]") 10 | { 11 | int v1 = 23; 12 | int v2 = 45; 13 | int sum = v1 + v2; 14 | int mul = v1 * v2; 15 | auto lambda = createLambdaFunctionWithCapturesGoodCase(); 16 | 17 | REQUIRE(lambda(v1, v2) == sum); 18 | 19 | std::cout << "JET_TEST: disable(lamb_capt_good:1); enable(lamb_capt_good:2)" << std::endl; 20 | waitForReload(); 21 | 22 | REQUIRE(lambda(v1, v2) == mul); 23 | } 24 | -------------------------------------------------------------------------------- /tests/src/good/LambdaFunctionWithCaptures_test.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include "utility/LambdaFunctionWithCaptures.hpp" 6 | #include "Globals.hpp" 7 | #include "WaitForReload.hpp" 8 | 9 | TEST_CASE("Reload of lambda function with captured data", "[function]") 10 | { 11 | int v1 = 23; 12 | int v2 = 45; 13 | int sum = v1 + v2; 14 | int mul = v1 * v2; 15 | auto lambda = createLambdaFunctionWithCaptures(); 16 | 17 | REQUIRE(lambda(v1, v2) == sum); 18 | 19 | std::cout << "JET_TEST: disable(lamb_capt:1); enable(lamb_capt:2)" << std::endl; 20 | waitForReload(); 21 | 22 | REQUIRE(lambda(v1, v2) == mul); 23 | } 24 | -------------------------------------------------------------------------------- /tests/src/good/LambdaFunction_test.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include "utility/LambdaFunction.hpp" 6 | #include "Globals.hpp" 7 | #include "WaitForReload.hpp" 8 | 9 | TEST_CASE("Reload of lambda function with no captured data", "[function]") 10 | { 11 | int v1 = 23; 12 | int v2 = 45; 13 | int sum = v1 + v2; 14 | int mul = v1 * v2; 15 | auto lambda = createLambdaFunction(); 16 | 17 | REQUIRE(lambda(v1, v2) == sum); 18 | 19 | std::cout << "JET_TEST: disable(lamb_nocapt:1); enable(lamb_nocapt:2)" << std::endl; 20 | waitForReload(); 21 | 22 | REQUIRE(lambda(v1, v2) == mul); 23 | } 24 | -------------------------------------------------------------------------------- /tests/src/good/LostModification_test.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include "utility/LostModification.hpp" 5 | #include "WaitForReload.hpp" 6 | 7 | TEST_CASE("Lost modifications when adding new file", "[common]") 8 | { 9 | auto beforeReload = lostModificationGetValue(); 10 | REQUIRE(beforeReload == 12); 11 | 12 | std::cout << "JET_TEST: disable(lost_mod:1); enable(lost_mod:2)" << std::endl; 13 | waitForReload(); // Load time error 14 | auto afterReload1 = lostModificationGetValue(); 15 | REQUIRE(afterReload1 == 12); 16 | 17 | std::cout << "JET_TEST: enable(lost_mod:3)" << std::endl; 18 | waitForReload(5000); // 2 files should be reloaded 19 | auto afterReload2 = lostModificationGetValue(); 20 | REQUIRE(afterReload2 == 34); 21 | } 22 | -------------------------------------------------------------------------------- /tests/src/good/MacosFunctionOutOfScope_test.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include "utility/MacosFunctionOutOfScope.hpp" 6 | #include "Globals.hpp" 7 | #include "WaitForReload.hpp" 8 | 9 | TEST_CASE("Function address is out of readable memory", "[function]") 10 | { 11 | REQUIRE(getStdStringValue() == "some string"); 12 | 13 | std::cout << "JET_TEST: disable(fun_out_of_scope:1); enable(fun_out_of_scope:2)" << std::endl; 14 | waitForReload(); 15 | 16 | REQUIRE(getStdStringValue() == "some another string"); 17 | 18 | std::cout << "JET_TEST: disable(fun_out_of_scope:2); enable(fun_out_of_scope:1)" << std::endl; 19 | waitForReload(); 20 | 21 | REQUIRE(getStdStringValue() == "some string"); 22 | } 23 | -------------------------------------------------------------------------------- /tests/src/good/ModifyFileDuringReload_test.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include "utility/ModifyFileDuringReload.hpp" 6 | #include "Globals.hpp" 7 | #include "WaitForReload.hpp" 8 | 9 | TEST_CASE("Bug caused by modifying some source file during code reload process", "[common]") 10 | { 11 | int v1 = 28; 12 | int v2 = 7; 13 | int sum = v1 + v2; 14 | int mul = v1 * v2; 15 | int diff = v1 - v2; 16 | int div = v1 / v2; 17 | 18 | REQUIRE(mfdrComputeResult(v1, v2) == sum); 19 | 20 | std::cout << "JET_TEST: disable(mfdr:1); enable(mfdr:2)" << std::endl; 21 | runAfterDelayAndWaitForReload([] { 22 | g_live->tryReload(); 23 | g_live->update(); 24 | g_live->update(); 25 | std::cout << "JET_TEST: disable(mfdr:2); enable(mfdr:3)" << std::endl; 26 | }); 27 | REQUIRE(mfdrComputeResult(v1, v2) == mul); 28 | 29 | runAfterDelayAndWaitForReload([] { 30 | g_live->tryReload(); 31 | }); 32 | REQUIRE(mfdrComputeResult(v1, v2) == diff); 33 | 34 | 35 | 36 | std::cout << "JET_TEST: disable(mfdr:3); enable(mfdr:4)" << std::endl; 37 | runAfterDelayAndWaitForReload([] { 38 | g_live->tryReload(); 39 | g_live->update(); 40 | g_live->update(); 41 | std::cout << "JET_TEST: disable(mfdr:4); enable(mfdr:1)" << std::endl; 42 | }); 43 | REQUIRE(mfdrComputeResult(v1, v2) == div); 44 | 45 | runAfterDelayAndWaitForReload([] { 46 | g_live->tryReload(); 47 | g_live->update(); 48 | }); 49 | REQUIRE(mfdrComputeResult(v1, v2) == sum); 50 | } 51 | -------------------------------------------------------------------------------- /tests/src/good/MultipleDefinitions_test.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include "utility/MultipleDefinitions.hpp" 6 | #include "Globals.hpp" 7 | #include "WaitForReload.hpp" 8 | 9 | TEST_CASE("Multiple definitions of symbols after reload, circular symbols dependency", "[common]") 10 | { 11 | auto beforeReload = multipleDefinitionsGetValue(); 12 | REQUIRE(beforeReload == 12); 13 | 14 | std::cout << "JET_TEST: disable(mul_def:1); enable(mul_def:2)" << std::endl; 15 | waitForReload(5000); 16 | 17 | auto afterReload = multipleDefinitionsGetValue(); 18 | REQUIRE(afterReload == 88); 19 | } 20 | 21 | -------------------------------------------------------------------------------- /tests/src/good/NewCompilationUnit_test.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include "utility/NewCompilationUnit.hpp" 6 | #include "Globals.hpp" 7 | #include "WaitForReload.hpp" 8 | 9 | TEST_CASE("Adding new compilation unit in runtime", "[common]") 10 | { 11 | int v1 = 23; 12 | int v2 = 45; 13 | int sum = v1 + v2; 14 | int mul = v1 * v2; 15 | 16 | REQUIRE(newCompilationUnitComputeResult(v1, v2) == sum); 17 | 18 | std::cout << "JET_TEST: disable(new_cu:1); enable(new_cu:2)" << std::endl; 19 | waitForReload(5000); 20 | REQUIRE(newCompilationUnitComputeResult(v1, v2) == mul); 21 | 22 | std::cout << "JET_TEST: disable(new_cu:3); enable(new_cu:4)" << std::endl; 23 | waitForReload(); 24 | REQUIRE(newCompilationUnitComputeResult(v1, v2) == mul + sum); 25 | } 26 | -------------------------------------------------------------------------------- /tests/src/good/NewHeaderDependency_test.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include "utility/NewHeaderDependency.hpp" 6 | #include "Globals.hpp" 7 | #include "WaitForReload.hpp" 8 | 9 | TEST_CASE("Adding new header dependency in runtime", "[common]") 10 | { 11 | int v1 = 52; 12 | int v2 = 65; 13 | int sum = v1 + v2; 14 | int mul = v1 * v2; 15 | 16 | REQUIRE(newHeaderDependencyComputeResult(v1, v2) == sum); 17 | 18 | std::cout << "JET_TEST: disable(new_header:1); enable(new_header:2)" << std::endl; 19 | waitForReload(); 20 | REQUIRE(newHeaderDependencyComputeResult(v1, v2) == mul); 21 | 22 | std::cout << "JET_TEST: disable(new_header:3); enable(new_header:4)" << std::endl; 23 | waitForReload(); 24 | REQUIRE(newHeaderDependencyComputeResult(v1, v2) == mul + sum); 25 | } 26 | -------------------------------------------------------------------------------- /tests/src/good/OneFrameCompileReload_test.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "utility/OneFrameCompileReload.hpp" 7 | #include "Globals.hpp" 8 | #include "WaitForReload.hpp" 9 | 10 | TEST_CASE("Checking crash if compilation and reload request appear in the same frame", "[common]") 11 | { 12 | auto beforeReload = ofcrGetNext(); 13 | REQUIRE(beforeReload == 4); 14 | 15 | std::cout << "JET_TEST: disable(ofcr_crash:1)" << std::endl; 16 | std::this_thread::sleep_for(std::chrono::milliseconds{50}); 17 | g_live->tryReload(); 18 | std::this_thread::sleep_for(std::chrono::milliseconds{50}); 19 | waitForReload(); 20 | 21 | auto afterReload = ofcrGetNext(); 22 | REQUIRE(afterReload == 8); 23 | } 24 | -------------------------------------------------------------------------------- /tests/src/good/ReloadAfterFailedCompilation_test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "utility/ReloadAfterFailedCompilation1.hpp" 4 | #include "utility/ReloadAfterFailedCompilation2.hpp" 5 | #include "WaitForReload.hpp" 6 | 7 | TEST_CASE("Reload after compilation error", "[common]") 8 | { 9 | auto beforeReload1 = rafcGetValue1(); 10 | auto beforeReload2 = rafcGetValue2(); 11 | REQUIRE(beforeReload1 == 15); 12 | REQUIRE(beforeReload2 == 56); 13 | 14 | std::cout << "JET_TEST: disable(rafc:1); enable(rafc:2)" << std::endl; 15 | waitForReload(); // Getting compilation error, should not reload anything 16 | REQUIRE(beforeReload1 == rafcGetValue1()); 17 | REQUIRE(beforeReload2 == rafcGetValue2()); 18 | 19 | std::cout << "JET_TEST: disable(rafc:2); enable(rafc:3)" << std::endl; 20 | waitForReload(); // Now reload everything 21 | REQUIRE(rafcGetValue1() == 19); 22 | REQUIRE(rafcGetValue2() == 69); 23 | } 24 | -------------------------------------------------------------------------------- /tests/src/good/ReloadOnSignal_test.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include "utility/ReloadOnSignal.hpp" 6 | #include "Globals.hpp" 7 | #include "WaitForReload.hpp" 8 | 9 | TEST_CASE("Reloading code when SIGUSR1 is received", "[common]") 10 | { 11 | auto beforeReload = reloadOnSignalGetValue(); 12 | REQUIRE(beforeReload == 42); 13 | 14 | std::cout << "JET_TEST: disable(reload_signal:1); enable(reload_signal:2)" << std::endl; 15 | waitForReloadWithSignal(); 16 | 17 | auto afterReload = reloadOnSignalGetValue(); 18 | REQUIRE(afterReload == 64); 19 | } 20 | -------------------------------------------------------------------------------- /tests/src/good/StaticFunctionLocalVariableAddress_test.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include "utility/StaticFunctionLocalVariableAddress.hpp" 6 | #include "Globals.hpp" 7 | #include "WaitForReload.hpp" 8 | 9 | TEST_CASE("Relocation of function local static variable, comparing address", "[variable]") 10 | { 11 | auto beforeReload = getStaticFunctionLocalVariableAddress(); 12 | 13 | std::cout << "JET_TEST: disable(st_func_loc_var_addr:1)" << std::endl; 14 | waitForReload(); 15 | 16 | auto afterReload = getStaticFunctionLocalVariableAddress(); 17 | REQUIRE(beforeReload == afterReload); 18 | } 19 | -------------------------------------------------------------------------------- /tests/src/good/StaticFunctionLocalVariable_test.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include "utility/StaticFunctionLocalVariable.hpp" 6 | #include "Globals.hpp" 7 | #include "WaitForReload.hpp" 8 | 9 | TEST_CASE("Relocation of function local static variable", "[variable]") 10 | { 11 | auto beforeReload = getNext2(); 12 | REQUIRE(beforeReload == 4); 13 | 14 | std::cout << "JET_TEST: disable(st_func_loc_var:1)" << std::endl; 15 | waitForReload(); 16 | 17 | auto afterReload = getNext2(); 18 | REQUIRE(afterReload == 8); 19 | } 20 | -------------------------------------------------------------------------------- /tests/src/good/StaticInternalVariableAddress_test.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include "utility/StaticInternalVariableAddress.hpp" 6 | #include "Globals.hpp" 7 | #include "WaitForReload.hpp" 8 | 9 | TEST_CASE("Relocation of static internal variable, comparing address", "[variable]") 10 | { 11 | auto oldVariableAddress = getStaticInternalVariableAddress(); 12 | 13 | std::cout << "JET_TEST: disable(st_intern_var_addr:1)" << std::endl; 14 | waitForReload(); 15 | 16 | auto newVariableAddress = getStaticInternalVariableAddress(); 17 | REQUIRE(oldVariableAddress == newVariableAddress); 18 | } 19 | -------------------------------------------------------------------------------- /tests/src/good/StaticInternalVariable_test.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include "utility/StaticInternalVariable.hpp" 6 | #include "Globals.hpp" 7 | #include "WaitForReload.hpp" 8 | 9 | TEST_CASE("Relocation of static internal variable", "[variable]") 10 | { 11 | auto beforeReload = getNext1(); 12 | REQUIRE(beforeReload.first == 0); 13 | REQUIRE(beforeReload.second == 0); 14 | 15 | std::cout << "JET_TEST: disable(st_intern_var:1); enable(st_intern_var:2)" << std::endl; 16 | waitForReload(); 17 | 18 | auto afterReload = getNext1(); 19 | REQUIRE(afterReload.first == 1); 20 | REQUIRE(afterReload.second == 1); 21 | } 22 | -------------------------------------------------------------------------------- /tests/src/good/StaticVariableAddress_test.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include "utility/StaticVariableAddress.hpp" 6 | #include "Globals.hpp" 7 | #include "WaitForReload.hpp" 8 | 9 | TEST_CASE("Relocation of static variable, comparing address", "[variable]") 10 | { 11 | auto oldVariableAddress = getStaticVariableAddress(); 12 | 13 | std::cout << "JET_TEST: disable(st_var_addr:1)" << std::endl; 14 | waitForReload(); 15 | 16 | auto newVariableAddress = getStaticVariableAddress(); 17 | REQUIRE(oldVariableAddress == newVariableAddress); 18 | } 19 | -------------------------------------------------------------------------------- /tests/src/good/StaticVariableSameName_test.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include "utility/StaticVariableSameName1.hpp" 6 | #include "utility/StaticVariableSameName2.hpp" 7 | #include "Globals.hpp" 8 | #include "WaitForReload.hpp" 9 | 10 | TEST_CASE("Relocation of static variables with same names in different compilation units", "[variable]") 11 | { 12 | auto beforeReload1 = getNextSameName1(); 13 | auto beforeReload2 = getNextSameName2(); 14 | REQUIRE(beforeReload1.first == 0); 15 | REQUIRE(beforeReload1.second == 10); 16 | REQUIRE(beforeReload2.first == 10); 17 | REQUIRE(beforeReload2.second == 110); 18 | 19 | std::cout << "JET_TEST: disable(st_var_same_name:1); enable(st_var_same_name:2)" << std::endl; 20 | waitForReload(); 21 | 22 | auto afterReload1 = getNextSameName1(); 23 | auto afterReload2 = getNextSameName2(); 24 | REQUIRE(afterReload1.first == 1); 25 | REQUIRE(afterReload1.second == 11); 26 | REQUIRE(afterReload2.first == 11); 27 | REQUIRE(afterReload2.second == 111); 28 | } 29 | -------------------------------------------------------------------------------- /tests/src/good/StaticVariable_test.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include "utility/StaticVariable.hpp" 6 | #include "Globals.hpp" 7 | #include "WaitForReload.hpp" 8 | 9 | TEST_CASE("Relocation of static variable", "[variable]") 10 | { 11 | auto beforeReload = getNext(); 12 | REQUIRE(beforeReload.first == 0); 13 | REQUIRE(beforeReload.second == 10); 14 | 15 | std::cout << "JET_TEST: disable(rel_stat_var:1); enable(rel_stat_var:2)" << std::endl; 16 | waitForReload(); 17 | 18 | auto afterReload = getNext(); 19 | REQUIRE(afterReload.first == 1); 20 | REQUIRE(afterReload.second == 11); 21 | } 22 | -------------------------------------------------------------------------------- /tests/src/good/UndefinedSymbolDeep_test.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include "utility/UndefinedSymbolDeep.hpp" 6 | #include "Globals.hpp" 7 | #include "WaitForReload.hpp" 8 | 9 | TEST_CASE("Undefined symbols after reload, deep symbols dependency", "[common]") 10 | { 11 | auto beforeReload = undefinedDeepGetValue(); 12 | REQUIRE(beforeReload == 33); 13 | 14 | std::cout << "JET_TEST: disable(undefined_sym_deep:1); enable(undefined_sym_deep:2)" << std::endl; 15 | waitForReload(); 16 | 17 | auto afterReload = undefinedDeepGetValue(); 18 | REQUIRE(afterReload == 56); 19 | } 20 | -------------------------------------------------------------------------------- /tests/src/good/UndefinedSymbol_test.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include "utility/UndefinedSymbol.hpp" 6 | #include "Globals.hpp" 7 | #include "WaitForReload.hpp" 8 | 9 | TEST_CASE("Undefined symbols after reload", "[common]") 10 | { 11 | auto beforeReload = undefinedGetValue(); 12 | REQUIRE(beforeReload == 21); 13 | 14 | std::cout << "JET_TEST: disable(undefined_sym:1); enable(undefined_sym:2)" << std::endl; 15 | waitForReload(); 16 | 17 | auto afterReload = undefinedGetValue(); 18 | REQUIRE(afterReload == 42); 19 | } 20 | -------------------------------------------------------------------------------- /tests/src/main.cpp: -------------------------------------------------------------------------------- 1 | 2 | #define CATCH_CONFIG_RUNNER 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "TestListener.hpp" 9 | #include 10 | #include "Stacktrace.hpp" 11 | 12 | TestListener* g_testListenerPtr = nullptr; 13 | jet::Live* g_live = nullptr; 14 | 15 | int main(int argc, char* argv[]) 16 | { 17 | setupSignalHandlers(); 18 | 19 | std::cout.setf(std::ios::unitbuf); 20 | std::cout << "Running tests" << std::endl; 21 | 22 | auto testListener = jet::make_unique(); 23 | g_testListenerPtr = testListener.get(); 24 | 25 | auto live = jet::make_unique(std::move(testListener)); 26 | g_live = live.get(); 27 | 28 | while (!g_live->isInitialized()) { 29 | std::this_thread::sleep_for(std::chrono::milliseconds(100)); 30 | } 31 | 32 | auto res = Catch::Session().run(argc, argv); 33 | 34 | for (int i = 0; i < 10; i++) { 35 | g_live->update(); 36 | std::this_thread::sleep_for(std::chrono::milliseconds(100)); 37 | } 38 | 39 | live.reset(); 40 | g_live = nullptr; 41 | testListener.reset(); 42 | g_testListenerPtr = nullptr; 43 | 44 | return res; 45 | } 46 | -------------------------------------------------------------------------------- /tests/src/utility/ClassInstanceMethod.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "ClassInstanceMethod.hpp" 3 | 4 | int ClassInstanceMethod::computeResult(int v1, int v2) 5 | { 6 | return v1 + v2; // 7 | // return v1 * v2; // 8 | } 9 | -------------------------------------------------------------------------------- /tests/src/utility/ClassInstanceMethod.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | class ClassInstanceMethod 5 | { 6 | public: 7 | int computeResult(int v1, int v2); 8 | }; 9 | -------------------------------------------------------------------------------- /tests/src/utility/ClassStaticMethod.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "ClassStaticMethod.hpp" 3 | 4 | int ClassStaticMethod::computeResult(int v1, int v2) 5 | { 6 | return v1 + v2; // 7 | // return v1 * v2; // 8 | } 9 | -------------------------------------------------------------------------------- /tests/src/utility/ClassStaticMethod.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | class ClassStaticMethod 5 | { 6 | public: 7 | static int computeResult(int v1, int v2); 8 | }; 9 | -------------------------------------------------------------------------------- /tests/src/utility/ClassVirtualMethod.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "ClassVirtualMethod.hpp" 3 | 4 | int ClassVirtualMethod::computeResult(int v1, int v2) 5 | { 6 | return v1 + v2; // 7 | // return v1 * v2; // 8 | } 9 | -------------------------------------------------------------------------------- /tests/src/utility/ClassVirtualMethod.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include "IClassVirtualMethod.hpp" 5 | 6 | class ClassVirtualMethod : public IClassVirtualMethod 7 | { 8 | public: 9 | int computeResult(int v1, int v2) override; 10 | }; 11 | -------------------------------------------------------------------------------- /tests/src/utility/CommonSection.c: -------------------------------------------------------------------------------- 1 | 2 | #include "CommonSection.h" 3 | 4 | int commonSectionVariable; 5 | char initialized = 0; 6 | 7 | int getCommonSectionVar() 8 | { 9 | if (initialized == 0) { 10 | commonSectionVariable = 10; 11 | initialized = 1; 12 | } 13 | // (void)initialized; // 14 | commonSectionVariable += 1; 15 | commonSectionVariable -= 1; 16 | return commonSectionVariable++; 17 | } 18 | 19 | void* getCommonSectionVarAddress() 20 | { 21 | commonSectionVariable += 1; 22 | commonSectionVariable -= 1; 23 | return (void*)(&commonSectionVariable); 24 | } 25 | 26 | -------------------------------------------------------------------------------- /tests/src/utility/CommonSection.h: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | int getCommonSectionVar(); 5 | void* getCommonSectionVarAddress(); 6 | -------------------------------------------------------------------------------- /tests/src/utility/ExternGlobalVariable.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "ExternGlobalVariable.hpp" 3 | 4 | extern int someExternGlobalVariable; 5 | 6 | std::pair getNextGlobal() 7 | { 8 | someExternGlobalVariable += 1; 9 | someExternGlobalVariable -= 1; 10 | return {0, someExternGlobalVariable++};; // 11 | // return {1, someExternGlobalVariable++};; // 12 | } 13 | -------------------------------------------------------------------------------- /tests/src/utility/ExternGlobalVariable.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | 6 | std::pair getNextGlobal(); 7 | -------------------------------------------------------------------------------- /tests/src/utility/ExternGlobalVariableAddress.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "ExternGlobalVariableAddress.hpp" 3 | 4 | extern int externGlobalVariableCheckingAddress; 5 | 6 | void* getExternGlobalVariableAddress() 7 | { 8 | externGlobalVariableCheckingAddress += 1; 9 | externGlobalVariableCheckingAddress -= 1; 10 | (void)externGlobalVariableCheckingAddress; // 11 | return reinterpret_cast(&externGlobalVariableCheckingAddress); 12 | } 13 | -------------------------------------------------------------------------------- /tests/src/utility/ExternGlobalVariableAddress.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | void* getExternGlobalVariableAddress(); 5 | -------------------------------------------------------------------------------- /tests/src/utility/FailedCompilationCrash.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "FailedCompilationCrash.hpp" 3 | 4 | int failedCompilationComputeResult(int v1, int v2) 5 | { 6 | return v1 + v2; // 7 | // return v1 + v2; // 8 | // not compilable code // 9 | // return v1 * v2; // 10 | } 11 | -------------------------------------------------------------------------------- /tests/src/utility/FailedCompilationCrash.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | int failedCompilationComputeResult(int v1, int v2); 5 | -------------------------------------------------------------------------------- /tests/src/utility/GlobalFreeFunction.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "GlobalFreeFunction.hpp" 3 | 4 | int computeResult(int v1, int v2) 5 | { 6 | return v1 + v2; // 7 | // return v1 * v2; // 8 | } 9 | -------------------------------------------------------------------------------- /tests/src/utility/GlobalFreeFunction.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | int computeResult(int v1, int v2); 5 | -------------------------------------------------------------------------------- /tests/src/utility/GlobalVariable.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "GlobalVariable.hpp" 3 | 4 | int someGlobalVariable = 10; 5 | 6 | std::pair getNextGlobal1() 7 | { 8 | someGlobalVariable += 1; 9 | someGlobalVariable -= 1; 10 | return {0, someGlobalVariable++}; // 11 | // return {1, someGlobalVariable++}; // 12 | } 13 | -------------------------------------------------------------------------------- /tests/src/utility/GlobalVariable.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | 6 | std::pair getNextGlobal1(); 7 | -------------------------------------------------------------------------------- /tests/src/utility/GlobalVariableAddress.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "GlobalVariableAddress.hpp" 3 | 4 | int someGlobalVariableCheckingAddress = 10; 5 | 6 | void* getGlobalVariableAddress() 7 | { 8 | someGlobalVariableCheckingAddress += 1; 9 | someGlobalVariableCheckingAddress -= 1; 10 | (void)someGlobalVariableCheckingAddress; // 11 | return reinterpret_cast(&someGlobalVariableCheckingAddress); 12 | } 13 | -------------------------------------------------------------------------------- /tests/src/utility/GlobalVariableAddress.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | void* getGlobalVariableAddress(); 5 | -------------------------------------------------------------------------------- /tests/src/utility/IClassVirtualMethod.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | class IClassVirtualMethod 5 | { 6 | public: 7 | virtual ~IClassVirtualMethod() {} 8 | 9 | virtual int computeResult(int v1, int v2) = 0; 10 | }; 11 | -------------------------------------------------------------------------------- /tests/src/utility/InternalLinkageFunction.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "InternalLinkageFunction.hpp" 3 | 4 | namespace 5 | { 6 | int internalComputeResult(int v1, int v2) 7 | { 8 | return v1 + v2; // 9 | // return v1 * v2; // 10 | } 11 | } 12 | 13 | void* getInternalFunctionAddress() 14 | { 15 | return reinterpret_cast(::internalComputeResult); 16 | } 17 | 18 | int computeResult1(int v1, int v2) 19 | { 20 | return ::internalComputeResult(v1, v2); 21 | } 22 | -------------------------------------------------------------------------------- /tests/src/utility/InternalLinkageFunction.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | void* getInternalFunctionAddress(); 5 | int computeResult1(int v1, int v2); 6 | -------------------------------------------------------------------------------- /tests/src/utility/LambdaFunction.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "LambdaFunction.hpp" 3 | 4 | std::function createLambdaFunction() 5 | { 6 | return [] (int v1, int v2) { 7 | return v1 + v2; // 8 | // return v1 * v2; // 9 | }; 10 | } 11 | -------------------------------------------------------------------------------- /tests/src/utility/LambdaFunction.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | 6 | std::function createLambdaFunction(); 7 | -------------------------------------------------------------------------------- /tests/src/utility/LambdaFunctionWithCaptures.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "LambdaFunctionWithCaptures.hpp" 3 | 4 | std::function createLambdaFunctionWithCaptures() 5 | { 6 | int dummyInt1 = 45; 7 | int dummyInt2 = -45; 8 | 9 | return [dummyInt1, dummyInt2] (int v1, int v2) { 10 | return v1 + v2 + dummyInt1 + dummyInt2; // 11 | // return v1 * v2 + dummyInt1 + dummyInt2; // 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /tests/src/utility/LambdaFunctionWithCaptures.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | 6 | std::function createLambdaFunctionWithCaptures(); 7 | -------------------------------------------------------------------------------- /tests/src/utility/LambdaFunctionWithCapturesBadCase.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "LambdaFunctionWithCapturesBadCase.hpp" 3 | 4 | std::function createLambdaFunctionWithCapturesBadCase() 5 | { 6 | int dummyInt1 = 45; 7 | int dummyInt2 = -45; 8 | // auto dummyLambda = [dummyInt1, dummyInt2] (int v1, int v2) { // 9 | // return v1 + v2 - 123 + dummyInt1 - dummyInt2; // 10 | // }; // 11 | // volatile int res = dummyLambda(55, 44); // 12 | 13 | return [dummyInt1, dummyInt2] (int v1, int v2) { 14 | return v1 + v2 + dummyInt1 + dummyInt2; // 15 | // return v1 * v2 + dummyInt1 + dummyInt2; // 16 | }; 17 | } 18 | -------------------------------------------------------------------------------- /tests/src/utility/LambdaFunctionWithCapturesBadCase.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | 6 | std::function createLambdaFunctionWithCapturesBadCase(); 7 | -------------------------------------------------------------------------------- /tests/src/utility/LambdaFunctionWithCapturesBadCase2.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "LambdaFunctionWithCapturesBadCase2.hpp" 3 | 4 | std::function createLambdaFunctionWithCapturesBadCase2() 5 | { 6 | int dummyInt1 = 45; 7 | int dummyInt2 = -45; 8 | // auto dummyLambda = [dummyInt1, dummyInt2] (int v1, int v2, float v3) { // 9 | // return v1 + v2 - 123 + dummyInt1 - dummyInt2 + static_cast(v3); // 10 | // }; // 11 | // volatile int res = dummyLambda(55, 44, 33.3f); // 12 | 13 | return [dummyInt1, dummyInt2] (int v1, int v2) { 14 | return v1 + v2 + dummyInt1 + dummyInt2; // 15 | // return v1 * v2 + dummyInt1 + dummyInt2; // 16 | }; 17 | } 18 | -------------------------------------------------------------------------------- /tests/src/utility/LambdaFunctionWithCapturesBadCase2.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | 6 | std::function createLambdaFunctionWithCapturesBadCase2(); 7 | -------------------------------------------------------------------------------- /tests/src/utility/LambdaFunctionWithCapturesGoodCase.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "LambdaFunctionWithCapturesGoodCase.hpp" 3 | 4 | std::function createLambdaFunctionWithCapturesGoodCase() 5 | { 6 | int dummyInt1 = 45; 7 | int dummyInt2 = -45; 8 | auto dummyLambda = [dummyInt1, dummyInt2] (int v1, int v2) { 9 | return v1 + v2 - 123 + dummyInt1 - dummyInt2; 10 | }; 11 | volatile int res = dummyLambda(55, 44); 12 | 13 | return [dummyInt1, dummyInt2] (int v1, int v2) { 14 | return v1 + v2 + dummyInt1 + dummyInt2; // 15 | // return v1 * v2 + dummyInt1 + dummyInt2; // 16 | }; 17 | } 18 | -------------------------------------------------------------------------------- /tests/src/utility/LambdaFunctionWithCapturesGoodCase.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | 6 | std::function createLambdaFunctionWithCapturesGoodCase(); 7 | -------------------------------------------------------------------------------- /tests/src/utility/LostModification.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "LostModification.hpp" 3 | // #include "LostModification2.hpp" // 4 | 5 | int lostModificationGetValue() 6 | { 7 | return 12; // 8 | // return lostModificationGetAnotherValue(); // 9 | } 10 | -------------------------------------------------------------------------------- /tests/src/utility/LostModification.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | int lostModificationGetValue(); 5 | -------------------------------------------------------------------------------- /tests/src/utility/LostModification2.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "LostModification2.hpp" 3 | 4 | int lostModificationGetAnotherValue() 5 | { 6 | return 34; 7 | } 8 | -------------------------------------------------------------------------------- /tests/src/utility/LostModification2.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | int lostModificationGetAnotherValue(); 5 | -------------------------------------------------------------------------------- /tests/src/utility/MacosFunctionOutOfScope.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "MacosFunctionOutOfScope.hpp" 3 | 4 | std::string getStdStringValue() 5 | { 6 | std::string stringValue = "some "; // 7 | // std::string stringValue = "some another "; // 8 | stringValue += "string"; 9 | return stringValue; 10 | } 11 | -------------------------------------------------------------------------------- /tests/src/utility/MacosFunctionOutOfScope.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | 6 | std::string getStdStringValue(); 7 | -------------------------------------------------------------------------------- /tests/src/utility/ModifyFileDuringReload.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "ModifyFileDuringReload.hpp" 3 | 4 | int mfdrComputeResult(int v1, int v2) 5 | { 6 | return v1 + v2; // 7 | // return v1 * v2; // 8 | // return v1 - v2; // 9 | // return v1 / v2; // 10 | } 11 | 12 | -------------------------------------------------------------------------------- /tests/src/utility/ModifyFileDuringReload.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | int mfdrComputeResult(int v1, int v2); 5 | -------------------------------------------------------------------------------- /tests/src/utility/MultipleDefinitions.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "MultipleDefinitions.hpp" 3 | #include "MultipleDefinitions/MultipleDefinitions1.hpp" 4 | 5 | static int multipleDefinitionsSomeStaticVariable = 11; 6 | 7 | int multipleDefinitionsGetValue() 8 | { 9 | return ++multipleDefinitionsSomeStaticVariable; // 10 | // return MulDefSomeClass{}.multipleDefinitionsGetValue2(); // 11 | } 12 | -------------------------------------------------------------------------------- /tests/src/utility/MultipleDefinitions.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | int multipleDefinitionsGetValue(); 5 | -------------------------------------------------------------------------------- /tests/src/utility/MultipleDefinitions/MultipleDefinitions1.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "MultipleDefinitions1.hpp" 3 | #include "MultipleDefinitions2.hpp" 4 | 5 | static int multipleDefinitionsSomeStaticVariable2 = 87; 6 | 7 | int MulDefSomeClass::multipleDefinitionsGetValue2() 8 | { 9 | return multipleDefinitionsAnotherGetValue(); 10 | } 11 | 12 | int multipleDefinitionsCircularGetValue() 13 | { 14 | return ++multipleDefinitionsSomeStaticVariable2; 15 | } 16 | -------------------------------------------------------------------------------- /tests/src/utility/MultipleDefinitions/MultipleDefinitions1.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | class MulDefSomeClass 5 | { 6 | public: 7 | int multipleDefinitionsGetValue2(); 8 | }; 9 | 10 | int multipleDefinitionsCircularGetValue(); 11 | -------------------------------------------------------------------------------- /tests/src/utility/MultipleDefinitions/MultipleDefinitions2.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "utility/MultipleDefinitions/MultipleDefinitions1.hpp" 3 | 4 | int multipleDefinitionsAnotherGetValue() 5 | { 6 | return multipleDefinitionsCircularGetValue(); 7 | } 8 | -------------------------------------------------------------------------------- /tests/src/utility/MultipleDefinitions/MultipleDefinitions2.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | int multipleDefinitionsAnotherGetValue(); 5 | -------------------------------------------------------------------------------- /tests/src/utility/NewCompilationUnit.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "NewCompilationUnit.hpp" 3 | //#include "NewCompilationUnit/NewCompilationUnit2.hpp" // 4 | 5 | int newCompilationUnitComputeResult(int v1, int v2) 6 | { 7 | return v1 + v2; // 8 | // return newCompilationUnit2ComputeResult(v1, v2); // 9 | } 10 | -------------------------------------------------------------------------------- /tests/src/utility/NewCompilationUnit.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | int newCompilationUnitComputeResult(int v1, int v2); 5 | -------------------------------------------------------------------------------- /tests/src/utility/NewCompilationUnit/NewCompilationUnit2.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "NewCompilationUnit2.hpp" 3 | 4 | int newCompilationUnit2ComputeResult(int v1, int v2) 5 | { 6 | return v1 * v2; // 7 | // return v1 * v2 + v1 + v2; // 8 | } 9 | -------------------------------------------------------------------------------- /tests/src/utility/NewCompilationUnit/NewCompilationUnit2.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | int newCompilationUnit2ComputeResult(int v1, int v2); 5 | -------------------------------------------------------------------------------- /tests/src/utility/NewHeaderDependency.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "NewHeaderDependency.hpp" 3 | //#include "NewHeaderDependency/NewHeaderDependency2.hpp" // 4 | 5 | int newHeaderDependencyComputeResult(int v1, int v2) 6 | { 7 | return v1 + v2; // 8 | // return newHeaderDependency2ComputeResult(v1, v2); // 9 | } 10 | -------------------------------------------------------------------------------- /tests/src/utility/NewHeaderDependency.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | int newHeaderDependencyComputeResult(int v1, int v2); 5 | -------------------------------------------------------------------------------- /tests/src/utility/NewHeaderDependency/NewHeaderDependency2.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | int newHeaderDependency2ComputeResult(int v1, int v2) 5 | { 6 | return v1 * v2; // 7 | // return v1 * v2 + v1 + v2; // 8 | } 9 | -------------------------------------------------------------------------------- /tests/src/utility/OneFrameCompileReload.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "OneFrameCompileReload.hpp" 3 | 4 | int ofcrGetNext() 5 | { 6 | static int ofctVariable = 0; 7 | ofctVariable += 4; 8 | ofctVariable += 1; 9 | ofctVariable -= 1; 10 | // Just to touch the file 11 | (void)ofctVariable; // 12 | return ofctVariable; 13 | } 14 | 15 | -------------------------------------------------------------------------------- /tests/src/utility/OneFrameCompileReload.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | int ofcrGetNext(); 5 | -------------------------------------------------------------------------------- /tests/src/utility/ReloadAfterFailedCompilation1.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "ReloadAfterFailedCompilation1.hpp" 3 | 4 | int rafcGetValue1() 5 | { 6 | return 15; // 7 | // return 17; // 8 | // return 19; // 9 | } 10 | -------------------------------------------------------------------------------- /tests/src/utility/ReloadAfterFailedCompilation1.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | int rafcGetValue1(); 5 | -------------------------------------------------------------------------------- /tests/src/utility/ReloadAfterFailedCompilation2.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "ReloadAfterFailedCompilation2.hpp" 3 | 4 | int rafcGetValue2() 5 | { 6 | return 56; // 7 | // does not compile // 8 | // return 69; // 9 | } 10 | -------------------------------------------------------------------------------- /tests/src/utility/ReloadAfterFailedCompilation2.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | int rafcGetValue2(); 5 | -------------------------------------------------------------------------------- /tests/src/utility/ReloadOnSignal.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "ReloadOnSignal.hpp" 3 | 4 | namespace 5 | { 6 | int get42Value() 7 | { 8 | static int res = 42; 9 | return res; 10 | } 11 | 12 | int get64Value() 13 | { 14 | static int res = 64; 15 | return res; 16 | } 17 | } 18 | 19 | int reloadOnSignalGetValue() 20 | { 21 | return ::get42Value(); // 22 | // return ::get64Value(); // 23 | } 24 | -------------------------------------------------------------------------------- /tests/src/utility/ReloadOnSignal.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | int reloadOnSignalGetValue(); 5 | -------------------------------------------------------------------------------- /tests/src/utility/SeveralReloads.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | 6 | std::pair severalGetGlobalVar(); 7 | std::pair severalGetExternGlobalVar(); 8 | std::pair severalGetStaticVar(); 9 | std::pair severalGetInternalStaticVar(); 10 | 11 | void* severalGetGlobalVarAddress(); 12 | void* severalGetExternGlobalVarAddress(); 13 | void* severalGetStaticVarAddress(); 14 | void* severalGetInternalStaticAddress(); 15 | void* severalGetFunctionLocalStaticVarAddress(); 16 | -------------------------------------------------------------------------------- /tests/src/utility/StaticFunctionLocalVariable.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "StaticFunctionLocalVariable.hpp" 3 | 4 | int getNext2() 5 | { 6 | static int variable = 0; 7 | variable += 4; 8 | variable += 1; 9 | variable -= 1; 10 | // Just to touch the file 11 | (void)variable; // 12 | return variable; 13 | } 14 | -------------------------------------------------------------------------------- /tests/src/utility/StaticFunctionLocalVariable.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | int getNext2(); 5 | -------------------------------------------------------------------------------- /tests/src/utility/StaticFunctionLocalVariableAddress.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "utility/StaticFunctionLocalVariableAddress.hpp" 3 | 4 | void* getStaticFunctionLocalVariableAddress() 5 | { 6 | static int variable = 0; 7 | variable += 1; 8 | variable -= 1; 9 | // Just to touch the file 10 | (void)variable; // 11 | return reinterpret_cast(&variable); 12 | } 13 | -------------------------------------------------------------------------------- /tests/src/utility/StaticFunctionLocalVariableAddress.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | void* getStaticFunctionLocalVariableAddress(); 5 | -------------------------------------------------------------------------------- /tests/src/utility/StaticInternalVariable.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "StaticInternalVariable.hpp" 3 | 4 | namespace 5 | { 6 | static int staticVariable = 0; 7 | } 8 | 9 | std::pair getNext1() 10 | { 11 | staticVariable += 1; 12 | staticVariable -= 1; 13 | return {0, staticVariable++}; // 14 | // return {1, staticVariable++}; // 15 | } 16 | -------------------------------------------------------------------------------- /tests/src/utility/StaticInternalVariable.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | 6 | std::pair getNext1(); 7 | -------------------------------------------------------------------------------- /tests/src/utility/StaticInternalVariableAddress.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "StaticInternalVariableAddress.hpp" 3 | 4 | namespace 5 | { 6 | static int staticVariableCheckingAddress = 0; 7 | } 8 | 9 | void* getStaticInternalVariableAddress() 10 | { 11 | staticVariableCheckingAddress += 1; 12 | staticVariableCheckingAddress -= 1; 13 | (void)staticVariableCheckingAddress; // 14 | return reinterpret_cast(&staticVariableCheckingAddress); 15 | } 16 | -------------------------------------------------------------------------------- /tests/src/utility/StaticInternalVariableAddress.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | void* getStaticInternalVariableAddress(); 5 | -------------------------------------------------------------------------------- /tests/src/utility/StaticVariable.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "StaticVariable.hpp" 3 | 4 | static int staticVariable = 10; 5 | 6 | std::pair getNext() 7 | { 8 | staticVariable += 1; 9 | staticVariable -= 1; 10 | return {0, staticVariable++}; // 11 | // return {1, staticVariable++}; // 12 | } 13 | -------------------------------------------------------------------------------- /tests/src/utility/StaticVariable.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | 6 | std::pair getNext(); 7 | -------------------------------------------------------------------------------- /tests/src/utility/StaticVariableAddress.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "StaticVariableAddress.hpp" 3 | 4 | static int staticVariableCheckingAddress = 10; 5 | 6 | void* getStaticVariableAddress() 7 | { 8 | staticVariableCheckingAddress += 1; 9 | staticVariableCheckingAddress -= 1; 10 | (void)staticVariableCheckingAddress; // 11 | return reinterpret_cast(&staticVariableCheckingAddress); 12 | } 13 | -------------------------------------------------------------------------------- /tests/src/utility/StaticVariableAddress.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | void* getStaticVariableAddress(); 5 | -------------------------------------------------------------------------------- /tests/src/utility/StaticVariableSameName1.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "StaticVariableSameName1.hpp" 3 | 4 | static int staticVariableWithTheSameName = 10; 5 | 6 | std::pair getNextSameName1() 7 | { 8 | staticVariableWithTheSameName += 1; 9 | staticVariableWithTheSameName -= 1; 10 | // Ensuring that this file was reloaded 11 | return {0, staticVariableWithTheSameName++}; // 12 | // return {1, staticVariableWithTheSameName++}; // 13 | } 14 | 15 | -------------------------------------------------------------------------------- /tests/src/utility/StaticVariableSameName1.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | 6 | std::pair getNextSameName1(); 7 | -------------------------------------------------------------------------------- /tests/src/utility/StaticVariableSameName2.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "StaticVariableSameName2.hpp" 3 | 4 | static int staticVariableWithTheSameName = 110; 5 | 6 | std::pair getNextSameName2() 7 | { 8 | staticVariableWithTheSameName += 1; 9 | staticVariableWithTheSameName -= 1; 10 | // Ensuring that this file was reloaded 11 | return {10, staticVariableWithTheSameName++}; // 12 | // return {11, staticVariableWithTheSameName++}; // 13 | } 14 | -------------------------------------------------------------------------------- /tests/src/utility/StaticVariableSameName2.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | #include 5 | 6 | std::pair getNextSameName2(); 7 | -------------------------------------------------------------------------------- /tests/src/utility/UndefinedSymbol.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "UndefinedSymbol.hpp" 3 | #include "UndefinedSymbol2.hpp" 4 | 5 | static int undefinedSomeStaticVariable = 21; 6 | 7 | int undefinedGetValue() 8 | { 9 | return undefinedSomeStaticVariable++; // 10 | // return UndefinedSomeClass{}.undefinedGetValue2(); // 11 | } 12 | -------------------------------------------------------------------------------- /tests/src/utility/UndefinedSymbol.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | int undefinedGetValue(); 5 | -------------------------------------------------------------------------------- /tests/src/utility/UndefinedSymbol2.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "UndefinedSymbol2.hpp" 3 | 4 | int UndefinedSomeClass::undefinedGetValue2() 5 | { 6 | return m_value++; 7 | } 8 | -------------------------------------------------------------------------------- /tests/src/utility/UndefinedSymbol2.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | class UndefinedSomeClass 5 | { 6 | public: 7 | int undefinedGetValue2(); 8 | 9 | private: 10 | int m_value = 42; 11 | }; 12 | -------------------------------------------------------------------------------- /tests/src/utility/UndefinedSymbolDeep.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "UndefinedSymbolDeep.hpp" 3 | #include "UndefinedSymbolDeep/UndefinedSymbolDeep1.hpp" 4 | 5 | static int undefinedDeepSomeStaticVariable = 32; 6 | 7 | int undefinedDeepGetValue() 8 | { 9 | return ++undefinedDeepSomeStaticVariable; // 10 | // return UndefinedDeepSomeClass{}.undefinedDeepGetValue2(); // 11 | } 12 | -------------------------------------------------------------------------------- /tests/src/utility/UndefinedSymbolDeep.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | int undefinedDeepGetValue(); 5 | -------------------------------------------------------------------------------- /tests/src/utility/UndefinedSymbolDeep/UndefinedSymbolDeep1.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "UndefinedSymbolDeep1.hpp" 3 | #include "UndefinedSymbolDeep2.hpp" 4 | 5 | int UndefinedDeepSomeClass::undefinedDeepGetValue2() 6 | { 7 | return undefinedDeepGetValueFromSomeFunction(); 8 | } 9 | -------------------------------------------------------------------------------- /tests/src/utility/UndefinedSymbolDeep/UndefinedSymbolDeep1.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | class UndefinedDeepSomeClass 5 | { 6 | public: 7 | int undefinedDeepGetValue2(); 8 | }; 9 | -------------------------------------------------------------------------------- /tests/src/utility/UndefinedSymbolDeep/UndefinedSymbolDeep2.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "UndefinedSymbolDeep2.hpp" 3 | 4 | static int undefinedDeeptaticVarForSomeFunction = 55; 5 | 6 | int undefinedDeepGetValueFromSomeFunction() 7 | { 8 | return ++undefinedDeeptaticVarForSomeFunction; 9 | } 10 | -------------------------------------------------------------------------------- /tests/src/utility/UndefinedSymbolDeep/UndefinedSymbolDeep2.hpp: -------------------------------------------------------------------------------- 1 | 2 | #pragma once 3 | 4 | int undefinedDeepGetValueFromSomeFunction(); 5 | -------------------------------------------------------------------------------- /tools/format/format.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | dirpath=$(python -c "import os,sys; print os.path.realpath(sys.argv[1])" $1) 4 | pushd $dirpath > /dev/null 5 | find . -type f -not -path "*/build/*" \( -name \*.h -o -name \*.hpp -o -name \*.inl -o -name \*.mm -o -name \*.m -o -name \*.cpp \) -print | xargs clang-format -i 6 | popd > /dev/null 7 | --------------------------------------------------------------------------------