├── .github └── workflows │ └── codeql.yml ├── .gitignore ├── .gitmodules ├── .travis.yml ├── LICENSE ├── README.md ├── cmake └── modules │ └── CodeCoverage.cmake ├── src └── system │ ├── task.cpp │ └── task.h └── test ├── CMakeLists.txt ├── README.md └── test.cpp /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ "master" ] 17 | pull_request: 18 | branches: [ "master" ] 19 | schedule: 20 | - cron: '35 5 * * 6' 21 | 22 | jobs: 23 | analyze: 24 | name: Analyze (${{ matrix.language }}) 25 | # Runner size impacts CodeQL analysis time. To learn more, please see: 26 | # - https://gh.io/recommended-hardware-resources-for-running-codeql 27 | # - https://gh.io/supported-runners-and-hardware-resources 28 | # - https://gh.io/using-larger-runners (GitHub.com only) 29 | # Consider using larger runners or machines with greater resources for possible analysis time improvements. 30 | runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }} 31 | timeout-minutes: ${{ (matrix.language == 'swift' && 120) || 360 }} 32 | permissions: 33 | # required for all workflows 34 | security-events: write 35 | 36 | # required to fetch internal or private CodeQL packs 37 | packages: read 38 | 39 | # only required for workflows in private repositories 40 | actions: read 41 | contents: read 42 | 43 | strategy: 44 | fail-fast: false 45 | matrix: 46 | include: 47 | - language: c-cpp 48 | build-mode: manual 49 | # CodeQL supports the following values keywords for 'language': 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift' 50 | # Use `c-cpp` to analyze code written in C, C++ or both 51 | # Use 'java-kotlin' to analyze code written in Java, Kotlin or both 52 | # Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both 53 | # To learn more about changing the languages that are analyzed or customizing the build mode for your analysis, 54 | # see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning. 55 | # If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how 56 | # your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages 57 | steps: 58 | - name: Checkout repository 59 | uses: actions/checkout@v4 60 | 61 | # Initializes the CodeQL tools for scanning. 62 | - name: Initialize CodeQL 63 | uses: github/codeql-action/init@v3 64 | with: 65 | languages: ${{ matrix.language }} 66 | build-mode: ${{ matrix.build-mode }} 67 | # If you wish to specify custom queries, you can do so here or in a config file. 68 | # By default, queries listed here will override any specified in a config file. 69 | # Prefix the list here with "+" to use these queries and those in the config file. 70 | 71 | # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs 72 | # queries: security-extended,security-and-quality 73 | 74 | # If the analyze step fails for one of the languages you are analyzing with 75 | # "We were unable to automatically build your code", modify the matrix above 76 | # to set the build mode to "manual" for that language. Then modify this step 77 | # to build your code. 78 | # ℹ️ Command-line programs to run using the OS shell. 79 | # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun 80 | - if: matrix.build-mode == 'manual' 81 | shell: bash 82 | run: | 83 | git submodule update --init 84 | cd test 85 | mkdir -p build 86 | cd $_ 87 | cmake .. 88 | make 89 | 90 | - name: Perform CodeQL Analysis 91 | uses: github/codeql-action/analyze@v3 92 | with: 93 | category: "/language:${{matrix.language}}" 94 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Compiled Dynamic libraries 12 | *.so 13 | *.dylib 14 | *.dll 15 | 16 | # Fortran module files 17 | *.mod 18 | 19 | # Compiled Static libraries 20 | *.lai 21 | *.la 22 | *.a 23 | *.lib 24 | 25 | # Executables 26 | *.exe 27 | *.out 28 | *.app 29 | 30 | # Visual Studio Code 31 | .vscode/ 32 | 33 | # Other 34 | 35 | build*/ 36 | 37 | ### https://raw.github.com/github/gitignore/fad779220742a6d54ccfc0c1a0e5b3d820253de6/CMake.gitignore 38 | 39 | CMakeCache.txt 40 | CMakeFiles 41 | CMakeScripts 42 | Testing 43 | Makefile 44 | cmake_install.cmake 45 | install_manifest.txt 46 | compile_commands.json 47 | CTestTestfile.cmake 48 | 49 | 50 | ### https://raw.github.com/github/gitignore/fad779220742a6d54ccfc0c1a0e5b3d820253de6/Global/VisualStudioCode.gitignore 51 | 52 | .vscode/* 53 | !.vscode/settings.json 54 | !.vscode/tasks.json 55 | !.vscode/launch.json 56 | !.vscode/extensions.json 57 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "iutest"] 2 | path = iutest 3 | url = https://github.com/srz-zumix/iutest.git 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | compiler: 2 | - clang 3 | - gcc 4 | cache: 5 | apt: true 6 | sudo: required 7 | addons: 8 | apt: 9 | sources: 10 | - ubuntu-toolchain-r-test 11 | packages: 12 | #- lcov 13 | - ruby 14 | - clang-5.0 15 | - g++-7 16 | - gcc-7 17 | before_install: 18 | - git submodule update --init 19 | - cpanm local::lib --sudo 20 | - cpanm PerlIO::gzip --sudo 21 | - cpanm JSON --sudo 22 | - cpanm Capture::Tiny --sudo 23 | install: 24 | - | 25 | if [ "$CXX" = "g++" ]; then 26 | pwd 27 | git clone https://github.com/linux-test-project/lcov.git ./lcov 28 | cd lcov 29 | sudo make install 30 | cd .. 31 | pwd 32 | gem install lcoveralls; 33 | fi 34 | language: cpp 35 | script: 36 | - pwd 37 | - pushd test 38 | - mkdir -p build 39 | - cd build 40 | - which gcov-7 41 | - | 42 | if [ "$CXX" = "g++" ]; then 43 | cmake -DCMAKE_CXX_COMPILER=g++-7 -DCMAKE_C_COMPILER=gcc-7 -DGCOV_PATH=$(which gcov-7) -DCMAKE_BUILD_TYPE=Debug -DGTF_Test_ENABLE_COVERAGE=1 ..; 44 | fi 45 | - if [ "$CXX" = "clang++" ]; then cmake -DCMAKE_CXX_COMPILER=clang++-5.0 -DCMAKE_C_COMPILER=clang-5.0 -DCMAKE_BUILD_TYPE=Debug ..; fi 46 | - make 47 | - if [ "$CXX" = "g++" ]; then make GTF_Test_coverage; fi 48 | after_success: 49 | # Coverage - lcoveralls require current directory has .git 50 | - popd 51 | - pwd 52 | - if [ "$CXX" = "g++" ]; then lcoveralls --retry-count 3 ./test/build/GTF_Test_coverage.info.cleaned; fi 53 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2001-2004 aki, 2015-2017 At-sushi 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://app.travis-ci.com/At-sushi/GTFramework.svg?branch=master)](https://app.travis-ci.com/At-sushi/GTFramework) 2 | [![Coverage Status](https://coveralls.io/repos/github/At-sushi/GTFramework/badge.svg?branch=master)](https://coveralls.io/github/At-sushi/GTFramework?branch=master) 3 | [![MIT License](http://img.shields.io/badge/license-MIT-blue.svg?style=flat)](./LICENSE) 4 | # GTFramework 5 | Goluah Task Framework ver1.50a 6 | 7 | 「Goluah!」から流用したゲーム開発向け汎用タスクシステム 8 | 9 | タスクのリスト式管理・検索・優先度つきの描画などが高速に行えます。 10 | 11 | ## 導入方法 12 | src/systemフォルダ以下をプロジェクト内にコピーして使用してください。 13 | 14 | ライブラリをbuildするMakefile等は今のところありません。 15 | 16 | ## 簡単な使い方 17 | ### タスク用クラスの定義 18 | タスク用の基礎クラスを継承することで、GTFrameworkで管理することの出来るタスククラスを生成することが出来ます。 19 | 20 | ```cpp 21 | #include "task.h" 22 | 23 | class NewTask : gtf::TaskBase 24 | { 25 | virtual void Initialize() override // 初期化時の処理 26 | { 27 | // タスク追加処理など 28 | } 29 | 30 | virtual bool Execute(double elapsedTime) override // 実行時の処理 31 | { 32 | // do something 33 | return true; 34 | } 35 | 36 | virtual unsigned int GetID() const override 37 | { 38 | return 12; 39 | } 40 | }; 41 | ``` 42 | 43 | GTFrameworkには3種類の基礎クラスがあります。 44 | 45 | * `gtf::TaskBase` 通常タスク(下記の排他タスクに依存して(子タスクとして)振る舞う。 親排他タスクが実行中の時のみ実行される。 シーン中のオブジェクトなど。) 46 | * `gtf::ExclusiveTaskBase` 排他タスク(他の排他タスクと同時に実行されない。 スタック可能。 シーン遷移などに。) 47 | * `gtf::BackgroundTaskBase` 常駐タスク(タスク階層に依存せずに常時実行されるタスク) 48 | 49 | これらの使い分けの詳細については,下記のリファレンスをご参照ください。 50 | 51 | タスクが初期化され、実行可能な状態になると`Initialize`メソッドが実行されます。 52 | 排他タスクの場合、生成直後にはタスクがアクティブにならないため、子タスクの生成処理などはこの関数の内部で行うようにしてください。 53 | 54 | タスクが実行されると`Execute`メソッドが実行され、`false`を返すとそのタスクは破棄されます。 55 | 56 | `GetID`メソッドは、タスクに個別のIDを付けたいときに使えます(`0`にすると未設定扱いとなりますのでご注意ください。) 57 | 58 | ### 初期化・実行 59 | 60 | ```cpp 61 | gtf::TaskManager taskManager; 62 | 63 | taskManager.AddNewTask(); 64 | ``` 65 | 66 | `gtf::TaskManager`クラスをインスタンス化するとタスクを管理できるようになります。 67 | 68 | `gtf::TaskManager::AddNewTask`メソッドにテンプレート引数としてクラスをわたすと、タスクが自動で生成されます。 69 | 括弧の中に引数を記述すると、タスクのコンストラクタ引数として初期化時に渡すことが出来ます。 70 | 71 | ```cpp 72 | taskManager.AddNewTask(12, 2, "String"); 73 | ``` 74 | 75 | タスクをすべて実行するには`gtf::TaskManager::Execute`メソッドを使います。 76 | 77 | ```cpp 78 | taskManager.Execute(0); 79 | ``` 80 | 81 | ### 検索 82 | 83 | ```cpp 84 | auto p = taskManager.FindTask(12); 85 | ``` 86 | 87 | `gtf::TaskManager::FindTask`メソッドを使用すると、指定したIDのタスクのスマートポインタが手に入ります。 88 | テンプレート引数としてタスクのクラス型を指定すると、動的キャストを行い、指定された型の`shared_ptr`を返します。 89 | ただし排他タスクの検索は出来ません。 90 | 91 | ### 描画(優先度付き) 92 | 93 | ```cpp 94 | #include "task.h" 95 | 96 | class NewTask : gtf::TaskBase 97 | { 98 | virtual void Draw() override // Draw実行時の処理 99 | { 100 | // do something 101 | } 102 | 103 | virtual int GetDrawPriority() const override 104 | { 105 | return 0; // 描画の優先度。数値の大きいものから先に処理される。-1で無効。 106 | } 107 | }; 108 | ``` 109 | 110 | `Draw`メソッドを使うには、`GetDrawPriority`メソッドをオーバーライドして、 111 | あらかじめ優先度を定義しておく必要があります。 112 | 113 | 描画は(別に描画処理でなくてもいいのですが)優先度の数値が大きい順に処理され、`-1`のものは処理されません。 114 | 115 | すべてのタスクの`Draw`メソッドを実行するには、`gtf::TaskManager`クラスの`Draw`メソッドを使います。 116 | 117 | ```cpp 118 | taskManager.Draw(); 119 | ``` 120 | 121 | 排他タスクの生成時、コンストラクタ引数`fallthroughDraw`に`true`を指定して生成すると、Draw処理のフォールスルーが行われるようになります。 122 | この状態で`Draw`処理がコールされると、一つ下の階層のタスクも含めて描画することが出来ます。 123 | ```cpp 124 | class NewExTask : gtf::ExcusiveTaskBase 125 | { 126 | NewExTask() : gtf::ExcusiveTaskBase(true) 127 | { 128 | // do something 129 | return true; 130 | } 131 | }; 132 | ``` 133 | 134 | 135 | ## リファレンス: 136 | http://at-sushi.github.io/GTFramework/ 137 | 138 | 詳しいことはこちらをご参照ください。 139 | -------------------------------------------------------------------------------- /cmake/modules/CodeCoverage.cmake: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2012 - 2017, Lars Bilke 2 | # All rights reserved. 3 | # 4 | # Redistribution and use in source and binary forms, with or without modification, 5 | # are permitted provided that the following conditions are met: 6 | # 7 | # 1. Redistributions of source code must retain the above copyright notice, this 8 | # list of conditions and the following disclaimer. 9 | # 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 | # 3. Neither the name of the copyright holder nor the names of its contributors 15 | # may be used to endorse or promote products derived from this software without 16 | # specific prior written permission. 17 | # 18 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 19 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 22 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 25 | # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 27 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | # 29 | # CHANGES: 30 | # 31 | # 2012-01-31, Lars Bilke 32 | # - Enable Code Coverage 33 | # 34 | # 2013-09-17, Joakim Söderberg 35 | # - Added support for Clang. 36 | # - Some additional usage instructions. 37 | # 38 | # 2016-02-03, Lars Bilke 39 | # - Refactored functions to use named parameters 40 | # 41 | # 2017-06-02, Lars Bilke 42 | # - Merged with modified version from github.com/ufz/ogs 43 | # 44 | # 45 | # USAGE: 46 | # 47 | # 1. Copy this file into your cmake modules path. 48 | # 49 | # 2. Add the following line to your CMakeLists.txt: 50 | # include(CodeCoverage) 51 | # 52 | # 3. Append necessary compiler flags: 53 | # APPEND_COVERAGE_COMPILER_FLAGS() 54 | # 55 | # 4. If you need to exclude additional directories from the report, specify them 56 | # using the COVERAGE_EXCLUDES variable before calling SETUP_TARGET_FOR_COVERAGE. 57 | # Example: 58 | # set(COVERAGE_EXCLUDES 'dir1/*' 'dir2/*') 59 | # 60 | # 5. Use the functions described below to create a custom make target which 61 | # runs your test executable and produces a code coverage report. 62 | # 63 | # 6. Build a Debug build: 64 | # cmake -DCMAKE_BUILD_TYPE=Debug .. 65 | # make 66 | # make my_coverage_target 67 | # 68 | 69 | include(CMakeParseArguments) 70 | 71 | # Check prereqs 72 | find_program( GCOV_PATH gcov ) 73 | find_program( LCOV_PATH lcov ) 74 | find_program( GCOVR_PATH gcovr PATHS ${CMAKE_SOURCE_DIR}/scripts/test) 75 | find_program( SIMPLE_PYTHON_EXECUTABLE python ) 76 | 77 | if(NOT GCOV_PATH) 78 | message(FATAL_ERROR "gcov not found! Aborting...") 79 | endif() # NOT GCOV_PATH 80 | 81 | if("${CMAKE_CXX_COMPILER_ID}" MATCHES "(Apple)?[Cc]lang") 82 | if("${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS 3) 83 | message(FATAL_ERROR "Clang version must be 3.0.0 or greater! Aborting...") 84 | endif() 85 | elseif(NOT CMAKE_COMPILER_IS_GNUCXX) 86 | message(FATAL_ERROR "Compiler is not GNU gcc! Aborting...") 87 | endif() 88 | 89 | set(COVERAGE_COMPILER_FLAGS "-g -O0 --coverage -fprofile-arcs -ftest-coverage" 90 | CACHE INTERNAL "") 91 | 92 | set(CMAKE_CXX_FLAGS_COVERAGE 93 | ${COVERAGE_COMPILER_FLAGS} 94 | CACHE STRING "Flags used by the C++ compiler during coverage builds." 95 | FORCE ) 96 | set(CMAKE_C_FLAGS_COVERAGE 97 | ${COVERAGE_COMPILER_FLAGS} 98 | CACHE STRING "Flags used by the C compiler during coverage builds." 99 | FORCE ) 100 | set(CMAKE_EXE_LINKER_FLAGS_COVERAGE 101 | "" 102 | CACHE STRING "Flags used for linking binaries during coverage builds." 103 | FORCE ) 104 | set(CMAKE_SHARED_LINKER_FLAGS_COVERAGE 105 | "" 106 | CACHE STRING "Flags used by the shared libraries linker during coverage builds." 107 | FORCE ) 108 | mark_as_advanced( 109 | CMAKE_CXX_FLAGS_COVERAGE 110 | CMAKE_C_FLAGS_COVERAGE 111 | CMAKE_EXE_LINKER_FLAGS_COVERAGE 112 | CMAKE_SHARED_LINKER_FLAGS_COVERAGE ) 113 | 114 | if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug") 115 | message(WARNING "Code coverage results with an optimised (non-Debug) build may be misleading") 116 | endif() # NOT CMAKE_BUILD_TYPE STREQUAL "Debug" 117 | 118 | if(CMAKE_C_COMPILER_ID STREQUAL "GNU") 119 | link_libraries(gcov) 120 | else() 121 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --coverage") 122 | endif() 123 | 124 | # Defines a target for running and collection code coverage information 125 | # Builds dependencies, runs the given executable and outputs reports. 126 | # NOTE! The executable should always have a ZERO as exit code otherwise 127 | # the coverage generation will not complete. 128 | # 129 | # SETUP_TARGET_FOR_COVERAGE( 130 | # NAME testrunner_coverage # New target name 131 | # EXECUTABLE testrunner -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR 132 | # DEPENDENCIES testrunner # Dependencies to build first 133 | # ) 134 | function(SETUP_TARGET_FOR_COVERAGE) 135 | 136 | set(options NONE) 137 | set(oneValueArgs NAME) 138 | set(multiValueArgs EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES) 139 | cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) 140 | 141 | if(NOT LCOV_PATH) 142 | message(FATAL_ERROR "lcov not found! Aborting...") 143 | endif() # NOT LCOV_PATH 144 | 145 | # Setup target 146 | add_custom_target(${Coverage_NAME} 147 | 148 | # Cleanup lcov 149 | COMMAND ${LCOV_PATH} --directory . --zerocounters 150 | # Create baseline to make sure untouched files show up in the report 151 | COMMAND ${LCOV_PATH} -c -i -d . -o ${Coverage_NAME}.base 152 | 153 | # Run tests 154 | COMMAND ${Coverage_EXECUTABLE} 155 | 156 | # Capturing lcov counters and generating report 157 | COMMAND ${LCOV_PATH} --directory . --capture --output-file ${Coverage_NAME}.info 158 | # add baseline counters 159 | COMMAND ${LCOV_PATH} -a ${Coverage_NAME}.base -a ${Coverage_NAME}.info --output-file ${Coverage_NAME}.total 160 | COMMAND ${LCOV_PATH} --remove ${Coverage_NAME}.total ${COVERAGE_EXCLUDES} --output-file ${PROJECT_BINARY_DIR}/${Coverage_NAME}.info.cleaned 161 | COMMAND ${CMAKE_COMMAND} -E remove ${Coverage_NAME}.base ${Coverage_NAME}.info ${Coverage_NAME}.total 162 | 163 | WORKING_DIRECTORY ${PROJECT_BINARY_DIR} 164 | DEPENDS ${Coverage_DEPENDENCIES} 165 | COMMENT "Resetting code coverage counters to zero.\nProcessing code coverage counters and generating report." 166 | ) 167 | 168 | # Show info where to find the report 169 | add_custom_command(TARGET ${Coverage_NAME} POST_BUILD 170 | COMMAND ; 171 | COMMENT "Result is ${PROJECT_BINARY_DIR}/${Coverage_NAME}.info.cleaned" 172 | ) 173 | 174 | endfunction() # SETUP_TARGET_FOR_COVERAGE 175 | 176 | # Defines a target for running and collection code coverage information 177 | # Builds dependencies, runs the given executable and outputs reports. 178 | # NOTE! The executable should always have a ZERO as exit code otherwise 179 | # the coverage generation will not complete. 180 | # 181 | # SETUP_TARGET_FOR_COVERAGE_COBERTURA( 182 | # NAME ctest_coverage # New target name 183 | # EXECUTABLE ctest -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR 184 | # DEPENDENCIES executable_target # Dependencies to build first 185 | # ) 186 | function(SETUP_TARGET_FOR_COVERAGE_COBERTURA) 187 | 188 | set(options NONE) 189 | set(oneValueArgs NAME) 190 | set(multiValueArgs EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES) 191 | cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) 192 | 193 | if(NOT SIMPLE_PYTHON_EXECUTABLE) 194 | message(FATAL_ERROR "python not found! Aborting...") 195 | endif() # NOT SIMPLE_PYTHON_EXECUTABLE 196 | 197 | if(NOT GCOVR_PATH) 198 | message(FATAL_ERROR "gcovr not found! Aborting...") 199 | endif() # NOT GCOVR_PATH 200 | 201 | # Combine excludes to several -e arguments 202 | set(COBERTURA_EXCLUDES "") 203 | foreach(EXCLUDE ${COVERAGE_EXCLUDES}) 204 | set(COBERTURA_EXCLUDES "-e ${EXCLUDE} ${COBERTURA_EXCLUDES}") 205 | endforeach() 206 | 207 | add_custom_target(${Coverage_NAME} 208 | 209 | # Run tests 210 | ${Coverage_EXECUTABLE} 211 | 212 | # Running gcovr 213 | COMMAND ${GCOVR_PATH} -x -r ${CMAKE_SOURCE_DIR} ${COBERTURA_EXCLUDES} 214 | -o ${Coverage_NAME}.xml 215 | WORKING_DIRECTORY ${PROJECT_BINARY_DIR} 216 | DEPENDS ${Coverage_DEPENDENCIES} 217 | COMMENT "Running gcovr to produce Cobertura code coverage report." 218 | ) 219 | 220 | # Show info where to find the report 221 | add_custom_command(TARGET ${Coverage_NAME} POST_BUILD 222 | COMMAND ; 223 | COMMENT "Cobertura code coverage report saved in ${Coverage_NAME}.xml." 224 | ) 225 | 226 | endfunction() # SETUP_TARGET_FOR_COVERAGE_COBERTURA 227 | 228 | function(APPEND_COVERAGE_COMPILER_FLAGS) 229 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE) 230 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE) 231 | message(STATUS "Appending code coverage compiler flags: ${COVERAGE_COMPILER_FLAGS}") 232 | endfunction() # APPEND_COVERAGE_COMPILER_FLAGS 233 | -------------------------------------------------------------------------------- /src/system/task.cpp: -------------------------------------------------------------------------------- 1 |  2 | 3 | /*============================================================================ 4 | 5 | タスク管理(?) 6 | 7 | ==============================================================================*/ 8 | 9 | #include 10 | #include 11 | #include 12 | #include "task.h" 13 | 14 | namespace gtf 15 | { 16 | TaskManager::TaskManager() 17 | { 18 | // ダミーデータ挿入 19 | const auto it = tasks.emplace(tasks.end(), std::make_shared()); 20 | ex_stack.emplace_back(exNext, it); 21 | } 22 | 23 | void TaskManager::Destroy() 24 | { 25 | //バックグラウンドタスクTerminate 26 | for(auto&& ib : bg_tasks) ib->Terminate(); 27 | bg_tasks.clear(); 28 | 29 | //排他タスク・通常タスクTerminate 30 | while (ex_stack.size() != 0 && ex_stack.back().value){ 31 | CleanupPartialSubTasks(ex_stack.back().SubTaskStartPos); 32 | ex_stack.back().value->Terminate(); 33 | ex_stack.pop_back(); 34 | } 35 | exNext = nullptr; 36 | } 37 | 38 | TaskManager::TaskPtr TaskManager::AddTaskGuaranteed(TaskBase *newTask) 39 | { 40 | assert(newTask); 41 | assert(dynamic_cast(newTask) == nullptr); 42 | assert(dynamic_cast(newTask) == nullptr); 43 | 44 | if (newTask->GetID() != 0){ 45 | RemoveTaskByID(newTask->GetID()); 46 | } 47 | 48 | //通常タスクとしてAdd 49 | tasks.emplace_back(newTask); 50 | auto pnew = tasks.back(); 51 | newTask->Initialize(); 52 | if (newTask->GetID() != 0) 53 | indices[newTask->GetID()] = pnew; 54 | if (pnew->GetDrawPriority() >= 0) 55 | ex_stack.back().drawList.emplace(pnew->GetDrawPriority(), pnew); 56 | return pnew; 57 | } 58 | 59 | TaskManager::ExTaskPtr TaskManager::AddTask(ExclusiveTaskBase *newTask) 60 | { 61 | //排他タスクとしてAdd 62 | //Execute中かもしれないので、ポインタ保存のみ 63 | if (exNext){ 64 | auto t1 = *exNext; 65 | auto t2 = *newTask; 66 | OutputLog("■ALERT■ 排他タスクが2つ以上Addされた : %s / %s", 67 | typeid(t1).name(), typeid(t2).name()); 68 | } 69 | exNext = std::shared_ptr(newTask); 70 | 71 | return exNext; 72 | } 73 | 74 | TaskManager::BgTaskPtr TaskManager::AddTask(BackgroundTaskBase *newTask) 75 | { 76 | if (newTask->GetID() != 0){ 77 | RemoveTaskByID(newTask->GetID()); 78 | } 79 | 80 | bg_tasks.emplace_back(newTask); 81 | 82 | auto pbgt = bg_tasks.back(); 83 | 84 | //常駐タスクとしてAdd 85 | pbgt->Initialize(); 86 | if (newTask->GetID() != 0) 87 | bg_indices[newTask->GetID()] = pbgt; 88 | if (pbgt->GetDrawPriority() >= 0) 89 | drawListBG.emplace(pbgt->GetDrawPriority(), pbgt); 90 | return pbgt; 91 | } 92 | 93 | void TaskManager::Execute(double elapsedTime) 94 | { 95 | #ifdef ARRAYBOUNDARY_DEBUG 96 | if(!AfxCheckMemory()){ 97 | OutputLog("AfxCheckMemory() failed"); 98 | return; 99 | } 100 | #endif 101 | 102 | //排他タスク、topのみExecute 103 | assert(ex_stack.size() != 0); 104 | std::shared_ptr exTsk = ex_stack.back().value; 105 | 106 | // 新しいタスクがある場合 107 | if (exNext){ 108 | //現在排他タスクのInactivate 109 | assert(ex_stack.size() != 0); 110 | if (exTsk && !exTsk->Inactivate(exNext->GetID())){ 111 | //通常タスクを全て破棄する 112 | CleanupPartialSubTasks(ex_stack.back().SubTaskStartPos); 113 | 114 | exTsk->Terminate(); 115 | ex_stack.pop_back(); 116 | } 117 | 118 | //AddされたタスクをInitializeして突っ込む 119 | const auto it = tasks.emplace(tasks.end(), std::make_shared()); // ダミータスク挿入 120 | ex_stack.emplace_back(move(exNext), it); 121 | auto pnew = ex_stack.back().value; 122 | if (pnew->IsFallthroughDraw()) { 123 | assert(ex_stack.size() >= 2); 124 | ex_stack.back().drawList = (ex_stack.rbegin() + 1)->drawList; // 一つ下の階層のdrawListをコピー 125 | } 126 | pnew->Initialize(); 127 | if (pnew->GetDrawPriority() >= 0) 128 | ex_stack.back().drawList.emplace(pnew->GetDrawPriority(), pnew); 129 | 130 | exNext = nullptr; 131 | exTsk = move(pnew); 132 | } 133 | 134 | if (exTsk) 135 | { 136 | bool ex_ret = true; 137 | #ifdef _CATCH_WHILE_EXEC 138 | try{ 139 | #endif 140 | ex_ret = exTsk->Execute(elapsedTime); 141 | #ifdef _CATCH_WHILE_EXEC 142 | }catch(...){ 143 | if (ex_stack.back() == NULL)OutputLog("catch while execute3 : NULL", SYSLOG_ERROR); 144 | else OutputLog("catch while execute3 : %X %s",ex_stack.back(),typeid(*ex_stack.back()).name()); 145 | } 146 | #endif 147 | 148 | if (!ex_ret) 149 | { 150 | if (!exNext){ 151 | //現在排他タスクの変更 152 | 153 | #ifdef _CATCH_WHILE_EXEC 154 | try{ 155 | #endif 156 | 157 | //通常タスクを全て破棄する 158 | CleanupPartialSubTasks(ex_stack.back().SubTaskStartPos); 159 | 160 | #ifdef _CATCH_WHILE_EXEC 161 | }catch(...){ 162 | if ((*i) == NULL)OutputLog("catch while terminate1 : NULL", SYSLOG_ERROR); 163 | else OutputLog("catch while terminate1 : %X %s", (*i), typeid(*(*i)).name()); 164 | } 165 | #endif 166 | 167 | #ifdef _CATCH_WHILE_EXEC 168 | try{ 169 | #endif 170 | 171 | //現在排他タスクの破棄 172 | unsigned int prvID = exTsk->GetID(); 173 | exTsk->Terminate(); 174 | exTsk = nullptr; 175 | ex_stack.pop_back(); 176 | 177 | #ifdef _CATCH_WHILE_EXEC 178 | }catch(...){ 179 | if (exTsk == NULL)OutputLog("catch while terminate2 : NULL", SYSLOG_ERROR); 180 | else OutputLog("catch while terminate : %X %s", exTsk, typeid(*exTsk).name()); 181 | } 182 | #endif 183 | 184 | 185 | #ifdef _CATCH_WHILE_EXEC 186 | try{ 187 | #endif 188 | 189 | //次の排他タスクをActivateする 190 | assert(ex_stack.size() != 0); 191 | exTsk = ex_stack.back().value; 192 | if (exTsk) 193 | exTsk->Activate(prvID); 194 | 195 | #ifdef _CATCH_WHILE_EXEC 196 | }catch(...){ 197 | if (exTsk == NULL)OutputLog("catch while activate : NULL", SYSLOG_ERROR); 198 | else OutputLog("catch while activate : %X %s", exTsk, typeid(*exTsk).name()); 199 | } 200 | #endif 201 | 202 | 203 | return; 204 | } 205 | } 206 | } 207 | 208 | //通常タスクExecute 209 | assert(!ex_stack.empty()); 210 | taskExecute(tasks, ex_stack.back().SubTaskStartPos, tasks.end(), elapsedTime); 211 | 212 | //常駐タスクExecute 213 | taskExecute(bg_tasks, bg_tasks.begin(), bg_tasks.end(), elapsedTime); 214 | } 215 | 216 | 217 | void TaskManager::Draw() 218 | { 219 | assert(ex_stack.size() != 0); 220 | 221 | //Drawリストを取得 222 | auto iv = ex_stack.back().drawList.begin(); 223 | const auto iedv = ex_stack.back().drawList.end(); 224 | auto ivBG = drawListBG.begin(); 225 | const auto iedvBG = drawListBG.end(); 226 | auto DrawAndProceed = [](DrawPriorityMap::iterator& iv, DrawPriorityMap& drawList) 227 | { 228 | auto is = iv->second.lock(); 229 | 230 | if (is) 231 | { 232 | is->Draw(); 233 | ++iv; 234 | } 235 | else 236 | drawList.erase(iv++); 237 | }; 238 | 239 | //描画 240 | while (iv != iedv) 241 | { 242 | #ifdef _CATCH_WHILE_RENDER 243 | try{ 244 | #endif 245 | while (ivBG != iedvBG && ivBG->first <= iv->first) 246 | DrawAndProceed(ivBG, drawListBG); 247 | DrawAndProceed(iv, ex_stack.back().drawList); 248 | #ifdef _CATCH_WHILE_RENDER 249 | }catch(...){ 250 | OutputLog("catch while draw : %X %s", *iv, typeid(*(*iv).lock()).name()); 251 | } 252 | #endif 253 | } 254 | 255 | // 書き残した常駐タスク処理 256 | while (ivBG != iedvBG) 257 | DrawAndProceed(ivBG, drawListBG); 258 | } 259 | 260 | void TaskManager::RemoveTaskByID(unsigned int id) 261 | { 262 | // ID比較用関数 263 | const auto is_equal_to_id = [id](const auto& i){ 264 | return id == i->GetID(); 265 | }; 266 | 267 | //通常タスクをチェック 268 | if (indices.count(id) != 0) 269 | { 270 | // 該当するIDのタスクがあったら削除 271 | const auto it = std::find_if( 272 | tasks.begin(), 273 | tasks.end(), 274 | is_equal_to_id); 275 | 276 | if (it != tasks.end()) { 277 | (*it)->Terminate(); 278 | tasks.erase(it); 279 | } 280 | } 281 | 282 | //バックグラウンドタスクTerminate 283 | if (bg_indices.count(id) != 0) 284 | { 285 | // 該当するIDのタスクがあったら削除 286 | const auto it = std::find_if( 287 | bg_tasks.begin(), 288 | bg_tasks.end(), 289 | is_equal_to_id); 290 | 291 | if (it != bg_tasks.end()) { 292 | (*it)->Terminate(); 293 | bg_tasks.erase(it); 294 | } 295 | } 296 | } 297 | 298 | 299 | //指定IDの排他タスクまでTerminate/popする 300 | void TaskManager::RevertExclusiveTaskByID(unsigned int id) 301 | { 302 | bool act = false; 303 | unsigned int previd = 0; 304 | 305 | assert(ex_stack.size() != 0); 306 | while (ex_stack.back().value){ 307 | const std::shared_ptr& task = ex_stack.back().value; 308 | if (task->GetID() == id){ 309 | if (act){ 310 | task->Activate(previd); 311 | } 312 | return; 313 | } 314 | else{ 315 | previd = task->GetID(); 316 | act = true; 317 | CleanupPartialSubTasks(ex_stack.back().SubTaskStartPos); 318 | task->Terminate(); 319 | ex_stack.pop_back(); 320 | assert(ex_stack.size() != 0); 321 | } 322 | } 323 | } 324 | 325 | //通常タスクを一部だけ破棄する 326 | void TaskManager::CleanupPartialSubTasks(TaskList::iterator it_task) 327 | { 328 | for (TaskList::iterator i = it_task; i != tasks.end(); ++i){ 329 | (*i)->Terminate(); 330 | } 331 | tasks.erase(it_task, tasks.end()); 332 | } 333 | 334 | 335 | //デバッグ・タスク一覧表示 336 | void TaskManager::DebugOutputTaskList() 337 | { 338 | OutputLog("\n\n■TaskManager::DebugOutputTaskList() - start"); 339 | 340 | OutputLog("□通常タスク一覧□"); 341 | //通常タスク 342 | for(auto&& i : tasks) OutputLog(typeid(i).name()); 343 | 344 | OutputLog("□常駐タスク一覧□"); 345 | //バックグラウンドタスク 346 | for(auto&& ib : bg_tasks) OutputLog(typeid(ib).name()); 347 | 348 | //排他タスク 349 | OutputLog("\n"); 350 | OutputLog("□現在のタスク:"); 351 | if (ex_stack.empty()) 352 | OutputLog("なし"); 353 | else { 354 | auto s_top_v = *ex_stack.back().value; 355 | OutputLog(typeid(s_top_v).name()); 356 | } 357 | 358 | OutputLog("\n\n■TaskManager::DebugOutputTaskList() - end\n\n"); 359 | } 360 | } 361 | -------------------------------------------------------------------------------- /src/system/task.h: -------------------------------------------------------------------------------- 1 | /*! 2 | * @file 3 | * @brief タスク(?)管理・定義 4 | */ 5 | #pragma once 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #ifdef __clang__ 19 | # if !__has_feature(cxx_noexcept) 20 | # define NOEXCEPT 21 | # else 22 | # define NOEXCEPT noexcept 23 | # endif 24 | #elif (defined(_MSC_FULL_VER) && _MSC_FULL_VER < 190023026) || (defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 6) || !defined(__GXX_EXPERIMENTAL_CXX0X__))) 25 | #define NOEXCEPT 26 | #else 27 | #define NOEXCEPT noexcept 28 | #endif 29 | 30 | /*! 31 | * @defgroup Tasks 32 | * @brief タスク 33 | * 34 | * TaskBaseを継承したクラスは、メインループから呼ばれる更新・描画処理関数を持っています。 35 | * システムはこのクラスのリストを持っています。 36 | * タイトル・キャラセレ・試合 などのゲームの状態の変更は、 37 | * これらタスククラスの切り替えによって行われます。 38 | */ 39 | 40 | namespace gtf 41 | { 42 | /*! 43 | * @ingroup Tasks 44 | * @brief 基本タスク 45 | * 46 | * ・Executeでfalseを返すと破棄される 47 | * ・親の排他タスクが変更されたとき、破棄される 48 | */ 49 | class TaskBase 50 | { 51 | public: 52 | virtual ~TaskBase(){} 53 | virtual void Initialize(){} //!< ExecuteまたはDrawがコールされる前に1度だけコールされる 54 | virtual bool Execute(double /* elapsedTime */) 55 | {return(true);} //!< 毎フレームコールされる 56 | virtual void Terminate(){} //!< タスクのリストから外されるときにコールされる(その直後、deleteされる) 57 | virtual void Draw(){} //!< 描画時にコールされる 58 | virtual unsigned int GetID() const { return 0; } //!< 0以外を返すようにした場合、マネージャに同じIDを持つタスクがAddされたとき破棄される 59 | virtual int GetDrawPriority() const { return -1; } //!< 描画プライオリティ。低いほど後順に(手前に)Draw処理。マイナスならば表示しない 60 | }; 61 | 62 | 63 | /*! 64 | * @ingroup Tasks 65 | * @brief 排他タスク? =ゲームのシーンと考えてください。 66 | * 67 | * ・他の排他タスクと一緒には動作(Execute)しない 68 | * ・他の排他タスクが追加された場合、Inactivateがコールされ、そこでfalseを返すと 69 | * 破棄される。trueを返すとExecute、WndMessageがコールされない状態になり、 70 | * 新規の排他タスクが全て破棄されたときにActivateが呼ばれ、処理が再開する。 71 | * ・通常タスクとの親子関係を持つ。 72 | * ・AddTask実行後、一度Executeが実行されるまで追加が保留される。その後に追加された通常タスクは子タスクとなる。 73 | */ 74 | class ExclusiveTaskBase : public TaskBase 75 | { 76 | public: 77 | explicit ExclusiveTaskBase(bool fallthroughDraw = false) NOEXCEPT : isFallthroughDraw(fallthroughDraw) {} 78 | virtual ~ExclusiveTaskBase(){} 79 | virtual void Activate(unsigned int /* prvTaskID */){} //!< Executeが再開されるときに呼ばれる 80 | virtual bool Inactivate(unsigned int /* nextTaskID */){return true;}//!< 他の排他タスクが開始したときに呼ばれる 81 | 82 | virtual int GetDrawPriority() const override {return 0;} //!< 描画プライオリティ取得メソッド 83 | bool IsFallthroughDraw() const NOEXCEPT { return isFallthroughDraw; } //!< 一つ下の階層のタスクのDrawを実行するかどうか 84 | 85 | private: 86 | const bool isFallthroughDraw = false; 87 | }; 88 | 89 | 90 | 91 | /*! 92 | * @ingroup Tasks 93 | * @brief 常駐タスク 94 | * 95 | * ・基本タスクと違い、排他タスクが変更されても破棄されない 96 | * ・Enabledでないときには Execute , WndMessage をコールしない 97 | */ 98 | class BackgroundTaskBase : public TaskBase 99 | { 100 | public: 101 | virtual ~BackgroundTaskBase(){} 102 | 103 | bool IsEnabled() const NOEXCEPT { return m_isEnabled; } 104 | void Enable() NOEXCEPT { m_isEnabled = true; } 105 | void Disable() NOEXCEPT { m_isEnabled = false; } 106 | 107 | private: 108 | bool m_isEnabled = true; 109 | }; 110 | 111 | 112 | 113 | 114 | /*! 115 | * @ingroup System 116 | * @brief タスク管理クラス 117 | * 118 | * タスク継承クラスのリストを管理し、描画、更新を行う。 119 | * 120 | * 実行中に例外が起こったとき、どのクラスが例外を起こしたのかをログに吐き出す。 121 | * その際に実行時型情報からクラス名を取得しているので、コンパイルの際には 122 | * 実行時型情報(RTTIと表記される場合もある)をONにすること。 123 | */ 124 | 125 | class TaskManager 126 | { 127 | 128 | public: 129 | TaskManager(); 130 | ~TaskManager(){Destroy();} 131 | 132 | using TaskPtr = std::weak_ptr; 133 | using ExTaskPtr = std::weak_ptr; 134 | using BgTaskPtr = std::weak_ptr; 135 | 136 | void Destroy(); 137 | 138 | void RemoveTaskByID(unsigned int id); //!< 指定IDを持つタスクの除去 ※注:Exclusiveタスクはチェックしない 139 | void RevertExclusiveTaskByID(unsigned int id); //!< 指定IDの排他タスクまでTerminate/popする 140 | 141 | //! 最上位にあるエクスクルーシブタスクをゲト 142 | ExTaskPtr GetTopExclusiveTask() const 143 | { 144 | return ex_stack.back().value; 145 | } 146 | 147 | //! タスクの自動生成 148 | template , 149 | typename std::enable_if< 150 | std::integral_constant::value || 151 | std::is_base_of::value 152 | >::value, std::nullptr_t>::type = nullptr> 153 | PC AddNewTask(A&&... args) 154 | { 155 | return std::static_pointer_cast(AddTask(new C(std::forward(args)...)).lock()); 156 | } 157 | 158 | template , 159 | typename std::enable_if< 160 | std::integral_constant::value && 161 | !std::is_base_of::value 162 | >::value, std::nullptr_t>::type = nullptr> 163 | PC AddNewTask(A&&... args) 164 | { 165 | return std::static_pointer_cast(AddTaskGuaranteed(new C(std::forward(args)...)).lock()); 166 | } 167 | 168 | //! 任意のクラス型のタスクを取得(通常・常駐兼用) 169 | template std::shared_ptr FindTask(unsigned int id) const 170 | { 171 | return std::dynamic_pointer_cast(FindTask_impl(id).lock()); 172 | } 173 | 174 | void Execute(double elapsedTime); //!< 各タスクのExecute関数をコールする 175 | void Draw(); //!< 各タスクをプライオリティ順にDrawする 176 | 177 | //!< 排他タスクが全部なくなっちゃったかどうか 178 | bool ExEmpty() const { 179 | return ex_stack.size() <= 1; 180 | } 181 | 182 | //デバッグ 183 | void DebugOutputTaskList(); //!< 現在リストに保持されているクラスのクラス名をデバッグ出力する 184 | 185 | private: 186 | using TaskList = std::list>; 187 | using BgTaskList = std::list>; 188 | using DrawPriorityMap = std::multimap>; 189 | 190 | struct ExTaskInfo { 191 | const std::shared_ptr value; //!< 排他タスクのポインタ 192 | const TaskList::iterator SubTaskStartPos; //!< 依存する通常タスクの開始地点 193 | DrawPriorityMap drawList; //!< Draw順ソート用コンテナ。排他タスク自身や、DrawFallthrough時は一つ下の階層のDrawリストも含まれる。 194 | 195 | ExTaskInfo(std::shared_ptr& source, TaskList::iterator startPos) NOEXCEPT 196 | : value(source), SubTaskStartPos(startPos) 197 | { 198 | } 199 | ExTaskInfo(std::shared_ptr&& source, TaskList::iterator startPos) NOEXCEPT 200 | : value(std::move(source)), SubTaskStartPos(startPos) 201 | { 202 | } 203 | 204 | }; 205 | using ExTaskStack = std::deque; 206 | 207 | //! 追加したタスクはTaskManager内部で自動的に破棄されるので、呼び出し側でdeleteしないこと。 208 | ExTaskPtr AddTask(ExclusiveTaskBase *newTask); //!< 排他タスク追加 209 | BgTaskPtr AddTask(BackgroundTaskBase *newTask); //!< 常駐タスク追加 210 | TaskPtr AddTaskGuaranteed(TaskBase *newTask); //!< タスク追加(エラー検出無し) 211 | 212 | //!指定IDの通常タスク取得 213 | TaskPtr FindTask(unsigned int id) const 214 | { 215 | const auto result = indices.find(id); 216 | return (result != indices.end()) ? result->second : TaskPtr(); 217 | } 218 | 219 | //!指定IDの常駐タスク取得 220 | BgTaskPtr FindBGTask(unsigned int id) const 221 | { 222 | const auto result = bg_indices.find(id); 223 | return (result != bg_indices.end()) ? result->second : BgTaskPtr(); 224 | } 225 | void CleanupPartialSubTasks(TaskList::iterator it_task); //!< 一部の通常タスクをTerminate , deleteする 226 | 227 | //! ログ出力 228 | void OutputLog(std::string /* s */, ...) 229 | { 230 | // Not Implemented 231 | } 232 | 233 | template::value && 236 | !std::is_base_of::value 237 | >::value, std::nullptr_t>::type = nullptr> 238 | TaskPtr FindTask_impl(unsigned int id) const 239 | { 240 | return FindTask(id); 241 | } 242 | 243 | template::value, std::nullptr_t>::type = nullptr> 244 | BgTaskPtr FindTask_impl(unsigned int id) const 245 | { 246 | return FindBGTask(id); 247 | } 248 | 249 | //! タスクExecute 250 | template 251 | void taskExecute(T& tasks, I i, I ied, double elapsedTime) 252 | { 253 | std::forward_list deleteList; 254 | 255 | for (; i != ied; ++i){ 256 | #ifdef _CATCH_WHILE_EXEC 257 | try{ 258 | #endif 259 | if ((*i)->Execute(elapsedTime) == false) 260 | { 261 | deleteList.push_front(i); 262 | } 263 | #ifdef _CATCH_WHILE_EXEC 264 | } 265 | catch (...){ 266 | if (*i == nullptr) OutputLog("catch while execute1 : NULL", SYSLOG_ERROR); 267 | else OutputLog("catch while execute1 : %X , %s", *i, typeid(**i).name()); 268 | break; 269 | } 270 | #endif 271 | } 272 | 273 | //タスクでfalseを返したものを消す 274 | for (const I& i : deleteList){ 275 | (*i)->Terminate(); 276 | tasks.erase(i); 277 | } 278 | } 279 | 280 | TaskList tasks; //!< 現在動作ちゅうのタスクリスト 281 | BgTaskList bg_tasks; //!< 常駐タスクリスト 282 | ExTaskStack ex_stack; //!< 排他タスクのスタック。topしか実行しない 283 | 284 | std::shared_ptr exNext = nullptr; //!< 現在フレームでAddされた排他タスク 285 | DrawPriorityMap drawListBG; //!< Draw順ソート用コンテナ(常駐タスク) 286 | std::unordered_map indices; 287 | std::unordered_map bg_indices; 288 | }; 289 | 290 | 291 | } 292 | 293 | #ifdef GTF_HEADER_ONLY 294 | # include "task.cpp" 295 | #endif 296 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.1) 2 | enable_language(CXX) 3 | set(CMAKE_CXX_STANDARD 14) # C++14... 4 | set(CMAKE_CXX_STANDARD_REQUIRED ON) #...is required... 5 | set(CMAKE_CXX_EXTENSIONS OFF) #...without compiler extensions like gnu++11 6 | 7 | option(GTF_Test_ENABLE_COVERAGE "enable coverage" OFF) 8 | # find_package(Threads REQUIRED) 9 | 10 | ## Set our project name 11 | project(GTF_Test) 12 | 13 | set(gtf_test_src 14 | test.cpp 15 | ) 16 | if(MSVC) 17 | # Force to always compile with W4 18 | if(CMAKE_CXX_FLAGS MATCHES "/W[0-4]") 19 | string(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") 20 | else() 21 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4") 22 | endif() 23 | elseif(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) 24 | # Update if necessary 25 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wno-long-long -pedantic") 26 | #for coverage 27 | if(GTF_Test_ENABLE_COVERAGE) 28 | message(STATUS "coverage enabled") 29 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/../cmake/modules) 30 | include(CodeCoverage) 31 | APPEND_COVERAGE_COMPILER_FLAGS() 32 | set(COVERAGE_EXCLUDES "*iutest*" "*/usr/include/*") 33 | SETUP_TARGET_FOR_COVERAGE( 34 | NAME GTF_Test_coverage # New target name 35 | EXECUTABLE GTF_Test# Executable in PROJECT_BINARY_DIR 36 | DEPENDENCIES GTF_Test # Dependencies to build first 37 | ) 38 | endif() 39 | endif() 40 | ## Define the executable 41 | add_executable(GTF_Test ${gtf_test_src}) 42 | if(WIN32) 43 | target_link_libraries(GTF_Test ws2_32) 44 | endif() 45 | # target_link_libraries(GTF_Test Threads::Threads) 46 | -------------------------------------------------------------------------------- /test/README.md: -------------------------------------------------------------------------------- 1 | # Test 2 | 3 | 単体テスト用のdirectoryです。 4 | 5 | 単体テストフレームワークには、[iutest](https://github.com/srz-zumix/iutest)を利用しています。 6 | 7 | ## ビルド方法 8 | 9 | ### 通常のビルド 10 | 11 | CMakeが必要です。 12 | 13 | ```sh 14 | $ mkdir -p build 15 | $ cd $_ 16 | $ cmake -DCMAKE_BUILD_TYPE=Debug .. 17 | $ make 18 | ``` 19 | 20 | Debugビルドではないときは`-DCMAKE_BUILD_TYPE=Debug`を取り除いてください 21 | 22 | ### coverageを有効にする 23 | 24 | - gcc 25 | - gcov 26 | - lcov 27 | - perl 28 | 29 | が必要です。 30 | 31 | Windowsではmsys2のMINGW64 shellで 32 | 33 | ```sh 34 | $ pacman -S base_devel mingw-w64-x86_64-gcc mingw-w64-x86_64-cmake git 35 | $ cd ~ 36 | $ git clone https://github.com/Alexpux/MINGW-packages.git --depth=1 37 | $ cd MINGW-packages/mingw-w64-lcov 38 | $ makepkg -cs 39 | $ pacamn -U mingw-w64-x86_64-lcov-1.13-1-any.pkg.tar.xz 40 | ``` 41 | 42 | としてください。`mingw-w64-x86_64-lcov`のpacmanから落ちてくる`1.12-1`は壊れています(ref https://github.com/Alexpux/MINGW-packages/issues/3156)。 43 | 44 | ```sh 45 | $ mkdir -p build 46 | $ cd $_ 47 | $ cmake -DCMAKE_BUILD_TYPE=Debug -DGTF_Test_ENABLE_COVERAGE=1 .. 48 | $ make 49 | $ make GTF_Test_coverage 50 | ``` 51 | 52 | msys2では`make`の代わりに`ninja`を利用しないでください。`pacamn -U mingw-w64-x86_64-lcov-1.13-1-any.pkg.tar.xz`で`/mingw64/bin/lcov.exe`ではないく`/mingw64/bin/lcov`がインストールされるため、Windowsがこれを実行ファイルと認識できないためです。 53 | 54 | gcov, lcovが見つからないというエラーが出る場合は、`-DGCOV_PATH=`/`-DLCOV_PATH=`を`cmake`に指定してください 55 | 56 | 生成した`GTF_Test_coverage.info.cleaned`をhtmlにしたい場合は 57 | 58 | ``` 59 | $ genhtml -O . GTF_Test_coverage.info.cleaned 60 | ``` 61 | 62 | などとすればいいです。`-O`がhtmlの生成先を指定するものです。 63 | -------------------------------------------------------------------------------- /test/test.cpp: -------------------------------------------------------------------------------- 1 | #define GTF_HEADER_ONLY 2 | #include "../iutest/include/iutest.hpp" 3 | #include "../src/system/task.h" 4 | 5 | #include 6 | 7 | using namespace gtf; 8 | 9 | IUTEST_MAKE_PEEP(std::weak_ptr (TaskManager::*)(unsigned int) const, TaskManager, FindBGTask); 10 | 11 | static std::vector veve; 12 | 13 | template 14 | class CTekitou : public B 15 | { 16 | public: 17 | CTekitou(T init) : hogehoge(init) 18 | { 19 | 20 | } 21 | ~CTekitou() 22 | {} 23 | 24 | T hogehoge; 25 | unsigned int GetID() const override { return hogehoge; } 26 | int GetDrawPriority() const override { return 1; } 27 | void Draw() override { veve.push_back(hogehoge); } 28 | }; 29 | 30 | template 31 | class CTekitou2 : public B 32 | { 33 | public: 34 | CTekitou2(T init, Arg&&... args) : B(std::forward(args)...), hogehoge(init) 35 | { 36 | 37 | } 38 | ~CTekitou2() 39 | {} 40 | 41 | T hogehoge; 42 | 43 | bool Execute(double /* e */) override{ veve.push_back(hogehoge); return true; } 44 | unsigned int GetID()const override{ return hogehoge; } 45 | }; 46 | 47 | template 48 | class CExTaskSelfDestruct : public ExclusiveTaskBase 49 | { 50 | public: 51 | CExTaskSelfDestruct(T init, Arg&&... args) : ExclusiveTaskBase(std::forward(args)...), hogehoge(init) 52 | { 53 | 54 | } 55 | ~CExTaskSelfDestruct() 56 | {} 57 | 58 | T hogehoge; 59 | 60 | bool Execute(double /* e */) override{ veve.push_back(hogehoge); return false; } 61 | unsigned int GetID()const override{ return hogehoge; } 62 | }; 63 | 64 | IUTEST(gtfTest, TestMethod1) 65 | { 66 | TaskManager task; 67 | auto ptr = task.AddNewTask< CTekitou >(1); 68 | IUTEST_ASSERT_EQ((void*)task.FindTask(ptr->GetID()).get(), (void*)ptr.get()); 69 | } 70 | 71 | IUTEST(gtfTest, TestMethod2) 72 | { 73 | TaskManager task; 74 | auto ptr = task.AddNewTask< CTekitou2 >(1); 75 | IUTEST_ASSERT_EQ((void*)(task.FindTask(ptr->GetID())).get(), (void*)ptr.get()); 76 | } 77 | IUTEST(gtfTest, TestMethod3) 78 | { 79 | TaskManager task; 80 | auto ptr = task.AddNewTask< CTekitou2 >(1); 81 | IUTEST_ASSERT_NE((void*)task.FindTask(ptr->GetID()).get(), (void*)ptr.get()); 82 | } 83 | IUTEST(gtfTest, RunOrder1) 84 | { 85 | TaskManager task; 86 | veve.clear(); 87 | auto ptr = task.AddNewTask< CTekitou2 >(1); 88 | auto ptr2 = task.AddNewTask< CTekitou2 >(2); 89 | //modify veve 90 | task.Execute(0); 91 | task.Execute(1); 92 | IUTEST_ASSERT_EQ(1, veve[0]); 93 | IUTEST_ASSERT_EQ(1, veve[1]); 94 | } 95 | IUTEST(gtfTest, RunOrder2) 96 | { 97 | static TaskManager task; 98 | class ct : public CTekitou2 < int, ExclusiveTaskBase > 99 | { 100 | public: 101 | ct(int init) : CTekitou2 < int, ExclusiveTaskBase >(init) {} 102 | void Initialize() 103 | { 104 | task.AddNewTask< CTekitou2 >(2); 105 | } 106 | }; 107 | 108 | veve.clear(); 109 | auto ptr = task.AddNewTask(1); 110 | task.Execute(0); 111 | task.Execute(1); 112 | IUTEST_ASSERT_EQ(1, veve[0]); 113 | IUTEST_ASSERT_EQ(2, veve[1]); 114 | } 115 | 116 | IUTEST(gtfTest, Draw1) 117 | { 118 | static TaskManager task; 119 | class ct2 : public CTekitou2 < int, ExclusiveTaskBase > 120 | { 121 | public: 122 | ct2(int init) : CTekitou2 < int, ExclusiveTaskBase >(init) 123 | { 124 | 125 | } 126 | void Initialize() 127 | { 128 | task.AddNewTask< CTekitou >(hogehoge + 1); 129 | } 130 | }; 131 | 132 | for (int i = 1; i < 257; i++) 133 | { 134 | task.AddNewTask(i * 2); 135 | task.Execute(0); 136 | } 137 | veve.clear(); 138 | task.RemoveTaskByID(1); 139 | for (int i = 0; i < 4; i++) 140 | task.Draw(); 141 | 142 | IUTEST_ASSERT_EQ(513, veve[0]); 143 | } 144 | IUTEST(gtfTest, Draw2) 145 | { 146 | static TaskManager task; 147 | class ct2 : public CTekitou2 < int, ExclusiveTaskBase > 148 | { 149 | public: 150 | ct2(int init) : CTekitou2 < int, ExclusiveTaskBase >(init) 151 | { 152 | 153 | } 154 | void Initialize() 155 | { 156 | task.AddNewTask< CTekitou >(hogehoge + 1); 157 | } 158 | }; 159 | 160 | for (int i = 1; i < 5; i++) 161 | { 162 | task.AddNewTask(i * 2); 163 | task.Execute(0); 164 | } 165 | veve.clear(); 166 | task.RemoveTaskByID(1); 167 | for (int i = 0; i < 4; i++) 168 | task.Draw(); 169 | 170 | IUTEST_ASSERT_EQ(3, veve[0]); 171 | } 172 | IUTEST(gtfTest, DrawFallthrough) 173 | { 174 | static TaskManager task; 175 | class ct2 : public CTekitou2 < int, ExclusiveTaskBase, bool > 176 | { 177 | public: 178 | ct2(int init) : CTekitou2 < int, ExclusiveTaskBase, bool >(init, true) 179 | { 180 | 181 | } 182 | void Initialize() 183 | { 184 | task.AddNewTask< CTekitou >(hogehoge + 1); 185 | } 186 | }; 187 | 188 | for (int i = 1; i < 5; i++) 189 | { 190 | task.AddNewTask(i * 2); 191 | task.Execute(0); 192 | } 193 | veve.clear(); 194 | task.RemoveTaskByID(1); 195 | for (int i = 0; i < 4; i++) 196 | task.Draw(); 197 | 198 | IUTEST_ASSERT_EQ(3, veve[0]); 199 | } 200 | 201 | IUTEST(gtfTest, TaskDependency) 202 | { 203 | static TaskManager task; 204 | class ct : public CTekitou2 < int, ExclusiveTaskBase > 205 | { 206 | public: 207 | ct(int init) : CTekitou2 < int, ExclusiveTaskBase >(init) 208 | { 209 | 210 | } 211 | void Initialize() 212 | { 213 | task.AddNewTask< CTekitou2 >(hogehoge + 20); 214 | } 215 | virtual bool Inactivate(unsigned int /* nextTaskID */){ return true; }//!< 他の排他タスクが開始したときに呼ばれる 216 | }; 217 | 218 | veve.clear(); 219 | auto ptr = task.AddNewTask(1); 220 | task.Execute(0); 221 | auto ptr2 = task.AddNewTask(3); 222 | task.Execute(1); 223 | IUTEST_ASSERT_EQ(1, veve[0]); 224 | IUTEST_ASSERT_EQ(1 + 20, veve[1]); 225 | IUTEST_ASSERT_EQ(3, veve[2]); 226 | IUTEST_ASSERT_EQ(3 + 20, veve[3]); 227 | task.RevertExclusiveTaskByID(1); 228 | task.Execute(3); 229 | IUTEST_ASSERT_EQ(1, veve[4]); 230 | IUTEST_ASSERT_EQ(1 + 20, veve[5]); 231 | ptr2 = task.AddNewTask(4); 232 | task.Execute(4); 233 | task.RemoveTaskByID(21); 234 | task.Execute(5); 235 | IUTEST_ASSERT_EQ(4, veve[8]); 236 | IUTEST_ASSERT_EQ(4 + 20, veve[9]); 237 | } 238 | IUTEST(gtfTest, ReuseContainer) 239 | { 240 | TaskManager task; 241 | auto ptr = task.AddNewTask< CTekitou2 >(1); 242 | IUTEST_ASSERT_NE((void*)task.FindTask(ptr->GetID()).get(), (void*)ptr.get()); 243 | 244 | task.Destroy(); 245 | task.Execute(0); 246 | IUTEST_ASSERT_EQ((void*)task.GetTopExclusiveTask().lock().get(), (void*)nullptr); 247 | 248 | auto ptr3 = task.AddNewTask< CTekitou2 >(1); 249 | task.Execute(0); 250 | IUTEST_ASSERT_NE((void*)task.FindTask(ptr3->GetID()).get(), (void*)ptr3.get()); 251 | } 252 | IUTEST(gtfTest, ExTaskSelfDeestruct) 253 | { 254 | TaskManager task; 255 | veve.clear(); 256 | auto ptr = task.AddNewTask< CTekitou2 >(1); 257 | task.Execute(0); 258 | auto ptr2 = task.AddNewTask< CExTaskSelfDestruct >(2); 259 | task.Execute(0); 260 | task.Execute(0); 261 | IUTEST_ASSERT_EQ(1, veve[0]); 262 | IUTEST_ASSERT_EQ(2, veve[1]); 263 | IUTEST_ASSERT_EQ(1, veve[2]); 264 | } 265 | int main(int argc, char** argv) 266 | { 267 | IUTEST_INIT(&argc, argv); 268 | return IUTEST_RUN_ALL_TESTS(); 269 | } 270 | --------------------------------------------------------------------------------