├── .gitignore ├── CMakeLists.txt ├── CMakePresets.json ├── LICENSE ├── README.md ├── dehancer-maths-cpp.pc.in ├── include └── dehancer │ ├── details │ ├── observable_array.hpp │ └── optional.hpp │ ├── histogram.hpp │ ├── interpolator.hpp │ ├── math.hpp │ ├── matrix.hpp │ ├── properties.hpp │ ├── scope_guard.hpp │ ├── spline │ ├── bezier.hpp │ ├── bspline.hpp │ ├── catmul_rom.hpp │ ├── cubic.hpp │ ├── linear.hpp │ ├── matrix_based.hpp │ └── utils.hpp │ └── vectors.hpp ├── lib ├── CMakeLists.txt └── cmake │ ├── Config.cmake.in │ └── dehancer_maths_cpp.cmake ├── src ├── histogram.cpp ├── interpolator.cpp ├── spline │ ├── bezier.cpp │ ├── bspline.cpp │ ├── catmul_rom.cpp │ ├── cubic.cpp │ ├── linear.cpp │ ├── matrix_based.cpp │ └── utils.cpp └── vectors.cpp ├── tests ├── CMakeCommon.in ├── CMakeLists.txt ├── bezier │ ├── CMakeLists.txt │ └── bezier.cpp ├── bspline │ ├── CMakeLists.txt │ └── bspline_test.cpp ├── catmulrom │ ├── CMakeLists.txt │ └── catmulrom.cpp ├── common │ └── matlab_utils.hpp ├── cubic │ ├── CMakeLists.txt │ └── cubic.cpp ├── initial │ ├── CMakeLists.txt │ └── initial.cpp ├── interpolator │ ├── CMakeLists.txt │ └── interpolator.cpp └── vector │ ├── CMakeLists.txt │ └── vector.cpp └── version.txt /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | .env 4 | 5 | # Compiled Object files 6 | *.slo 7 | *.lo 8 | *.o 9 | *.obj 10 | 11 | # Precompiled Headers 12 | *.gch 13 | *.pch 14 | 15 | # Compiled Dynamic libraries 16 | *.so 17 | *.dylib 18 | *.dll 19 | 20 | # Fortran module files 21 | *.mod 22 | *.smod 23 | 24 | # Compiled Static libraries 25 | *.lai 26 | *.la 27 | *.a 28 | *.lib 29 | 30 | # Executables 31 | *.exe 32 | *.out 33 | *.app 34 | 35 | # 36 | # --- 37 | # 38 | CMakeCache.txt 39 | CMakeFiles 40 | CMakeScripts 41 | Testing 42 | cmake_install.cmake 43 | install_manifest.txt 44 | compile_commands.json 45 | CTestTestfile.cmake 46 | build 47 | build-* 48 | cmake-build-* 49 | .idea 50 | .idea/* 51 | Index 52 | Build 53 | Pods 54 | Podfile.lock 55 | *.xcworkspacedata 56 | .version 57 | .vscode 58 | # Build 59 | build 60 | *-build-* 61 | *.user 62 | .DS_Store 63 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.22) 2 | 3 | # 4 | # Project 5 | # 6 | set(PROJECT_LIB dehancer_maths_cpp) 7 | project(${PROJECT_LIB} VERSION 0.12.0) 8 | 9 | if(UNIX AND NOT APPLE) 10 | set(LINUX TRUE) 11 | endif() 12 | 13 | 14 | # 15 | # Options 16 | # 17 | option(BUILD_TESTING "Enable creation of Armadillo tests." OFF) 18 | option(DEHANCER_TARGET_ARCH "") 19 | option(VCPKG_TARGET_TRIPLET "") 20 | 21 | option(DEHANCER_COMMON_DIR "") 22 | if (NOT DEHANCER_COMMON_DIR) 23 | set(DEHANCER_COMMON_DIR ${CMAKE_BINARY_DIR}/tmp) 24 | endif () 25 | 26 | option(EXTERNAL_INSTALL_LOCATION "") 27 | if (NOT EXTERNAL_INSTALL_LOCATION) 28 | set (EXTERNAL_INSTALL_LOCATION ${CMAKE_BINARY_DIR}/external) 29 | endif () 30 | 31 | 32 | # 33 | # Global settings 34 | # 35 | set(VERSION_FILE "version.txt") 36 | set(CMAKE_CXX_STANDARD 17) 37 | 38 | if (NOT WIN32) 39 | set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g") 40 | set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3") 41 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -lstdc++ -fvisibility=default -Wno-unused-command-line-argument") 42 | endif () 43 | 44 | # 45 | # Generators 46 | # 47 | file (WRITE "${VERSION_FILE}" "${PROJECT_NAME} ${PROJECT_VERSION}") 48 | 49 | # 50 | # Packages 51 | # 52 | find_package (PkgConfig QUIET) 53 | 54 | if(LINUX) 55 | 56 | find_package (lapack) 57 | 58 | if (LAPACK_NOT_FOUND) 59 | message(FATAL "LAPACK has not bin found at all. $ git clone https://github.com/Reference-LAPACK/lapack-release and install") 60 | else() 61 | message("LAPACK LIBRARY: ${LAPACK_LIBRARIES}") 62 | endif () 63 | 64 | else() 65 | 66 | find_package (LAPACK REQUIRED) 67 | find_package (BLAS REQUIRED) 68 | 69 | endif() 70 | 71 | set(CMAKE_INSTALL_LIBDIR "lib") 72 | 73 | if (LINUX) 74 | 75 | set(DEHANCER_EXT_MATH_LIB) 76 | 77 | set(FORTRAN_LIB_PATHS ${CMAKE_SYSTEM_LIBRARY_PATH};/usr/lib/gcc/x86_64-redhat-linux/8;/usr/lib/gcc/x86_64-linux-gnu/9;/usr/lib/gcc/x86_64-linux-gnu/8;/usr/lib/gcc/x86_64-linux-gnu;/lib64;/lib;/usr/lib64;/usr/lib;/usr/local/lib64;/usr/local/lib;/opt/local/lib64;/opt/local/lib) 78 | 79 | message(STATUS "FORTRAN_LIB_PATHS: ${FORTRAN_LIB_PATHS}") 80 | 81 | find_library(GFORTRAN_LIBRARY 82 | NAMES gfortran 83 | PATHS ${FORTRAN_LIB_PATHS} 84 | REQUIRED 85 | ) 86 | 87 | find_library(GQUADMATH_LIBRARY 88 | NAMES quadmath 89 | PATHS ${FORTRAN_LIB_PATHS} 90 | ) 91 | 92 | message("GFORTRAN_LIBRARY: ${GFORTRAN_LIBRARY}") 93 | 94 | set(DEHANCER_EXT_MATH_LIB ${BLAS_LIBRARIES};${LAPACK_LIBRARIES}) 95 | 96 | if (GFORTRAN_LIBRARY) 97 | set(DEHANCER_EXT_MATH_LIB ${DEHANCER_EXT_MATH_LIB};${GFORTRAN_LIBRARY};m) 98 | else () 99 | set(DEHANCER_EXT_MATH_LIB ${DEHANCER_EXT_MATH_LIB};m) 100 | endif () 101 | 102 | find_library(DEHANCER_EXT_MATH_LIB REQUIRED ${DEHANCER_EXT_MATH}) 103 | 104 | else() 105 | set(DEHANCER_EXT_MATH_LIB ${BLAS_LIBRARIES};${LAPACK_LIBRARIES}) 106 | endif () 107 | 108 | include_directories(${BLAS_INCLUDE_DIRS} ${LAPACK_INCLUDE_DIRS}) 109 | 110 | message("BLASS/LAPACK: ${DEHANCER_EXT_MATH_LIB}") 111 | 112 | 113 | find_package(Threads REQUIRED) 114 | 115 | if(NOT PKG_CONFIG_FOUND) 116 | message(FATAL_ERROR "pkg-config not found!" ) 117 | message(FATAL_ERROR "sudo apt-get install pkg-config, or brew install pkg-config") 118 | endif() 119 | 120 | # 121 | # Programms 122 | # 123 | find_program(CCACHE_FOUND ccache) 124 | find_program(MAKE_EXE NAMES gmake nmake make) 125 | 126 | # 127 | # CCache settings 128 | # 129 | if(CCACHE_FOUND) 130 | set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache) 131 | set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache) 132 | endif(CCACHE_FOUND) 133 | 134 | 135 | # 136 | # Compiler settings 137 | # 138 | 139 | message(STATUS "CMAKE_CXX_COMPILER_ID: " ${CMAKE_CXX_COMPILER_ID}) 140 | 141 | if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang") 142 | 143 | message(STATUS "Using Clang" ) 144 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wc++17-extensions") 145 | 146 | elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") 147 | 148 | message(STATUS "Using gcc" ) 149 | 150 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -W -Wall -Wextra -Wno-ignored-qualifiers -Wvariadic-macros -pthread -static-libgcc -static-libstdc++") 151 | set(CMAKE_CXX_FLAGS "-fvisibility=default -Wno-pedantic") 152 | set(CMAKE_LINK_DEPENDS_NO_SHARED TRUE) 153 | 154 | add_compile_options(-lpthread) 155 | 156 | if (${CMAKE_SYSTEM_NAME} STREQUAL Linux) 157 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DX86_LINUX") 158 | endif() 159 | 160 | elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel") 161 | 162 | message( FATAL_ERROR "The project does not support Intel compiler" ) 163 | 164 | elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") 165 | 166 | message( FATAL_ERROR "The project does not support MSVC compiler" ) 167 | 168 | endif() 169 | 170 | if (WIN32) 171 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -EHsc -Wno-deprecated-declarations") 172 | add_definitions(/MT /DWIN32=1 /D_ITERATOR_DEBUG_LEVEL=0 /GR /Ob0) 173 | string(TOLOWER ${CMAKE_BUILD_TYPE} BUILD_TYPE) 174 | if (${BUILD_TYPE} STREQUAL "debug") 175 | add_definitions(/MTd) 176 | endif() 177 | else() 178 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -rdynamic") 179 | endif () 180 | 181 | # 182 | # Package manager 183 | # 184 | include(ExternalProject) 185 | 186 | # 187 | # External project dependencies 188 | # 189 | set(COMMON_DEPENDENCIES) 190 | set(COMMON_LIBRARIES ${DEHANCER_EXT_MATH_LIB};${CMAKE_THREAD_LIBS_INIT};${MKL_LIBRARIES}) 191 | 192 | string(STRIP "${CMAKE_C_FLAGS} -D_ITERATOR_DEBUG_LEVEL=0" C_FLAGS) 193 | string(STRIP "${CMAKE_CXX_FLAGS} -D_ITERATOR_DEBUG_LEVEL=0" CXX_FLAGS) 194 | 195 | include(FetchContent) 196 | 197 | # 198 | # Google Test 199 | # 200 | if (BUILD_TESTING) 201 | 202 | find_package(GTest) 203 | 204 | if (NOT GTest_FOUND) 205 | 206 | string(STRIP "${CMAKE_C_FLAGS} -D_ITERATOR_DEBUG_LEVEL=0" C_FLAGS) 207 | string(STRIP "${CMAKE_CXX_FLAGS} -D_ITERATOR_DEBUG_LEVEL=0" CXX_FLAGS) 208 | 209 | set(CMAKE_OSX_ARCHITECTURES "${CMAKE_OSX_ARCHITECTURES}" CACHE STRING "" FORCE) 210 | 211 | FetchContent_Declare( 212 | googletest 213 | GIT_REPOSITORY https://github.com/google/googletest.git 214 | GIT_TAG v1.14.0 215 | SOURCE_DIR "${CMAKE_BINARY_DIR}/googletest-src" 216 | ) 217 | 218 | FetchContent_MakeAvailable(googletest) 219 | # FetchContent_GetProperties(googletest) 220 | # 221 | # if(NOT googletest_POPULATED) 222 | # FetchContent_Populate(googletest) 223 | # add_subdirectory(${googletest_SOURCE_DIR} ${googletest_BINARY_DIR} EXCLUDE_FROM_ALL) 224 | # endif() 225 | 226 | endif () 227 | 228 | endif () 229 | 230 | #if (LINUX) 231 | set (BUILD_SMOKE_TEST OFF CACHE INTERNAL "BUILD_SMOKE_TEST OFF") 232 | set (BUILD_SHARED_LIBS OFF CACHE INTERNAL "BUILD_SHARED_LIBS OFF") 233 | #endif () 234 | 235 | FetchContent_Declare( 236 | armadillo 237 | # GIT_REPOSITORY https://github.com/dehancer/armadillo-code 238 | # GIT_TAG 9.700.x 239 | GIT_REPOSITORY https://gitlab.com/conradsnicta/armadillo-code 240 | GIT_TAG 12.8.x 241 | GIT_PROGRESS YES 242 | GIT_SHALLOW YES 243 | SOURCE_DIR "${CMAKE_BINARY_DIR}/armadillo-src" 244 | BINARY_DIR "${CMAKE_BINARY_DIR}/armadillo-build" 245 | ) 246 | FetchContent_MakeAvailable(armadillo) 247 | 248 | FetchContent_GetProperties(armadillo) 249 | 250 | # On iOS Armadillo has to be built with ARMA_USE_WRAPPER defined. 251 | if(armadillo_POPULATED AND CMAKE_SYSTEM_NAME STREQUAL "iOS") 252 | file(READ "${armadillo_SOURCE_DIR}/include/armadillo_bits/config.hpp" CONTENT) 253 | string(REGEX REPLACE "//[ ]+#define[ ]+ARMA_USE_WRAPPER" "#define ARMA_USE_WRAPPER" CONTENT_MODIFIED "${CONTENT}") 254 | file(WRITE "${armadillo_SOURCE_DIR}/include/armadillo_bits/config.hpp" "${CONTENT_MODIFIED}") 255 | message(STATUS "Armadillo DODODO: ${armadillo_SOURCE_DIR}") 256 | endif() 257 | 258 | include_directories( 259 | ${armadillo_SOURCE_DIR}/include 260 | ${CMAKE_CURRENT_BINARY_DIR} 261 | ) 262 | 263 | set(COMMON_LIBRARIES armadillo;${COMMON_LIBRARIES}) 264 | 265 | # 266 | # Details 267 | # 268 | add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/lib) 269 | 270 | if(BUILD_TESTING) 271 | add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/tests) 272 | enable_testing () 273 | endif() 274 | 275 | # Install package 276 | # 277 | if (NOT CMAKE_INSTALL_LIBDIR) 278 | set(CMAKE_INSTALL_LIBDIR lib) 279 | endif () 280 | if (NOT CMAKE_INSTALL_INCLUDEDIR) 281 | set(CMAKE_INSTALL_INCLUDEDIR include) 282 | endif () 283 | 284 | set(prefix ${CMAKE_INSTALL_PREFIX}) 285 | set(exec_prefix "\${prefix}") 286 | set(libdir "\${exec_prefix}/${CMAKE_INSTALL_LIBDIR}") 287 | set(includedir "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}") 288 | set(extra_math_libs "${DEHANCER_EXT_MATH_LIB}") 289 | 290 | 291 | configure_file(${CMAKE_CURRENT_SOURCE_DIR}/dehancer-maths-cpp.pc.in ${CMAKE_CURRENT_BINARY_DIR}/dehancer-maths-cpp.pc @ONLY) 292 | 293 | install(FILES 294 | ${CMAKE_CURRENT_BINARY_DIR}/dehancer-maths-cpp.pc 295 | DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig 296 | ) 297 | -------------------------------------------------------------------------------- /CMakePresets.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 3, 3 | "cmakeMinimumRequired": { 4 | "major": 3, 5 | "minor": 22, 6 | "patch": 0 7 | }, 8 | 9 | "configurePresets": [ 10 | 11 | { 12 | "name": "vs17", 13 | "hidden": true, 14 | "generator": "Visual Studio 17 2022", 15 | "toolset": "ClangCL" 16 | }, 17 | 18 | { 19 | "name": "ninja", 20 | "hidden": true, 21 | "generator": "Ninja" 22 | }, 23 | 24 | { 25 | "name": "unix", 26 | "hidden": true, 27 | "generator": "Unix Makefiles" 28 | }, 29 | 30 | { 31 | "name": "ios-xcode", 32 | "hidden": true, 33 | "generator": "Xcode" 34 | }, 35 | 36 | { 37 | "name": "msvc2022", 38 | "hidden": true, 39 | 40 | "environment": { 41 | "MSVC_BIN_DIR": "C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/Llvm/x64/bin", 42 | "PATH": "$env{MSVC_BIN_DIR};$penv{PATH}" 43 | } 44 | 45 | }, 46 | 47 | { 48 | 49 | "name": "windows", 50 | "hidden": true, 51 | "binaryDir": "${sourceDir}/build-${presetName}", 52 | "toolchainFile": "C:/vcpkg/scripts/buildsystems/vcpkg.cmake", 53 | "warnings": { 54 | "unusedCli": false 55 | }, 56 | 57 | "environment": { 58 | "HOME": "$env{USERPROFILE}" 59 | }, 60 | 61 | "cacheVariables": { 62 | 63 | "CMAKE_INSTALL_PREFIX": { 64 | "type": "STRING", 65 | "value": "$env{HOME}/Develop/local/${hostSystemName}/$env{BUILD_TYPE}/dehancer" 66 | }, 67 | 68 | "CMAKE_SHARED_LINKER_FLAGS": "/MANIFEST:NO", 69 | "CMAKE_EXE_LINKER_FLAGS": "/MANIFEST:NO", 70 | "CMAKE_C_COMPILER": "$env{MSVC_BIN_DIR}/clang-cl.exe", 71 | "CMAKE_CXX_COMPILER": "$env{MSVC_BIN_DIR}/clang-cl.exe", 72 | 73 | "CMAKE_SYSTEM_NAME": "Windows", 74 | "CMAKE_SYSTEM_VERSION": "10.0", 75 | 76 | "VCPKG_TARGET_TRIPLET": "x64-windows-static", 77 | 78 | "BUILD_SHARED_LIBS": { 79 | "type": "BOOL", 80 | "value": "OFF" 81 | }, 82 | 83 | "DEHANCER_CONTROLLED_SINGLETON": { 84 | "type": "BOOL", 85 | "value": "OFF" 86 | }, 87 | 88 | "USE_UNICODE" : { 89 | "type": "BOOL", 90 | "value": "ON" 91 | } 92 | 93 | } 94 | 95 | }, 96 | 97 | { 98 | "name": "macos", 99 | 100 | "hidden": true, 101 | 102 | "binaryDir": "${sourceDir}/build-${presetName}", 103 | 104 | "warnings": { 105 | "unusedCli": false 106 | }, 107 | 108 | "cacheVariables": { 109 | 110 | "CMAKE_INSTALL_PREFIX": { 111 | "type": "STRING", 112 | "value": "$env{HOME}/Develop/local/${hostSystemName}/$env{BUILD_TYPE}/dehancer" 113 | }, 114 | 115 | "CMAKE_OSX_ARCHITECTURES": { 116 | "type": "STRING", 117 | "value": "arm64;x86_64" 118 | }, 119 | 120 | "CMAKE_OSX_DEPLOYMENT_TARGET": { 121 | "type": "STRING", 122 | "value": "11.0" 123 | }, 124 | 125 | "CMAKE_OSX_SYSROOT": { 126 | "type": "STRING", 127 | "value": "macosx" 128 | }, 129 | 130 | "BUILD_SHARED_LIBS": { 131 | "type": "STRING", 132 | "value": "OFF" 133 | } 134 | 135 | } 136 | }, 137 | 138 | { 139 | "name": "ios", 140 | 141 | "hidden": true, 142 | 143 | "binaryDir": "${sourceDir}/build-${presetName}", 144 | 145 | "warnings": { 146 | "unusedCli": false 147 | }, 148 | 149 | "cacheVariables": { 150 | "CMAKE_INSTALL_PREFIX": { 151 | "type": "STRING", 152 | "value": "$env{HOME}/Develop/local/ios-$env{BUILD_TYPE}/dehancer" 153 | }, 154 | 155 | "PLATFORM": { 156 | "type": "STRING", 157 | "value": "OS64COMBINED" 158 | }, 159 | 160 | "DEPLOYMENT_TARGET": { 161 | "type": "STRING", 162 | "value": "14.0" 163 | }, 164 | 165 | "CMAKE_TOOLCHAIN_FILE" : { 166 | "type" : "STRING", 167 | "value" : "$env{HOME}/Develop/Dehancer/Dehancer-Plugins/ios-cmake/ios.toolchain.cmake" 168 | }, 169 | 170 | "BUILD_SHARED_LIBS": { 171 | "type": "STRING", 172 | "value": "OFF" 173 | }, 174 | 175 | "EXIV2_BUILD_SAMPLES": { 176 | "type": "STRING", 177 | "value": "OFF" 178 | }, 179 | 180 | "EXIV2_BUILD_EXIV2_COMMAND": { 181 | "type": "STRING", 182 | "value": "OFF" 183 | }, 184 | 185 | "EXIV2_ENABLE_XMP": { 186 | "type": "STRING", 187 | "value": "ON" 188 | }, 189 | 190 | "EXIV2_ENABLE_DYNAMIC_RUNTIME": { 191 | "type": "STRING", 192 | "value": "OFF" 193 | }, 194 | 195 | "CURL_ROOT_PATH": { 196 | "type": "STRING", 197 | "value": "$env{HOME}/Develop/local/ios" 198 | } 199 | } 200 | }, 201 | 202 | { 203 | "name": "linux", 204 | 205 | "hidden": true, 206 | 207 | "binaryDir": "${sourceDir}/build-${presetName}", 208 | 209 | "vendor": { 210 | "jetbrains.com/clion": { 211 | "toolchain": "Docker-rockylinux-qt5", 212 | "toolset": "ClangCL" 213 | } 214 | }, 215 | 216 | "warnings": { 217 | "unusedCli": false 218 | }, 219 | 220 | "cacheVariables": { 221 | 222 | "CMAKE_INSTALL_PREFIX": { 223 | "type": "STRING", 224 | "value": "$env{HOME}/Develop/local/${hostSystemName}/$env{BUILD_TYPE}/dehancer" 225 | }, 226 | 227 | "BUILD_SHARED_LIBS": { 228 | "type": "STRING", 229 | "value": "OFF" 230 | } 231 | 232 | } 233 | 234 | }, 235 | 236 | { 237 | 238 | "name": "debug", 239 | "hidden": true, 240 | 241 | "environment": { 242 | "BUILD_TYPE": "debug" 243 | }, 244 | 245 | "cacheVariables": { 246 | 247 | "GTest_ROOT": { 248 | "type": "STRING", 249 | "value": "$env{HOME}/Develop/local/${hostSystemName}" 250 | }, 251 | 252 | "DEHANCER_DEBUG": { 253 | "type": "STRING", 254 | "value": "ON" 255 | }, 256 | 257 | "PRINT_DEBUG": { 258 | "type": "STRING", 259 | "value": "ON" 260 | }, 261 | 262 | "BUILD_TESTING": { 263 | "type": "STRING", 264 | "value": "ON" 265 | }, 266 | 267 | "CMAKE_BUILD_TYPE": "Debug" 268 | 269 | } 270 | }, 271 | 272 | { 273 | "name": "windows_debug", 274 | "hidden": true, 275 | "cacheVariables": { 276 | "CMAKE_BUILD_TYPE": "Release" 277 | }, 278 | "inherits": ["debug"] 279 | }, 280 | 281 | { 282 | 283 | "name": "release", 284 | "hidden": true, 285 | 286 | "environment": { 287 | "BUILD_TYPE": "release" 288 | }, 289 | 290 | "cacheVariables": { 291 | 292 | "DEHANCER_DEBUG": { 293 | "type": "STRING", 294 | "value": "OFF" 295 | }, 296 | 297 | "PRINT_DEBUG": { 298 | "type": "STRING", 299 | "value": "OFF" 300 | }, 301 | 302 | "BUILD_TESTING": { 303 | "type": "STRING", 304 | "value": "OFF" 305 | }, 306 | 307 | "CMAKE_BUILD_TYPE": "Release" 308 | 309 | } 310 | }, 311 | 312 | 313 | { 314 | "name": "windows_release", 315 | "hidden": true, 316 | "cacheVariables": { 317 | "CMAKE_BUILD_TYPE": "Release" 318 | }, 319 | "inherits": ["release"] 320 | }, 321 | 322 | { 323 | "name": "windows-debug", 324 | "displayName": "Dehancer userlib windows debug build, x86_64", 325 | "inherits": [ "windows_debug", "msvc2022", "ninja", "windows" ] 326 | }, 327 | 328 | { 329 | "name": "windows-release", 330 | "displayName": "Dehancer userlib windows release build, x86_64", 331 | "inherits": [ "windows_release", "msvc2022", "ninja", "windows" ] 332 | }, 333 | 334 | { 335 | "name": "macos-debug", 336 | "displayName": "Dehancer userlib build, arm64; x86_64", 337 | "inherits": [ "macos", "debug" ] 338 | }, 339 | 340 | { 341 | "name": "macos-release", 342 | "displayName": "Dehancer userlib build, arm64; x86_64", 343 | "inherits": [ "macos", "release" ] 344 | }, 345 | 346 | { 347 | "name": "linux-debug", 348 | "displayName": "Dehancer userlib build, x86_64", 349 | "inherits": [ "unix", "debug", "linux" ] 350 | }, 351 | 352 | { 353 | "name": "linux-release", 354 | "displayName": "Dehancer userlib build, x86_64", 355 | "inherits": [ "unix", "release", "linux"] 356 | }, 357 | 358 | { 359 | "name": "ios-debug", 360 | "displayName": "Dehancer userlib build, OS64-COMBINED", 361 | "inherits": [ "ios", "ios-xcode", "debug" ] 362 | }, 363 | 364 | { 365 | "name": "ios-release", 366 | "displayName": "Dehancer userlib build, OS64-COMBINED", 367 | "inherits": [ "ios", "ios-xcode" ,"release" ] 368 | } 369 | ] 370 | 371 | } 372 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Aithea 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # dehancer-maths-cpp 2 | 3 | ## Requirements 4 | Install: 5 | 1. https://github.com/dnevera/base64cpp 6 | 1. https://github.com/dnevera/ed25519cpp 7 | 1. win32/mvsc+clang: /c/vcpkg/vcpkg install openblas 8 | 1. win32/mvsc+clang: /c/vcpkg/vcpkg install lapack 9 | 10 | Windows GCC 11 | ======= 12 | 13 | # mingw 14 | # Install https://www.msys2.org/ 15 | # https://blog.jetbrains.com/clion/2020/12/setting-up-clang-on-windows/ 16 | 17 | pacman -S mingw-w64-x86_64-toolchain 18 | pacman -S mingw-w64-x86_64-clang 19 | pacman -S mingw-w64-x86_64-cmake 20 | pacman -S libcurl 21 | pacman -S zlib-devel 22 | pacman -S libcurl-devel 23 | 24 | 25 | Windows MVSC 26 | ======= 27 | # Requrements: 28 | # Visual Studio, English Language Pack! 29 | # https://vcpkg.info/ 30 | # GitBash 31 | 32 | cd C: 33 | git clone https://github.com/microsoft/vcpkg 34 | cd /c/vcpkg/ 35 | ./bootstrap-vcpkg.sh 36 | /c/vcpkg/vcpkg integrate install 37 | /c/vcpkg/vcpkg install openblas:x64-windows 38 | /c/vcpkg/vcpkg install lapack:x64-windows 39 | 40 | # cmake integration 41 | -DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake -------------------------------------------------------------------------------- /dehancer-maths-cpp.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@prefix@ 2 | exec_prefix=@exec_prefix@ 3 | libdir=@libdir@ 4 | includedir=@includedir@ 5 | 6 | Name: dehancer-maths-cpp 7 | Description: Dehancer math layer SDK 8 | Version: @PROJECT_VERSION@ 9 | URL: https://github.com/dehancer/dehancer-maths-cpp 10 | Requires.private: @requires_private@ 11 | Libs: -L${libdir} -ldehancer_maths_cpp -larmadillo @extra_math_libs@ 12 | Libs.private: @libs_private@ 13 | CFlags: -I${includedir} 14 | -------------------------------------------------------------------------------- /include/dehancer/details/observable_array.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by denn nevera on 2019-09-04. 3 | // 4 | 5 | #pragma once 6 | 7 | #include 8 | #include "dehancer/properties.hpp" 9 | 10 | namespace dehancer::observable { 11 | 12 | struct auto_lf { 13 | std::function< void() > _lambda; 14 | template< typename RET, typename ... ARGS > 15 | inline auto_lf( RET F( ARGS... ), ARGS... args ) : _lambda{ [ F, args... ] { F( args... ); } } {} 16 | inline auto_lf( std::function< void() >&& func ) : _lambda{ std::move( func ) } {} 17 | inline ~auto_lf() { _lambda(); } 18 | }; 19 | 20 | template 21 | using Handler = std::function; 22 | 23 | template 24 | struct Aproxy { 25 | 26 | Aproxy(T& v, 27 | std::vector& a, 28 | const Handler>& on_update = nullptr): 29 | data_(&v), 30 | root_(&a), 31 | on_update_(on_update) 32 | {} 33 | 34 | Aproxy& operator = (const T& data) { 35 | *data_ = data; 36 | if (on_update_) { 37 | on_update_(*root_); 38 | } 39 | return *this; 40 | } 41 | 42 | Aproxy& operator = (const Aproxy& a) { 43 | *data_ = *a.data_; 44 | root_ = a.root_; 45 | if (on_update_) { 46 | on_update_(*root_); 47 | } 48 | return *this; 49 | } 50 | 51 | PROPERTY(point, 52 | T, 53 | Aproxy, 54 | { return get_data(); }, // getter 55 | { get_data() = value; } // setter 56 | ); 57 | 58 | T& get_data() { return *data_;}; 59 | const T& get_data() const { return *data_;}; 60 | 61 | private: 62 | T* data_; 63 | std::vector* root_; 64 | Handler> on_update_; 65 | }; 66 | 67 | template 68 | struct Array { 69 | 70 | Array() = default; 71 | 72 | explicit Array(const std::vector& value){ 73 | //std::copy(value.begin(), value.end(), std::back_inserter(value_)); 74 | for (auto v: value) value_.push_back(v); 75 | } 76 | 77 | Array(const Array& value){ 78 | for (auto v: value.value_) value_.push_back(v); 79 | //std::copy(value.value_.begin(), value.value_.end(), std::back_inserter(value_)); 80 | } 81 | 82 | Handler> on_update = nullptr; 83 | 84 | size_t size() const { return value_.size(); } 85 | 86 | std::vector& operator= (const std::vector& value) { 87 | value_ = value; 88 | if (on_update) { 89 | on_update(value_); 90 | } 91 | return value_; 92 | } 93 | 94 | Array& operator= (const Array& value) { 95 | value_ = value.value_; 96 | if (on_update) { 97 | on_update(value_); 98 | } 99 | return *this; 100 | } 101 | 102 | operator std::vector() const { 103 | return value_; 104 | } 105 | 106 | const T operator[] (int index) const { 107 | if (value_.empty()) return {0,0}; 108 | if (index<0) return value_[0]; 109 | if (index>=value_.size()) return value_[value_.size()-1]; 110 | return value_[index]; 111 | } 112 | 113 | Aproxy operator[](int i) { 114 | 115 | if (i>=value_.size()) { 116 | value_.resize(i+1); 117 | } 118 | 119 | return Aproxy( 120 | value_[i], 121 | value_, 122 | [this](const std::vector& vector){ 123 | if (on_update) 124 | on_update(vector); 125 | }); 126 | } 127 | 128 | friend std::ostream& operator<<(std::ostream& os, const Array& array){ 129 | for (auto &v: array.value_) { 130 | os << v.t(); 131 | } 132 | return os; 133 | } 134 | 135 | private: 136 | std::vector value_; 137 | }; 138 | } 139 | 140 | 141 | 142 | template 143 | std::ostream& operator<<(std::ostream& os, const std::vector& vector){ 144 | for (auto &v: vector) { 145 | os << v.t(); 146 | } 147 | return os; 148 | } 149 | -------------------------------------------------------------------------------- /include/dehancer/details/optional.hpp: -------------------------------------------------------------------------------- 1 | 2 | /// 3 | // optional - An implementation of std::optional with extensions 4 | // Written in 2017 by Simon Brand (simonrbrand@gmail.com, @TartanLlama) 5 | // 6 | // Documentation available at https://tl.tartanllama.xyz/ 7 | // 8 | // To the extent possible under law, the author(s) have dedicated all 9 | // copyright and related and neighboring rights to this software to the 10 | // public domain worldwide. This software is distributed without any warranty. 11 | // 12 | // You should have received a copy of the CC0 Public Domain Dedication 13 | // along with this software. If not, see 14 | // . 15 | /// 16 | 17 | #ifndef TL_OPTIONAL_HPP 18 | #define TL_OPTIONAL_HPP 19 | 20 | #define TL_OPTIONAL_VERSION_MAJOR 1 21 | #define TL_OPTIONAL_VERSION_MINOR 0 22 | #define TL_OPTIONAL_VERSION_PATCH 0 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #if (defined(_MSC_VER) && _MSC_VER == 1900) 31 | #define TL_OPTIONAL_MSVC2015 32 | #endif 33 | 34 | #if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && \ 35 | !defined(__clang__)) 36 | #define TL_OPTIONAL_GCC49 37 | #endif 38 | 39 | #if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 4 && \ 40 | !defined(__clang__)) 41 | #define TL_OPTIONAL_GCC54 42 | #endif 43 | 44 | #if (defined(__GNUC__) && __GNUC__ == 5 && __GNUC_MINOR__ <= 5 && \ 45 | !defined(__clang__)) 46 | #define TL_OPTIONAL_GCC55 47 | #endif 48 | 49 | #if (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ <= 9 && \ 50 | !defined(__clang__)) 51 | // GCC < 5 doesn't support overloading on const&& for member functions 52 | #define TL_OPTIONAL_NO_CONSTRR 53 | 54 | // GCC < 5 doesn't support some standard C++11 type traits 55 | #define TL_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \ 56 | std::has_trivial_copy_constructor::value 57 | #define TL_OPTIONAL_IS_TRIVIALLY_COPY_ASSIGNABLE(T) std::has_trivial_copy_assign::value 58 | 59 | // This one will be different for GCC 5.7 if it's ever supported 60 | #define TL_OPTIONAL_IS_TRIVIALLY_DESTRUCTIBLE(T) std::is_trivially_destructible::value 61 | 62 | // GCC 5 < v < 8 has a bug in is_trivially_copy_constructible which breaks std::vector 63 | // for non-copyable types 64 | #elif (defined(__GNUC__) && __GNUC__ < 8 && \ 65 | !defined(__clang__)) 66 | #ifndef TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX 67 | #define TL_GCC_LESS_8_TRIVIALLY_COPY_CONSTRUCTIBLE_MUTEX 68 | namespace tl { 69 | namespace detail { 70 | template 71 | struct is_trivially_copy_constructible : std::is_trivially_copy_constructible{}; 72 | #ifdef _GLIBCXX_VECTOR 73 | template 74 | struct is_trivially_copy_constructible> 75 | : std::is_trivially_copy_constructible{}; 76 | #endif 77 | } 78 | } 79 | #endif 80 | 81 | #define TL_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \ 82 | tl::detail::is_trivially_copy_constructible::value 83 | #define TL_OPTIONAL_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \ 84 | std::is_trivially_copy_assignable::value 85 | #define TL_OPTIONAL_IS_TRIVIALLY_DESTRUCTIBLE(T) std::is_trivially_destructible::value 86 | #else 87 | #define TL_OPTIONAL_IS_TRIVIALLY_COPY_CONSTRUCTIBLE(T) \ 88 | std::is_trivially_copy_constructible::value 89 | #define TL_OPTIONAL_IS_TRIVIALLY_COPY_ASSIGNABLE(T) \ 90 | std::is_trivially_copy_assignable::value 91 | #define TL_OPTIONAL_IS_TRIVIALLY_DESTRUCTIBLE(T) std::is_trivially_destructible::value 92 | #endif 93 | 94 | #if __cplusplus > 201103L 95 | #define TL_OPTIONAL_CXX14 96 | #endif 97 | 98 | // constexpr implies const in C++11, not C++14 99 | #if (__cplusplus == 201103L || defined(TL_OPTIONAL_MSVC2015) || \ 100 | defined(TL_OPTIONAL_GCC49)) 101 | #define TL_OPTIONAL_11_CONSTEXPR 102 | #else 103 | #define TL_OPTIONAL_11_CONSTEXPR constexpr 104 | #endif 105 | 106 | namespace tl { 107 | #ifndef TL_MONOSTATE_INPLACE_MUTEX 108 | #define TL_MONOSTATE_INPLACE_MUTEX 109 | /// Used to represent an optional with no data; essentially a bool 110 | class monostate {}; 111 | 112 | /// A tag type to tell optional to construct its value in-place 113 | struct in_place_t { 114 | explicit in_place_t() = default; 115 | }; 116 | /// A tag to tell optional to construct its value in-place 117 | static constexpr in_place_t in_place{}; 118 | #endif 119 | 120 | template class optional; 121 | 122 | namespace detail { 123 | #ifndef TL_TRAITS_MUTEX 124 | #define TL_TRAITS_MUTEX 125 | // C++14-style aliases for brevity 126 | template using remove_const_t = typename std::remove_const::type; 127 | template 128 | using remove_reference_t = typename std::remove_reference::type; 129 | template using decay_t = typename std::decay::type; 130 | template 131 | using enable_if_t = typename std::enable_if::type; 132 | template 133 | using conditional_t = typename std::conditional::type; 134 | 135 | // std::conjunction from C++17 136 | template struct conjunction : std::true_type {}; 137 | template struct conjunction : B {}; 138 | template 139 | struct conjunction 140 | : std::conditional, B>::type {}; 141 | 142 | #if defined(_LIBCPP_VERSION) && __cplusplus == 201103L 143 | #define TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND 144 | #endif 145 | 146 | // In C++11 mode, there's an issue in libc++'s std::mem_fn 147 | // which results in a hard-error when using it in a noexcept expression 148 | // in some cases. This is a check to workaround the common failing case. 149 | #ifdef TL_TRAITS_LIBCXX_MEM_FN_WORKAROUND 150 | template struct is_pointer_to_non_const_member_func : std::false_type{}; 151 | template 152 | struct is_pointer_to_non_const_member_func : std::true_type{}; 153 | template 154 | struct is_pointer_to_non_const_member_func : std::true_type{}; 155 | template 156 | struct is_pointer_to_non_const_member_func : std::true_type{}; 157 | template 158 | struct is_pointer_to_non_const_member_func : std::true_type{}; 159 | template 160 | struct is_pointer_to_non_const_member_func : std::true_type{}; 161 | template 162 | struct is_pointer_to_non_const_member_func : std::true_type{}; 163 | 164 | template struct is_const_or_const_ref : std::false_type{}; 165 | template struct is_const_or_const_ref : std::true_type{}; 166 | template struct is_const_or_const_ref : std::true_type{}; 167 | #endif 168 | 169 | // std::invoke from C++17 170 | // https://stackoverflow.com/questions/38288042/c11-14-invoke-workaround 171 | template ::value 174 | && is_const_or_const_ref::value)>, 175 | #endif 176 | typename = enable_if_t>::value>, 177 | int = 0> 178 | constexpr auto invoke(Fn &&f, Args &&... args) noexcept( 179 | noexcept(std::mem_fn(f)(std::forward(args)...))) 180 | -> decltype(std::mem_fn(f)(std::forward(args)...)) { 181 | return std::mem_fn(f)(std::forward(args)...); 182 | } 183 | 184 | template >::value>> 186 | constexpr auto invoke(Fn &&f, Args &&... args) noexcept( 187 | noexcept(std::forward(f)(std::forward(args)...))) 188 | -> decltype(std::forward(f)(std::forward(args)...)) { 189 | return std::forward(f)(std::forward(args)...); 190 | } 191 | 192 | // std::invoke_result from C++17 193 | template struct invoke_result_impl; 194 | 195 | template 196 | struct invoke_result_impl< 197 | F, decltype(detail::invoke(std::declval(), std::declval()...), void()), 198 | Us...> { 199 | using type = decltype(detail::invoke(std::declval(), std::declval()...)); 200 | }; 201 | 202 | template 203 | using invoke_result = invoke_result_impl; 204 | 205 | template 206 | using invoke_result_t = typename invoke_result::type; 207 | 208 | #if defined(_MSC_VER) && _MSC_VER <= 1900 209 | // TODO make a version which works with MSVC 2015 210 | template struct is_swappable : std::true_type {}; 211 | 212 | template struct is_nothrow_swappable : std::true_type {}; 213 | #else 214 | // https://stackoverflow.com/questions/26744589/what-is-a-proper-way-to-implement-is-swappable-to-test-for-the-swappable-concept 215 | namespace swap_adl_tests { 216 | // if swap ADL finds this then it would call std::swap otherwise (same 217 | // signature) 218 | struct tag {}; 219 | 220 | template tag swap(T &, T &); 221 | template tag swap(T (&a)[N], T (&b)[N]); 222 | 223 | // helper functions to test if an unqualified swap is possible, and if it 224 | // becomes std::swap 225 | template std::false_type can_swap(...) noexcept(false); 226 | template (), std::declval()))> 228 | std::true_type can_swap(int) noexcept(noexcept(swap(std::declval(), 229 | std::declval()))); 230 | 231 | template std::false_type uses_std(...); 232 | template 233 | std::is_same(), std::declval())), tag> 234 | uses_std(int); 235 | 236 | template 237 | struct is_std_swap_noexcept 238 | : std::integral_constant::value && 240 | std::is_nothrow_move_assignable::value> {}; 241 | 242 | template 243 | struct is_std_swap_noexcept : is_std_swap_noexcept {}; 244 | 245 | template 246 | struct is_adl_swap_noexcept 247 | : std::integral_constant(0))> {}; 248 | } // namespace swap_adl_tests 249 | 250 | template 251 | struct is_swappable 252 | : std::integral_constant< 253 | bool, 254 | decltype(detail::swap_adl_tests::can_swap(0))::value && 255 | (!decltype(detail::swap_adl_tests::uses_std(0))::value || 256 | (std::is_move_assignable::value && 257 | std::is_move_constructible::value))> {}; 258 | 259 | template 260 | struct is_swappable 261 | : std::integral_constant< 262 | bool, 263 | decltype(detail::swap_adl_tests::can_swap(0))::value && 264 | (!decltype( 265 | detail::swap_adl_tests::uses_std(0))::value || 266 | is_swappable::value)> {}; 267 | 268 | template 269 | struct is_nothrow_swappable 270 | : std::integral_constant< 271 | bool, 272 | is_swappable::value && 273 | ((decltype(detail::swap_adl_tests::uses_std(0))::value 274 | &&detail::swap_adl_tests::is_std_swap_noexcept::value) || 275 | (!decltype(detail::swap_adl_tests::uses_std(0))::value && 276 | detail::swap_adl_tests::is_adl_swap_noexcept::value))> { 278 | }; 279 | #endif 280 | #endif 281 | 282 | // std::void_t from C++17 283 | template struct voider { using type = void; }; 284 | template using void_t = typename voider::type; 285 | 286 | // Trait for checking if a type is a tl::optional 287 | template struct is_optional_impl : std::false_type {}; 288 | template struct is_optional_impl> : std::true_type {}; 289 | template using is_optional = is_optional_impl>; 290 | 291 | // Change void to tl::monostate 292 | template 293 | using fixup_void = conditional_t::value, monostate, U>; 294 | 295 | template > 296 | using get_map_return = optional>>; 297 | 298 | // Check if invoking F for some Us returns void 299 | template struct returns_void_impl; 300 | template 301 | struct returns_void_impl>, U...> 302 | : std::is_void> {}; 303 | template 304 | using returns_void = returns_void_impl; 305 | 306 | template 307 | using enable_if_ret_void = enable_if_t::value>; 308 | 309 | template 310 | using disable_if_ret_void = enable_if_t::value>; 311 | 312 | template 313 | using enable_forward_value = 314 | detail::enable_if_t::value && 315 | !std::is_same, in_place_t>::value && 316 | !std::is_same, detail::decay_t>::value>; 317 | 318 | template 319 | using enable_from_other = detail::enable_if_t< 320 | std::is_constructible::value && 321 | !std::is_constructible &>::value && 322 | !std::is_constructible &&>::value && 323 | !std::is_constructible &>::value && 324 | !std::is_constructible &&>::value && 325 | !std::is_convertible &, T>::value && 326 | !std::is_convertible &&, T>::value && 327 | !std::is_convertible &, T>::value && 328 | !std::is_convertible &&, T>::value>; 329 | 330 | template 331 | using enable_assign_forward = detail::enable_if_t< 332 | !std::is_same, detail::decay_t>::value && 333 | !detail::conjunction, 334 | std::is_same>>::value && 335 | std::is_constructible::value && std::is_assignable::value>; 336 | 337 | template 338 | using enable_assign_from_other = detail::enable_if_t< 339 | std::is_constructible::value && 340 | std::is_assignable::value && 341 | !std::is_constructible &>::value && 342 | !std::is_constructible &&>::value && 343 | !std::is_constructible &>::value && 344 | !std::is_constructible &&>::value && 345 | !std::is_convertible &, T>::value && 346 | !std::is_convertible &&, T>::value && 347 | !std::is_convertible &, T>::value && 348 | !std::is_convertible &&, T>::value && 349 | !std::is_assignable &>::value && 350 | !std::is_assignable &&>::value && 351 | !std::is_assignable &>::value && 352 | !std::is_assignable &&>::value>; 353 | 354 | // The storage base manages the actual storage, and correctly propagates 355 | // trivial destruction from T. This case is for when T is not trivially 356 | // destructible. 357 | template ::value> 358 | struct optional_storage_base { 359 | TL_OPTIONAL_11_CONSTEXPR optional_storage_base() noexcept 360 | : m_dummy(), m_has_value(false) {} 361 | 362 | template 363 | TL_OPTIONAL_11_CONSTEXPR optional_storage_base(in_place_t, U &&... u) 364 | : m_value(std::forward(u)...), m_has_value(true) {} 365 | 366 | ~optional_storage_base() { 367 | if (m_has_value) { 368 | m_value.~T(); 369 | m_has_value = false; 370 | } 371 | } 372 | 373 | struct dummy {}; 374 | union { 375 | dummy m_dummy; 376 | T m_value; 377 | }; 378 | 379 | bool m_has_value; 380 | }; 381 | 382 | // This case is for when T is trivially destructible. 383 | template struct optional_storage_base { 384 | TL_OPTIONAL_11_CONSTEXPR optional_storage_base() noexcept 385 | : m_dummy(), m_has_value(false) {} 386 | 387 | template 388 | TL_OPTIONAL_11_CONSTEXPR optional_storage_base(in_place_t, U &&... u) 389 | : m_value(std::forward(u)...), m_has_value(true) {} 390 | 391 | // No destructor, so this class is trivially destructible 392 | 393 | struct dummy {}; 394 | union { 395 | dummy m_dummy; 396 | T m_value; 397 | }; 398 | 399 | bool m_has_value = false; 400 | }; 401 | 402 | // This base class provides some handy member functions which can be used in 403 | // further derived classes 404 | template struct optional_operations_base : optional_storage_base { 405 | using optional_storage_base::optional_storage_base; 406 | 407 | void hard_reset() noexcept { 408 | get().~T(); 409 | this->m_has_value = false; 410 | } 411 | 412 | template void construct(Args &&... args) noexcept { 413 | new (std::addressof(this->m_value)) T(std::forward(args)...); 414 | this->m_has_value = true; 415 | } 416 | 417 | template void assign(Opt &&rhs) { 418 | if (this->has_value()) { 419 | if (rhs.has_value()) { 420 | this->m_value = std::forward(rhs).get(); 421 | } else { 422 | this->m_value.~T(); 423 | this->m_has_value = false; 424 | } 425 | } 426 | 427 | else if (rhs.has_value()) { 428 | construct(std::forward(rhs).get()); 429 | } 430 | } 431 | 432 | bool has_value() const { return this->m_has_value; } 433 | 434 | TL_OPTIONAL_11_CONSTEXPR T &get() & { return this->m_value; } 435 | TL_OPTIONAL_11_CONSTEXPR const T &get() const & { return this->m_value; } 436 | TL_OPTIONAL_11_CONSTEXPR T &&get() && { return std::move(this->m_value); } 437 | #ifndef TL_OPTIONAL_NO_CONSTRR 438 | constexpr const T &&get() const && { return std::move(this->m_value); } 439 | #endif 440 | }; 441 | 442 | // This class manages conditionally having a trivial copy constructor 443 | // This specialization is for when T is trivially copy constructible 444 | template 445 | struct optional_copy_base : optional_operations_base { 446 | using optional_operations_base::optional_operations_base; 447 | }; 448 | 449 | // This specialization is for when T is not trivially copy constructible 450 | template 451 | struct optional_copy_base : optional_operations_base { 452 | using optional_operations_base::optional_operations_base; 453 | 454 | optional_copy_base() = default; 455 | optional_copy_base(const optional_copy_base &rhs) { 456 | if (rhs.has_value()) { 457 | this->construct(rhs.get()); 458 | } else { 459 | this->m_has_value = false; 460 | } 461 | } 462 | 463 | optional_copy_base(optional_copy_base &&rhs) = default; 464 | optional_copy_base &operator=(const optional_copy_base &rhs) = default; 465 | optional_copy_base &operator=(optional_copy_base &&rhs) = default; 466 | }; 467 | 468 | // This class manages conditionally having a trivial move constructor 469 | // Unfortunately there's no way to achieve this in GCC < 5 AFAIK, since it 470 | // doesn't implement an analogue to std::is_trivially_move_constructible. We 471 | // have to make do with a non-trivial move constructor even if T is trivially 472 | // move constructible 473 | #ifndef TL_OPTIONAL_GCC49 474 | template ::value> 475 | struct optional_move_base : optional_copy_base { 476 | using optional_copy_base::optional_copy_base; 477 | }; 478 | #else 479 | template struct optional_move_base; 480 | #endif 481 | template struct optional_move_base : optional_copy_base { 482 | using optional_copy_base::optional_copy_base; 483 | 484 | optional_move_base() = default; 485 | optional_move_base(const optional_move_base &rhs) = default; 486 | 487 | optional_move_base(optional_move_base &&rhs) noexcept( 488 | std::is_nothrow_move_constructible::value) { 489 | if (rhs.has_value()) { 490 | this->construct(std::move(rhs.get())); 491 | } else { 492 | this->m_has_value = false; 493 | } 494 | } 495 | optional_move_base &operator=(const optional_move_base &rhs) = default; 496 | optional_move_base &operator=(optional_move_base &&rhs) = default; 497 | }; 498 | 499 | // This class manages conditionally having a trivial copy assignment operator 500 | template 503 | struct optional_copy_assign_base : optional_move_base { 504 | using optional_move_base::optional_move_base; 505 | }; 506 | 507 | template 508 | struct optional_copy_assign_base : optional_move_base { 509 | using optional_move_base::optional_move_base; 510 | 511 | optional_copy_assign_base() = default; 512 | optional_copy_assign_base(const optional_copy_assign_base &rhs) = default; 513 | 514 | optional_copy_assign_base(optional_copy_assign_base &&rhs) = default; 515 | optional_copy_assign_base &operator=(const optional_copy_assign_base &rhs) { 516 | this->assign(rhs); 517 | return *this; 518 | } 519 | optional_copy_assign_base & 520 | operator=(optional_copy_assign_base &&rhs) = default; 521 | }; 522 | 523 | // This class manages conditionally having a trivial move assignment operator 524 | // Unfortunately there's no way to achieve this in GCC < 5 AFAIK, since it 525 | // doesn't implement an analogue to std::is_trivially_move_assignable. We have 526 | // to make do with a non-trivial move assignment operator even if T is trivially 527 | // move assignable 528 | #ifndef TL_OPTIONAL_GCC49 529 | template ::value 530 | &&std::is_trivially_move_constructible::value 531 | &&std::is_trivially_move_assignable::value> 532 | struct optional_move_assign_base : optional_copy_assign_base { 533 | using optional_copy_assign_base::optional_copy_assign_base; 534 | }; 535 | #else 536 | template struct optional_move_assign_base; 537 | #endif 538 | 539 | template 540 | struct optional_move_assign_base : optional_copy_assign_base { 541 | using optional_copy_assign_base::optional_copy_assign_base; 542 | 543 | optional_move_assign_base() = default; 544 | optional_move_assign_base(const optional_move_assign_base &rhs) = default; 545 | 546 | optional_move_assign_base(optional_move_assign_base &&rhs) = default; 547 | 548 | optional_move_assign_base & 549 | operator=(const optional_move_assign_base &rhs) = default; 550 | 551 | optional_move_assign_base & 552 | operator=(optional_move_assign_base &&rhs) noexcept( 553 | std::is_nothrow_move_constructible::value 554 | &&std::is_nothrow_move_assignable::value) { 555 | this->assign(std::move(rhs)); 556 | return *this; 557 | } 558 | }; 559 | 560 | // optional_delete_ctor_base will conditionally delete copy and move 561 | // constructors depending on whether T is copy/move constructible 562 | template ::value, 563 | bool EnableMove = std::is_move_constructible::value> 564 | struct optional_delete_ctor_base { 565 | optional_delete_ctor_base() = default; 566 | optional_delete_ctor_base(const optional_delete_ctor_base &) = default; 567 | optional_delete_ctor_base(optional_delete_ctor_base &&) noexcept = default; 568 | optional_delete_ctor_base & 569 | operator=(const optional_delete_ctor_base &) = default; 570 | optional_delete_ctor_base & 571 | operator=(optional_delete_ctor_base &&) noexcept = default; 572 | }; 573 | 574 | template struct optional_delete_ctor_base { 575 | optional_delete_ctor_base() = default; 576 | optional_delete_ctor_base(const optional_delete_ctor_base &) = default; 577 | optional_delete_ctor_base(optional_delete_ctor_base &&) noexcept = delete; 578 | optional_delete_ctor_base & 579 | operator=(const optional_delete_ctor_base &) = default; 580 | optional_delete_ctor_base & 581 | operator=(optional_delete_ctor_base &&) noexcept = default; 582 | }; 583 | 584 | template struct optional_delete_ctor_base { 585 | optional_delete_ctor_base() = default; 586 | optional_delete_ctor_base(const optional_delete_ctor_base &) = delete; 587 | optional_delete_ctor_base(optional_delete_ctor_base &&) noexcept = default; 588 | optional_delete_ctor_base & 589 | operator=(const optional_delete_ctor_base &) = default; 590 | optional_delete_ctor_base & 591 | operator=(optional_delete_ctor_base &&) noexcept = default; 592 | }; 593 | 594 | template struct optional_delete_ctor_base { 595 | optional_delete_ctor_base() = default; 596 | optional_delete_ctor_base(const optional_delete_ctor_base &) = delete; 597 | optional_delete_ctor_base(optional_delete_ctor_base &&) noexcept = delete; 598 | optional_delete_ctor_base & 599 | operator=(const optional_delete_ctor_base &) = default; 600 | optional_delete_ctor_base & 601 | operator=(optional_delete_ctor_base &&) noexcept = default; 602 | }; 603 | 604 | // optional_delete_assign_base will conditionally delete copy and move 605 | // constructors depending on whether T is copy/move constructible + assignable 606 | template ::value && 608 | std::is_copy_assignable::value), 609 | bool EnableMove = (std::is_move_constructible::value && 610 | std::is_move_assignable::value)> 611 | struct optional_delete_assign_base { 612 | optional_delete_assign_base() = default; 613 | optional_delete_assign_base(const optional_delete_assign_base &) = default; 614 | optional_delete_assign_base(optional_delete_assign_base &&) noexcept = 615 | default; 616 | optional_delete_assign_base & 617 | operator=(const optional_delete_assign_base &) = default; 618 | optional_delete_assign_base & 619 | operator=(optional_delete_assign_base &&) noexcept = default; 620 | }; 621 | 622 | template struct optional_delete_assign_base { 623 | optional_delete_assign_base() = default; 624 | optional_delete_assign_base(const optional_delete_assign_base &) = default; 625 | optional_delete_assign_base(optional_delete_assign_base &&) noexcept = 626 | default; 627 | optional_delete_assign_base & 628 | operator=(const optional_delete_assign_base &) = default; 629 | optional_delete_assign_base & 630 | operator=(optional_delete_assign_base &&) noexcept = delete; 631 | }; 632 | 633 | template struct optional_delete_assign_base { 634 | optional_delete_assign_base() = default; 635 | optional_delete_assign_base(const optional_delete_assign_base &) = default; 636 | optional_delete_assign_base(optional_delete_assign_base &&) noexcept = 637 | default; 638 | optional_delete_assign_base & 639 | operator=(const optional_delete_assign_base &) = delete; 640 | optional_delete_assign_base & 641 | operator=(optional_delete_assign_base &&) noexcept = default; 642 | }; 643 | 644 | template struct optional_delete_assign_base { 645 | optional_delete_assign_base() = default; 646 | optional_delete_assign_base(const optional_delete_assign_base &) = default; 647 | optional_delete_assign_base(optional_delete_assign_base &&) noexcept = 648 | default; 649 | optional_delete_assign_base & 650 | operator=(const optional_delete_assign_base &) = delete; 651 | optional_delete_assign_base & 652 | operator=(optional_delete_assign_base &&) noexcept = delete; 653 | }; 654 | 655 | } // namespace detail 656 | 657 | /// A tag type to represent an empty optional 658 | struct nullopt_t { 659 | struct do_not_use {}; 660 | constexpr explicit nullopt_t(do_not_use, do_not_use) noexcept {} 661 | }; 662 | /// Represents an empty optional 663 | static constexpr nullopt_t nullopt{nullopt_t::do_not_use{}, 664 | nullopt_t::do_not_use{}}; 665 | 666 | class bad_optional_access : public std::exception { 667 | public: 668 | bad_optional_access() = default; 669 | const char *what() const noexcept { return "Optional has no value"; } 670 | }; 671 | 672 | /// An optional object is an object that contains the storage for another 673 | /// object and manages the lifetime of this contained object, if any. The 674 | /// contained object may be initialized after the optional object has been 675 | /// initialized, and may be destroyed before the optional object has been 676 | /// destroyed. The initialization state of the contained object is tracked by 677 | /// the optional object. 678 | template 679 | class optional : private detail::optional_move_assign_base, 680 | private detail::optional_delete_ctor_base, 681 | private detail::optional_delete_assign_base { 682 | using base = detail::optional_move_assign_base; 683 | 684 | static_assert(!std::is_same::value, 685 | "instantiation of optional with in_place_t is ill-formed"); 686 | static_assert(!std::is_same, nullopt_t>::value, 687 | "instantiation of optional with nullopt_t is ill-formed"); 688 | 689 | public: 690 | // The different versions for C++14 and 11 are needed because deduced return 691 | // types are not SFINAE-safe. This provides better support for things like 692 | // generic lambdas. C.f. 693 | // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0826r0.html 694 | #if defined(TL_OPTIONAL_CXX14) && !defined(TL_OPTIONAL_GCC49) && \ 695 | !defined(TL_OPTIONAL_GCC54) && !defined(TL_OPTIONAL_GCC55) 696 | /// Carries out some operation which returns an optional on the stored 697 | /// object if there is one. 698 | template TL_OPTIONAL_11_CONSTEXPR auto and_then(F &&f) & { 699 | using result = detail::invoke_result_t; 700 | static_assert(detail::is_optional::value, 701 | "F must return an optional"); 702 | 703 | return has_value() ? detail::invoke(std::forward(f), **this) 704 | : result(nullopt); 705 | } 706 | 707 | template TL_OPTIONAL_11_CONSTEXPR auto and_then(F &&f) && { 708 | using result = detail::invoke_result_t; 709 | static_assert(detail::is_optional::value, 710 | "F must return an optional"); 711 | 712 | return has_value() ? detail::invoke(std::forward(f), std::move(**this)) 713 | : result(nullopt); 714 | } 715 | 716 | template constexpr auto and_then(F &&f) const & { 717 | using result = detail::invoke_result_t; 718 | static_assert(detail::is_optional::value, 719 | "F must return an optional"); 720 | 721 | return has_value() ? detail::invoke(std::forward(f), **this) 722 | : result(nullopt); 723 | } 724 | 725 | #ifndef TL_OPTIONAL_NO_CONSTRR 726 | template constexpr auto and_then(F &&f) const && { 727 | using result = detail::invoke_result_t; 728 | static_assert(detail::is_optional::value, 729 | "F must return an optional"); 730 | 731 | return has_value() ? detail::invoke(std::forward(f), std::move(**this)) 732 | : result(nullopt); 733 | } 734 | #endif 735 | #else 736 | /// Carries out some operation which returns an optional on the stored 737 | /// object if there is one. 738 | template 739 | TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t and_then(F &&f) & { 740 | using result = detail::invoke_result_t; 741 | static_assert(detail::is_optional::value, 742 | "F must return an optional"); 743 | 744 | return has_value() ? detail::invoke(std::forward(f), **this) 745 | : result(nullopt); 746 | } 747 | 748 | template 749 | TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t and_then(F &&f) && { 750 | using result = detail::invoke_result_t; 751 | static_assert(detail::is_optional::value, 752 | "F must return an optional"); 753 | 754 | return has_value() ? detail::invoke(std::forward(f), std::move(**this)) 755 | : result(nullopt); 756 | } 757 | 758 | template 759 | constexpr detail::invoke_result_t and_then(F &&f) const & { 760 | using result = detail::invoke_result_t; 761 | static_assert(detail::is_optional::value, 762 | "F must return an optional"); 763 | 764 | return has_value() ? detail::invoke(std::forward(f), **this) 765 | : result(nullopt); 766 | } 767 | 768 | #ifndef TL_OPTIONAL_NO_CONSTRR 769 | template 770 | constexpr detail::invoke_result_t and_then(F &&f) const && { 771 | using result = detail::invoke_result_t; 772 | static_assert(detail::is_optional::value, 773 | "F must return an optional"); 774 | 775 | return has_value() ? detail::invoke(std::forward(f), std::move(**this)) 776 | : result(nullopt); 777 | } 778 | #endif 779 | #endif 780 | 781 | #if defined(TL_OPTIONAL_CXX14) && !defined(TL_OPTIONAL_GCC49) && \ 782 | !defined(TL_OPTIONAL_GCC54) && !defined(TL_OPTIONAL_GCC55) 783 | /// Carries out some operation on the stored object if there is one. 784 | template TL_OPTIONAL_11_CONSTEXPR auto map(F &&f) & { 785 | return optional_map_impl(*this, std::forward(f)); 786 | } 787 | 788 | template TL_OPTIONAL_11_CONSTEXPR auto map(F &&f) && { 789 | return optional_map_impl(std::move(*this), std::forward(f)); 790 | } 791 | 792 | template constexpr auto map(F &&f) const & { 793 | return optional_map_impl(*this, std::forward(f)); 794 | } 795 | 796 | template constexpr auto map(F &&f) const && { 797 | return optional_map_impl(std::move(*this), std::forward(f)); 798 | } 799 | #else 800 | /// Carries out some operation on the stored object if there is one. 801 | template 802 | TL_OPTIONAL_11_CONSTEXPR decltype(optional_map_impl(std::declval(), 803 | std::declval())) 804 | map(F &&f) & { 805 | return optional_map_impl(*this, std::forward(f)); 806 | } 807 | 808 | template 809 | TL_OPTIONAL_11_CONSTEXPR decltype(optional_map_impl(std::declval(), 810 | std::declval())) 811 | map(F &&f) && { 812 | return optional_map_impl(std::move(*this), std::forward(f)); 813 | } 814 | 815 | template 816 | constexpr decltype(optional_map_impl(std::declval(), 817 | std::declval())) 818 | map(F &&f) const & { 819 | return optional_map_impl(*this, std::forward(f)); 820 | } 821 | 822 | #ifndef TL_OPTIONAL_NO_CONSTRR 823 | template 824 | constexpr decltype(optional_map_impl(std::declval(), 825 | std::declval())) 826 | map(F &&f) const && { 827 | return optional_map_impl(std::move(*this), std::forward(f)); 828 | } 829 | #endif 830 | #endif 831 | 832 | #if defined(TL_OPTIONAL_CXX14) && !defined(TL_OPTIONAL_GCC49) && \ 833 | !defined(TL_OPTIONAL_GCC54) && !defined(TL_OPTIONAL_GCC55) 834 | /// Carries out some operation on the stored object if there is one. 835 | template TL_OPTIONAL_11_CONSTEXPR auto transform(F&& f) & { 836 | return optional_map_impl(*this, std::forward(f)); 837 | } 838 | 839 | template TL_OPTIONAL_11_CONSTEXPR auto transform(F&& f) && { 840 | return optional_map_impl(std::move(*this), std::forward(f)); 841 | } 842 | 843 | template constexpr auto transform(F&& f) const & { 844 | return optional_map_impl(*this, std::forward(f)); 845 | } 846 | 847 | template constexpr auto transform(F&& f) const && { 848 | return optional_map_impl(std::move(*this), std::forward(f)); 849 | } 850 | #else 851 | /// Carries out some operation on the stored object if there is one. 852 | template 853 | TL_OPTIONAL_11_CONSTEXPR decltype(optional_map_impl(std::declval(), 854 | std::declval())) 855 | transform(F&& f) & { 856 | return optional_map_impl(*this, std::forward(f)); 857 | } 858 | 859 | template 860 | TL_OPTIONAL_11_CONSTEXPR decltype(optional_map_impl(std::declval(), 861 | std::declval())) 862 | transform(F&& f) && { 863 | return optional_map_impl(std::move(*this), std::forward(f)); 864 | } 865 | 866 | template 867 | constexpr decltype(optional_map_impl(std::declval(), 868 | std::declval())) 869 | transform(F&& f) const & { 870 | return optional_map_impl(*this, std::forward(f)); 871 | } 872 | 873 | #ifndef TL_OPTIONAL_NO_CONSTRR 874 | template 875 | constexpr decltype(optional_map_impl(std::declval(), 876 | std::declval())) 877 | transform(F&& f) const && { 878 | return optional_map_impl(std::move(*this), std::forward(f)); 879 | } 880 | #endif 881 | #endif 882 | 883 | /// Calls `f` if the optional is empty 884 | template * = nullptr> 885 | optional TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) & { 886 | if (has_value()) 887 | return *this; 888 | 889 | std::forward(f)(); 890 | return nullopt; 891 | } 892 | 893 | template * = nullptr> 894 | optional TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) & { 895 | return has_value() ? *this : std::forward(f)(); 896 | } 897 | 898 | template * = nullptr> 899 | optional or_else(F &&f) && { 900 | if (has_value()) 901 | return std::move(*this); 902 | 903 | std::forward(f)(); 904 | return nullopt; 905 | } 906 | 907 | template * = nullptr> 908 | optional TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) && { 909 | return has_value() ? std::move(*this) : std::forward(f)(); 910 | } 911 | 912 | template * = nullptr> 913 | optional or_else(F &&f) const & { 914 | if (has_value()) 915 | return *this; 916 | 917 | std::forward(f)(); 918 | return nullopt; 919 | } 920 | 921 | template * = nullptr> 922 | optional TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) const & { 923 | return has_value() ? *this : std::forward(f)(); 924 | } 925 | 926 | #ifndef TL_OPTIONAL_NO_CONSTRR 927 | template * = nullptr> 928 | optional or_else(F &&f) const && { 929 | if (has_value()) 930 | return std::move(*this); 931 | 932 | std::forward(f)(); 933 | return nullopt; 934 | } 935 | 936 | template * = nullptr> 937 | optional or_else(F &&f) const && { 938 | return has_value() ? std::move(*this) : std::forward(f)(); 939 | } 940 | #endif 941 | 942 | /// Maps the stored value with `f` if there is one, otherwise returns `u`. 943 | template U map_or(F &&f, U &&u) & { 944 | return has_value() ? detail::invoke(std::forward(f), **this) 945 | : std::forward(u); 946 | } 947 | 948 | template U map_or(F &&f, U &&u) && { 949 | return has_value() ? detail::invoke(std::forward(f), std::move(**this)) 950 | : std::forward(u); 951 | } 952 | 953 | template U map_or(F &&f, U &&u) const & { 954 | return has_value() ? detail::invoke(std::forward(f), **this) 955 | : std::forward(u); 956 | } 957 | 958 | #ifndef TL_OPTIONAL_NO_CONSTRR 959 | template U map_or(F &&f, U &&u) const && { 960 | return has_value() ? detail::invoke(std::forward(f), std::move(**this)) 961 | : std::forward(u); 962 | } 963 | #endif 964 | 965 | /// Maps the stored value with `f` if there is one, otherwise calls 966 | /// `u` and returns the result. 967 | template 968 | detail::invoke_result_t map_or_else(F &&f, U &&u) & { 969 | return has_value() ? detail::invoke(std::forward(f), **this) 970 | : std::forward(u)(); 971 | } 972 | 973 | template 974 | detail::invoke_result_t map_or_else(F &&f, U &&u) && { 975 | return has_value() ? detail::invoke(std::forward(f), std::move(**this)) 976 | : std::forward(u)(); 977 | } 978 | 979 | template 980 | detail::invoke_result_t map_or_else(F &&f, U &&u) const & { 981 | return has_value() ? detail::invoke(std::forward(f), **this) 982 | : std::forward(u)(); 983 | } 984 | 985 | #ifndef TL_OPTIONAL_NO_CONSTRR 986 | template 987 | detail::invoke_result_t map_or_else(F &&f, U &&u) const && { 988 | return has_value() ? detail::invoke(std::forward(f), std::move(**this)) 989 | : std::forward(u)(); 990 | } 991 | #endif 992 | 993 | /// Returns `u` if `*this` has a value, otherwise an empty optional. 994 | template 995 | constexpr optional::type> conjunction(U &&u) const { 996 | using result = optional>; 997 | return has_value() ? result{u} : result{nullopt}; 998 | } 999 | 1000 | /// Returns `rhs` if `*this` is empty, otherwise the current value. 1001 | TL_OPTIONAL_11_CONSTEXPR optional disjunction(const optional &rhs) & { 1002 | return has_value() ? *this : rhs; 1003 | } 1004 | 1005 | constexpr optional disjunction(const optional &rhs) const & { 1006 | return has_value() ? *this : rhs; 1007 | } 1008 | 1009 | TL_OPTIONAL_11_CONSTEXPR optional disjunction(const optional &rhs) && { 1010 | return has_value() ? std::move(*this) : rhs; 1011 | } 1012 | 1013 | #ifndef TL_OPTIONAL_NO_CONSTRR 1014 | constexpr optional disjunction(const optional &rhs) const && { 1015 | return has_value() ? std::move(*this) : rhs; 1016 | } 1017 | #endif 1018 | 1019 | TL_OPTIONAL_11_CONSTEXPR optional disjunction(optional &&rhs) & { 1020 | return has_value() ? *this : std::move(rhs); 1021 | } 1022 | 1023 | constexpr optional disjunction(optional &&rhs) const & { 1024 | return has_value() ? *this : std::move(rhs); 1025 | } 1026 | 1027 | TL_OPTIONAL_11_CONSTEXPR optional disjunction(optional &&rhs) && { 1028 | return has_value() ? std::move(*this) : std::move(rhs); 1029 | } 1030 | 1031 | #ifndef TL_OPTIONAL_NO_CONSTRR 1032 | constexpr optional disjunction(optional &&rhs) const && { 1033 | return has_value() ? std::move(*this) : std::move(rhs); 1034 | } 1035 | #endif 1036 | 1037 | /// Takes the value out of the optional, leaving it empty 1038 | optional take() { 1039 | optional ret = std::move(*this); 1040 | reset(); 1041 | return ret; 1042 | } 1043 | 1044 | using value_type = T; 1045 | 1046 | /// Constructs an optional that does not contain a value. 1047 | constexpr optional() noexcept = default; 1048 | 1049 | constexpr optional(nullopt_t) noexcept {} 1050 | 1051 | /// Copy constructor 1052 | /// 1053 | /// If `rhs` contains a value, the stored value is direct-initialized with 1054 | /// it. Otherwise, the constructed optional is empty. 1055 | TL_OPTIONAL_11_CONSTEXPR optional(const optional &rhs) = default; 1056 | 1057 | /// Move constructor 1058 | /// 1059 | /// If `rhs` contains a value, the stored value is direct-initialized with 1060 | /// it. Otherwise, the constructed optional is empty. 1061 | TL_OPTIONAL_11_CONSTEXPR optional(optional &&rhs) = default; 1062 | 1063 | /// Constructs the stored value in-place using the given arguments. 1064 | template 1065 | constexpr explicit optional( 1066 | detail::enable_if_t::value, in_place_t>, 1067 | Args &&... args) 1068 | : base(in_place, std::forward(args)...) {} 1069 | 1070 | template 1071 | TL_OPTIONAL_11_CONSTEXPR explicit optional( 1072 | detail::enable_if_t &, 1073 | Args &&...>::value, 1074 | in_place_t>, 1075 | std::initializer_list il, Args &&... args) { 1076 | this->construct(il, std::forward(args)...); 1077 | } 1078 | 1079 | /// Constructs the stored value with `u`. 1080 | template < 1081 | class U = T, 1082 | detail::enable_if_t::value> * = nullptr, 1083 | detail::enable_forward_value * = nullptr> 1084 | constexpr optional(U &&u) : base(in_place, std::forward(u)) {} 1085 | 1086 | template < 1087 | class U = T, 1088 | detail::enable_if_t::value> * = nullptr, 1089 | detail::enable_forward_value * = nullptr> 1090 | constexpr explicit optional(U &&u) : base(in_place, std::forward(u)) {} 1091 | 1092 | /// Converting copy constructor. 1093 | template < 1094 | class U, detail::enable_from_other * = nullptr, 1095 | detail::enable_if_t::value> * = nullptr> 1096 | optional(const optional &rhs) { 1097 | if (rhs.has_value()) { 1098 | this->construct(*rhs); 1099 | } 1100 | } 1101 | 1102 | template * = nullptr, 1103 | detail::enable_if_t::value> * = 1104 | nullptr> 1105 | explicit optional(const optional &rhs) { 1106 | if (rhs.has_value()) { 1107 | this->construct(*rhs); 1108 | } 1109 | } 1110 | 1111 | /// Converting move constructor. 1112 | template < 1113 | class U, detail::enable_from_other * = nullptr, 1114 | detail::enable_if_t::value> * = nullptr> 1115 | optional(optional &&rhs) { 1116 | if (rhs.has_value()) { 1117 | this->construct(std::move(*rhs)); 1118 | } 1119 | } 1120 | 1121 | template < 1122 | class U, detail::enable_from_other * = nullptr, 1123 | detail::enable_if_t::value> * = nullptr> 1124 | explicit optional(optional &&rhs) { 1125 | if (rhs.has_value()) { 1126 | this->construct(std::move(*rhs)); 1127 | } 1128 | } 1129 | 1130 | /// Destroys the stored value if there is one. 1131 | ~optional() = default; 1132 | 1133 | /// Assignment to empty. 1134 | /// 1135 | /// Destroys the current value if there is one. 1136 | optional &operator=(nullopt_t) noexcept { 1137 | if (has_value()) { 1138 | this->m_value.~T(); 1139 | this->m_has_value = false; 1140 | } 1141 | 1142 | return *this; 1143 | } 1144 | 1145 | /// Copy assignment. 1146 | /// 1147 | /// Copies the value from `rhs` if there is one. Otherwise resets the stored 1148 | /// value in `*this`. 1149 | optional &operator=(const optional &rhs) = default; 1150 | 1151 | /// Move assignment. 1152 | /// 1153 | /// Moves the value from `rhs` if there is one. Otherwise resets the stored 1154 | /// value in `*this`. 1155 | optional &operator=(optional &&rhs) = default; 1156 | 1157 | /// Assigns the stored value from `u`, destroying the old value if there was 1158 | /// one. 1159 | template * = nullptr> 1160 | optional &operator=(U &&u) { 1161 | if (has_value()) { 1162 | this->m_value = std::forward(u); 1163 | } else { 1164 | this->construct(std::forward(u)); 1165 | } 1166 | 1167 | return *this; 1168 | } 1169 | 1170 | /// Converting copy assignment operator. 1171 | /// 1172 | /// Copies the value from `rhs` if there is one. Otherwise resets the stored 1173 | /// value in `*this`. 1174 | template * = nullptr> 1176 | optional &operator=(const optional &rhs) { 1177 | if (has_value()) { 1178 | if (rhs.has_value()) { 1179 | this->m_value = *rhs; 1180 | } else { 1181 | this->hard_reset(); 1182 | } 1183 | } 1184 | 1185 | if (rhs.has_value()) { 1186 | this->construct(*rhs); 1187 | } 1188 | 1189 | return *this; 1190 | } 1191 | 1192 | // TODO check exception guarantee 1193 | /// Converting move assignment operator. 1194 | /// 1195 | /// Moves the value from `rhs` if there is one. Otherwise resets the stored 1196 | /// value in `*this`. 1197 | template * = nullptr> 1198 | optional &operator=(optional &&rhs) { 1199 | if (has_value()) { 1200 | if (rhs.has_value()) { 1201 | this->m_value = std::move(*rhs); 1202 | } else { 1203 | this->hard_reset(); 1204 | } 1205 | } 1206 | 1207 | if (rhs.has_value()) { 1208 | this->construct(std::move(*rhs)); 1209 | } 1210 | 1211 | return *this; 1212 | } 1213 | 1214 | /// Constructs the value in-place, destroying the current one if there is 1215 | /// one. 1216 | template T &emplace(Args &&... args) { 1217 | static_assert(std::is_constructible::value, 1218 | "T must be constructible with Args"); 1219 | 1220 | *this = nullopt; 1221 | this->construct(std::forward(args)...); 1222 | return value(); 1223 | } 1224 | 1225 | template 1226 | detail::enable_if_t< 1227 | std::is_constructible &, Args &&...>::value, 1228 | T &> 1229 | emplace(std::initializer_list il, Args &&... args) { 1230 | *this = nullopt; 1231 | this->construct(il, std::forward(args)...); 1232 | return value(); 1233 | } 1234 | 1235 | /// Swaps this optional with the other. 1236 | /// 1237 | /// If neither optionals have a value, nothing happens. 1238 | /// If both have a value, the values are swapped. 1239 | /// If one has a value, it is moved to the other and the movee is left 1240 | /// valueless. 1241 | void 1242 | swap(optional &rhs) noexcept(std::is_nothrow_move_constructible::value 1243 | &&detail::is_nothrow_swappable::value) { 1244 | using std::swap; 1245 | if (has_value()) { 1246 | if (rhs.has_value()) { 1247 | swap(**this, *rhs); 1248 | } else { 1249 | new (std::addressof(rhs.m_value)) T(std::move(this->m_value)); 1250 | this->m_value.T::~T(); 1251 | } 1252 | } else if (rhs.has_value()) { 1253 | new (std::addressof(this->m_value)) T(std::move(rhs.m_value)); 1254 | rhs.m_value.T::~T(); 1255 | } 1256 | swap(this->m_has_value, rhs.m_has_value); 1257 | } 1258 | 1259 | /// Returns a pointer to the stored value 1260 | constexpr const T *operator->() const { 1261 | return std::addressof(this->m_value); 1262 | } 1263 | 1264 | TL_OPTIONAL_11_CONSTEXPR T *operator->() { 1265 | return std::addressof(this->m_value); 1266 | } 1267 | 1268 | /// Returns the stored value 1269 | TL_OPTIONAL_11_CONSTEXPR T &operator*() & { return this->m_value; } 1270 | 1271 | constexpr const T &operator*() const & { return this->m_value; } 1272 | 1273 | TL_OPTIONAL_11_CONSTEXPR T &&operator*() && { 1274 | return std::move(this->m_value); 1275 | } 1276 | 1277 | #ifndef TL_OPTIONAL_NO_CONSTRR 1278 | constexpr const T &&operator*() const && { return std::move(this->m_value); } 1279 | #endif 1280 | 1281 | /// Returns whether or not the optional has a value 1282 | constexpr bool has_value() const noexcept { return this->m_has_value; } 1283 | 1284 | constexpr explicit operator bool() const noexcept { 1285 | return this->m_has_value; 1286 | } 1287 | 1288 | /// Returns the contained value if there is one, otherwise throws bad_optional_access 1289 | TL_OPTIONAL_11_CONSTEXPR T &value() & { 1290 | if (has_value()) 1291 | return this->m_value; 1292 | throw bad_optional_access(); 1293 | } 1294 | TL_OPTIONAL_11_CONSTEXPR const T &value() const & { 1295 | if (has_value()) 1296 | return this->m_value; 1297 | throw bad_optional_access(); 1298 | } 1299 | TL_OPTIONAL_11_CONSTEXPR T &&value() && { 1300 | if (has_value()) 1301 | return std::move(this->m_value); 1302 | throw bad_optional_access(); 1303 | } 1304 | 1305 | #ifndef TL_OPTIONAL_NO_CONSTRR 1306 | TL_OPTIONAL_11_CONSTEXPR const T &&value() const && { 1307 | if (has_value()) 1308 | return std::move(this->m_value); 1309 | throw bad_optional_access(); 1310 | } 1311 | #endif 1312 | 1313 | /// Returns the stored value if there is one, otherwise returns `u` 1314 | template constexpr T value_or(U &&u) const & { 1315 | static_assert(std::is_copy_constructible::value && 1316 | std::is_convertible::value, 1317 | "T must be copy constructible and convertible from U"); 1318 | return has_value() ? **this : static_cast(std::forward(u)); 1319 | } 1320 | 1321 | template TL_OPTIONAL_11_CONSTEXPR T value_or(U &&u) && { 1322 | static_assert(std::is_move_constructible::value && 1323 | std::is_convertible::value, 1324 | "T must be move constructible and convertible from U"); 1325 | return has_value() ? **this : static_cast(std::forward(u)); 1326 | } 1327 | 1328 | /// Destroys the stored value if one exists, making the optional empty 1329 | void reset() noexcept { 1330 | if (has_value()) { 1331 | this->m_value.~T(); 1332 | this->m_has_value = false; 1333 | } 1334 | } 1335 | }; // namespace tl 1336 | 1337 | /// Compares two optional objects 1338 | template 1339 | inline constexpr bool operator==(const optional &lhs, 1340 | const optional &rhs) { 1341 | return lhs.has_value() == rhs.has_value() && 1342 | (!lhs.has_value() || *lhs == *rhs); 1343 | } 1344 | template 1345 | inline constexpr bool operator!=(const optional &lhs, 1346 | const optional &rhs) { 1347 | return lhs.has_value() != rhs.has_value() || 1348 | (lhs.has_value() && *lhs != *rhs); 1349 | } 1350 | template 1351 | inline constexpr bool operator<(const optional &lhs, 1352 | const optional &rhs) { 1353 | return rhs.has_value() && (!lhs.has_value() || *lhs < *rhs); 1354 | } 1355 | template 1356 | inline constexpr bool operator>(const optional &lhs, 1357 | const optional &rhs) { 1358 | return lhs.has_value() && (!rhs.has_value() || *lhs > *rhs); 1359 | } 1360 | template 1361 | inline constexpr bool operator<=(const optional &lhs, 1362 | const optional &rhs) { 1363 | return !lhs.has_value() || (rhs.has_value() && *lhs <= *rhs); 1364 | } 1365 | template 1366 | inline constexpr bool operator>=(const optional &lhs, 1367 | const optional &rhs) { 1368 | return !rhs.has_value() || (lhs.has_value() && *lhs >= *rhs); 1369 | } 1370 | 1371 | /// Compares an optional to a `nullopt` 1372 | template 1373 | inline constexpr bool operator==(const optional &lhs, nullopt_t) noexcept { 1374 | return !lhs.has_value(); 1375 | } 1376 | template 1377 | inline constexpr bool operator==(nullopt_t, const optional &rhs) noexcept { 1378 | return !rhs.has_value(); 1379 | } 1380 | template 1381 | inline constexpr bool operator!=(const optional &lhs, nullopt_t) noexcept { 1382 | return lhs.has_value(); 1383 | } 1384 | template 1385 | inline constexpr bool operator!=(nullopt_t, const optional &rhs) noexcept { 1386 | return rhs.has_value(); 1387 | } 1388 | template 1389 | inline constexpr bool operator<(const optional &, nullopt_t) noexcept { 1390 | return false; 1391 | } 1392 | template 1393 | inline constexpr bool operator<(nullopt_t, const optional &rhs) noexcept { 1394 | return rhs.has_value(); 1395 | } 1396 | template 1397 | inline constexpr bool operator<=(const optional &lhs, nullopt_t) noexcept { 1398 | return !lhs.has_value(); 1399 | } 1400 | template 1401 | inline constexpr bool operator<=(nullopt_t, const optional &) noexcept { 1402 | return true; 1403 | } 1404 | template 1405 | inline constexpr bool operator>(const optional &lhs, nullopt_t) noexcept { 1406 | return lhs.has_value(); 1407 | } 1408 | template 1409 | inline constexpr bool operator>(nullopt_t, const optional &) noexcept { 1410 | return false; 1411 | } 1412 | template 1413 | inline constexpr bool operator>=(const optional &, nullopt_t) noexcept { 1414 | return true; 1415 | } 1416 | template 1417 | inline constexpr bool operator>=(nullopt_t, const optional &rhs) noexcept { 1418 | return !rhs.has_value(); 1419 | } 1420 | 1421 | /// Compares the optional with a value. 1422 | template 1423 | inline constexpr bool operator==(const optional &lhs, const U &rhs) { 1424 | return lhs.has_value() ? *lhs == rhs : false; 1425 | } 1426 | template 1427 | inline constexpr bool operator==(const U &lhs, const optional &rhs) { 1428 | return rhs.has_value() ? lhs == *rhs : false; 1429 | } 1430 | template 1431 | inline constexpr bool operator!=(const optional &lhs, const U &rhs) { 1432 | return lhs.has_value() ? *lhs != rhs : true; 1433 | } 1434 | template 1435 | inline constexpr bool operator!=(const U &lhs, const optional &rhs) { 1436 | return rhs.has_value() ? lhs != *rhs : true; 1437 | } 1438 | template 1439 | inline constexpr bool operator<(const optional &lhs, const U &rhs) { 1440 | return lhs.has_value() ? *lhs < rhs : true; 1441 | } 1442 | template 1443 | inline constexpr bool operator<(const U &lhs, const optional &rhs) { 1444 | return rhs.has_value() ? lhs < *rhs : false; 1445 | } 1446 | template 1447 | inline constexpr bool operator<=(const optional &lhs, const U &rhs) { 1448 | return lhs.has_value() ? *lhs <= rhs : true; 1449 | } 1450 | template 1451 | inline constexpr bool operator<=(const U &lhs, const optional &rhs) { 1452 | return rhs.has_value() ? lhs <= *rhs : false; 1453 | } 1454 | template 1455 | inline constexpr bool operator>(const optional &lhs, const U &rhs) { 1456 | return lhs.has_value() ? *lhs > rhs : false; 1457 | } 1458 | template 1459 | inline constexpr bool operator>(const U &lhs, const optional &rhs) { 1460 | return rhs.has_value() ? lhs > *rhs : true; 1461 | } 1462 | template 1463 | inline constexpr bool operator>=(const optional &lhs, const U &rhs) { 1464 | return lhs.has_value() ? *lhs >= rhs : false; 1465 | } 1466 | template 1467 | inline constexpr bool operator>=(const U &lhs, const optional &rhs) { 1468 | return rhs.has_value() ? lhs >= *rhs : true; 1469 | } 1470 | 1471 | template ::value> * = nullptr, 1473 | detail::enable_if_t::value> * = nullptr> 1474 | void swap(optional &lhs, 1475 | optional &rhs) noexcept(noexcept(lhs.swap(rhs))) { 1476 | return lhs.swap(rhs); 1477 | } 1478 | 1479 | namespace detail { 1480 | struct i_am_secret {}; 1481 | } // namespace detail 1482 | 1483 | template ::value, 1486 | detail::decay_t, T>> 1487 | inline constexpr optional make_optional(U &&v) { 1488 | return optional(std::forward(v)); 1489 | } 1490 | 1491 | template 1492 | inline constexpr optional make_optional(Args &&... args) { 1493 | return optional(in_place, std::forward(args)...); 1494 | } 1495 | template 1496 | inline constexpr optional make_optional(std::initializer_list il, 1497 | Args &&... args) { 1498 | return optional(in_place, il, std::forward(args)...); 1499 | } 1500 | 1501 | #if __cplusplus >= 201703L 1502 | template optional(T)->optional; 1503 | #endif 1504 | 1505 | /// \exclude 1506 | namespace detail { 1507 | #ifdef TL_OPTIONAL_CXX14 1508 | template (), 1510 | *std::declval())), 1511 | detail::enable_if_t::value> * = nullptr> 1512 | constexpr auto optional_map_impl(Opt &&opt, F &&f) { 1513 | return opt.has_value() 1514 | ? detail::invoke(std::forward(f), *std::forward(opt)) 1515 | : optional(nullopt); 1516 | } 1517 | 1518 | template (), 1520 | *std::declval())), 1521 | detail::enable_if_t::value> * = nullptr> 1522 | auto optional_map_impl(Opt &&opt, F &&f) { 1523 | if (opt.has_value()) { 1524 | detail::invoke(std::forward(f), *std::forward(opt)); 1525 | return make_optional(monostate{}); 1526 | } 1527 | 1528 | return optional(nullopt); 1529 | } 1530 | #else 1531 | template (), 1533 | *std::declval())), 1534 | detail::enable_if_t::value> * = nullptr> 1535 | 1536 | constexpr auto optional_map_impl(Opt &&opt, F &&f) -> optional { 1537 | return opt.has_value() 1538 | ? detail::invoke(std::forward(f), *std::forward(opt)) 1539 | : optional(nullopt); 1540 | } 1541 | 1542 | template (), 1544 | *std::declval())), 1545 | detail::enable_if_t::value> * = nullptr> 1546 | 1547 | auto optional_map_impl(Opt &&opt, F &&f) -> optional { 1548 | if (opt.has_value()) { 1549 | detail::invoke(std::forward(f), *std::forward(opt)); 1550 | return monostate{}; 1551 | } 1552 | 1553 | return nullopt; 1554 | } 1555 | #endif 1556 | } // namespace detail 1557 | 1558 | /// Specialization for when `T` is a reference. `optional` acts similarly 1559 | /// to a `T*`, but provides more operations and shows intent more clearly. 1560 | template class optional { 1561 | public: 1562 | // The different versions for C++14 and 11 are needed because deduced return 1563 | // types are not SFINAE-safe. This provides better support for things like 1564 | // generic lambdas. C.f. 1565 | // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0826r0.html 1566 | #if defined(TL_OPTIONAL_CXX14) && !defined(TL_OPTIONAL_GCC49) && \ 1567 | !defined(TL_OPTIONAL_GCC54) && !defined(TL_OPTIONAL_GCC55) 1568 | 1569 | /// Carries out some operation which returns an optional on the stored 1570 | /// object if there is one. 1571 | template TL_OPTIONAL_11_CONSTEXPR auto and_then(F &&f) & { 1572 | using result = detail::invoke_result_t; 1573 | static_assert(detail::is_optional::value, 1574 | "F must return an optional"); 1575 | 1576 | return has_value() ? detail::invoke(std::forward(f), **this) 1577 | : result(nullopt); 1578 | } 1579 | 1580 | template TL_OPTIONAL_11_CONSTEXPR auto and_then(F &&f) && { 1581 | using result = detail::invoke_result_t; 1582 | static_assert(detail::is_optional::value, 1583 | "F must return an optional"); 1584 | 1585 | return has_value() ? detail::invoke(std::forward(f), **this) 1586 | : result(nullopt); 1587 | } 1588 | 1589 | template constexpr auto and_then(F &&f) const & { 1590 | using result = detail::invoke_result_t; 1591 | static_assert(detail::is_optional::value, 1592 | "F must return an optional"); 1593 | 1594 | return has_value() ? detail::invoke(std::forward(f), **this) 1595 | : result(nullopt); 1596 | } 1597 | 1598 | #ifndef TL_OPTIONAL_NO_CONSTRR 1599 | template constexpr auto and_then(F &&f) const && { 1600 | using result = detail::invoke_result_t; 1601 | static_assert(detail::is_optional::value, 1602 | "F must return an optional"); 1603 | 1604 | return has_value() ? detail::invoke(std::forward(f), **this) 1605 | : result(nullopt); 1606 | } 1607 | #endif 1608 | #else 1609 | /// Carries out some operation which returns an optional on the stored 1610 | /// object if there is one. 1611 | template 1612 | TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t and_then(F &&f) & { 1613 | using result = detail::invoke_result_t; 1614 | static_assert(detail::is_optional::value, 1615 | "F must return an optional"); 1616 | 1617 | return has_value() ? detail::invoke(std::forward(f), **this) 1618 | : result(nullopt); 1619 | } 1620 | 1621 | template 1622 | TL_OPTIONAL_11_CONSTEXPR detail::invoke_result_t and_then(F &&f) && { 1623 | using result = detail::invoke_result_t; 1624 | static_assert(detail::is_optional::value, 1625 | "F must return an optional"); 1626 | 1627 | return has_value() ? detail::invoke(std::forward(f), **this) 1628 | : result(nullopt); 1629 | } 1630 | 1631 | template 1632 | constexpr detail::invoke_result_t and_then(F &&f) const & { 1633 | using result = detail::invoke_result_t; 1634 | static_assert(detail::is_optional::value, 1635 | "F must return an optional"); 1636 | 1637 | return has_value() ? detail::invoke(std::forward(f), **this) 1638 | : result(nullopt); 1639 | } 1640 | 1641 | #ifndef TL_OPTIONAL_NO_CONSTRR 1642 | template 1643 | constexpr detail::invoke_result_t and_then(F &&f) const && { 1644 | using result = detail::invoke_result_t; 1645 | static_assert(detail::is_optional::value, 1646 | "F must return an optional"); 1647 | 1648 | return has_value() ? detail::invoke(std::forward(f), **this) 1649 | : result(nullopt); 1650 | } 1651 | #endif 1652 | #endif 1653 | 1654 | #if defined(TL_OPTIONAL_CXX14) && !defined(TL_OPTIONAL_GCC49) && \ 1655 | !defined(TL_OPTIONAL_GCC54) && !defined(TL_OPTIONAL_GCC55) 1656 | /// Carries out some operation on the stored object if there is one. 1657 | template TL_OPTIONAL_11_CONSTEXPR auto map(F &&f) & { 1658 | return detail::optional_map_impl(*this, std::forward(f)); 1659 | } 1660 | 1661 | template TL_OPTIONAL_11_CONSTEXPR auto map(F &&f) && { 1662 | return detail::optional_map_impl(std::move(*this), std::forward(f)); 1663 | } 1664 | 1665 | template constexpr auto map(F &&f) const & { 1666 | return detail::optional_map_impl(*this, std::forward(f)); 1667 | } 1668 | 1669 | template constexpr auto map(F &&f) const && { 1670 | return detail::optional_map_impl(std::move(*this), std::forward(f)); 1671 | } 1672 | #else 1673 | /// Carries out some operation on the stored object if there is one. 1674 | template 1675 | TL_OPTIONAL_11_CONSTEXPR decltype(detail::optional_map_impl(std::declval(), 1676 | std::declval())) 1677 | map(F &&f) & { 1678 | return detail::optional_map_impl(*this, std::forward(f)); 1679 | } 1680 | 1681 | template 1682 | TL_OPTIONAL_11_CONSTEXPR decltype(detail::optional_map_impl(std::declval(), 1683 | std::declval())) 1684 | map(F &&f) && { 1685 | return detail::optional_map_impl(std::move(*this), std::forward(f)); 1686 | } 1687 | 1688 | template 1689 | constexpr decltype(detail::optional_map_impl(std::declval(), 1690 | std::declval())) 1691 | map(F &&f) const & { 1692 | return detail::optional_map_impl(*this, std::forward(f)); 1693 | } 1694 | 1695 | #ifndef TL_OPTIONAL_NO_CONSTRR 1696 | template 1697 | constexpr decltype(detail::optional_map_impl(std::declval(), 1698 | std::declval())) 1699 | map(F &&f) const && { 1700 | return detail::optional_map_impl(std::move(*this), std::forward(f)); 1701 | } 1702 | #endif 1703 | #endif 1704 | 1705 | #if defined(TL_OPTIONAL_CXX14) && !defined(TL_OPTIONAL_GCC49) && \ 1706 | !defined(TL_OPTIONAL_GCC54) && !defined(TL_OPTIONAL_GCC55) 1707 | /// Carries out some operation on the stored object if there is one. 1708 | template TL_OPTIONAL_11_CONSTEXPR auto transform(F&& f) & { 1709 | return detail::optional_map_impl(*this, std::forward(f)); 1710 | } 1711 | 1712 | template TL_OPTIONAL_11_CONSTEXPR auto transform(F&& f) && { 1713 | return detail::optional_map_impl(std::move(*this), std::forward(f)); 1714 | } 1715 | 1716 | template constexpr auto transform(F&& f) const & { 1717 | return detail::optional_map_impl(*this, std::forward(f)); 1718 | } 1719 | 1720 | template constexpr auto transform(F&& f) const && { 1721 | return detail::optional_map_impl(std::move(*this), std::forward(f)); 1722 | } 1723 | #else 1724 | /// Carries out some operation on the stored object if there is one. 1725 | template 1726 | TL_OPTIONAL_11_CONSTEXPR decltype(detail::optional_map_impl(std::declval(), 1727 | std::declval())) 1728 | transform(F&& f) & { 1729 | return detail::optional_map_impl(*this, std::forward(f)); 1730 | } 1731 | 1732 | /// \group map 1733 | /// \synopsis template auto transform(F &&f) &&; 1734 | template 1735 | TL_OPTIONAL_11_CONSTEXPR decltype(detail::optional_map_impl(std::declval(), 1736 | std::declval())) 1737 | transform(F&& f) && { 1738 | return detail::optional_map_impl(std::move(*this), std::forward(f)); 1739 | } 1740 | 1741 | template 1742 | constexpr decltype(detail::optional_map_impl(std::declval(), 1743 | std::declval())) 1744 | transform(F&& f) const & { 1745 | return detail::optional_map_impl(*this, std::forward(f)); 1746 | } 1747 | 1748 | #ifndef TL_OPTIONAL_NO_CONSTRR 1749 | template 1750 | constexpr decltype(detail::optional_map_impl(std::declval(), 1751 | std::declval())) 1752 | transform(F&& f) const && { 1753 | return detail::optional_map_impl(std::move(*this), std::forward(f)); 1754 | } 1755 | #endif 1756 | #endif 1757 | 1758 | /// Calls `f` if the optional is empty 1759 | template * = nullptr> 1760 | optional TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) & { 1761 | if (has_value()) 1762 | return *this; 1763 | 1764 | std::forward(f)(); 1765 | return nullopt; 1766 | } 1767 | 1768 | template * = nullptr> 1769 | optional TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) & { 1770 | return has_value() ? *this : std::forward(f)(); 1771 | } 1772 | 1773 | template * = nullptr> 1774 | optional or_else(F &&f) && { 1775 | if (has_value()) 1776 | return std::move(*this); 1777 | 1778 | std::forward(f)(); 1779 | return nullopt; 1780 | } 1781 | 1782 | template * = nullptr> 1783 | optional TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) && { 1784 | return has_value() ? std::move(*this) : std::forward(f)(); 1785 | } 1786 | 1787 | template * = nullptr> 1788 | optional or_else(F &&f) const & { 1789 | if (has_value()) 1790 | return *this; 1791 | 1792 | std::forward(f)(); 1793 | return nullopt; 1794 | } 1795 | 1796 | template * = nullptr> 1797 | optional TL_OPTIONAL_11_CONSTEXPR or_else(F &&f) const & { 1798 | return has_value() ? *this : std::forward(f)(); 1799 | } 1800 | 1801 | #ifndef TL_OPTIONAL_NO_CONSTRR 1802 | template * = nullptr> 1803 | optional or_else(F &&f) const && { 1804 | if (has_value()) 1805 | return std::move(*this); 1806 | 1807 | std::forward(f)(); 1808 | return nullopt; 1809 | } 1810 | 1811 | template * = nullptr> 1812 | optional or_else(F &&f) const && { 1813 | return has_value() ? std::move(*this) : std::forward(f)(); 1814 | } 1815 | #endif 1816 | 1817 | /// Maps the stored value with `f` if there is one, otherwise returns `u` 1818 | template U map_or(F &&f, U &&u) & { 1819 | return has_value() ? detail::invoke(std::forward(f), **this) 1820 | : std::forward(u); 1821 | } 1822 | 1823 | template U map_or(F &&f, U &&u) && { 1824 | return has_value() ? detail::invoke(std::forward(f), std::move(**this)) 1825 | : std::forward(u); 1826 | } 1827 | 1828 | template U map_or(F &&f, U &&u) const & { 1829 | return has_value() ? detail::invoke(std::forward(f), **this) 1830 | : std::forward(u); 1831 | } 1832 | 1833 | #ifndef TL_OPTIONAL_NO_CONSTRR 1834 | template U map_or(F &&f, U &&u) const && { 1835 | return has_value() ? detail::invoke(std::forward(f), std::move(**this)) 1836 | : std::forward(u); 1837 | } 1838 | #endif 1839 | 1840 | /// Maps the stored value with `f` if there is one, otherwise calls 1841 | /// `u` and returns the result. 1842 | template 1843 | detail::invoke_result_t map_or_else(F &&f, U &&u) & { 1844 | return has_value() ? detail::invoke(std::forward(f), **this) 1845 | : std::forward(u)(); 1846 | } 1847 | 1848 | template 1849 | detail::invoke_result_t map_or_else(F &&f, U &&u) && { 1850 | return has_value() ? detail::invoke(std::forward(f), std::move(**this)) 1851 | : std::forward(u)(); 1852 | } 1853 | 1854 | template 1855 | detail::invoke_result_t map_or_else(F &&f, U &&u) const & { 1856 | return has_value() ? detail::invoke(std::forward(f), **this) 1857 | : std::forward(u)(); 1858 | } 1859 | 1860 | #ifndef TL_OPTIONAL_NO_CONSTRR 1861 | template 1862 | detail::invoke_result_t map_or_else(F &&f, U &&u) const && { 1863 | return has_value() ? detail::invoke(std::forward(f), std::move(**this)) 1864 | : std::forward(u)(); 1865 | } 1866 | #endif 1867 | 1868 | /// Returns `u` if `*this` has a value, otherwise an empty optional. 1869 | template 1870 | constexpr optional::type> conjunction(U &&u) const { 1871 | using result = optional>; 1872 | return has_value() ? result{u} : result{nullopt}; 1873 | } 1874 | 1875 | /// Returns `rhs` if `*this` is empty, otherwise the current value. 1876 | TL_OPTIONAL_11_CONSTEXPR optional disjunction(const optional &rhs) & { 1877 | return has_value() ? *this : rhs; 1878 | } 1879 | 1880 | constexpr optional disjunction(const optional &rhs) const & { 1881 | return has_value() ? *this : rhs; 1882 | } 1883 | 1884 | TL_OPTIONAL_11_CONSTEXPR optional disjunction(const optional &rhs) && { 1885 | return has_value() ? std::move(*this) : rhs; 1886 | } 1887 | 1888 | #ifndef TL_OPTIONAL_NO_CONSTRR 1889 | constexpr optional disjunction(const optional &rhs) const && { 1890 | return has_value() ? std::move(*this) : rhs; 1891 | } 1892 | #endif 1893 | 1894 | TL_OPTIONAL_11_CONSTEXPR optional disjunction(optional &&rhs) & { 1895 | return has_value() ? *this : std::move(rhs); 1896 | } 1897 | 1898 | constexpr optional disjunction(optional &&rhs) const & { 1899 | return has_value() ? *this : std::move(rhs); 1900 | } 1901 | 1902 | TL_OPTIONAL_11_CONSTEXPR optional disjunction(optional &&rhs) && { 1903 | return has_value() ? std::move(*this) : std::move(rhs); 1904 | } 1905 | 1906 | #ifndef TL_OPTIONAL_NO_CONSTRR 1907 | constexpr optional disjunction(optional &&rhs) const && { 1908 | return has_value() ? std::move(*this) : std::move(rhs); 1909 | } 1910 | #endif 1911 | 1912 | /// Takes the value out of the optional, leaving it empty 1913 | optional take() { 1914 | optional ret = std::move(*this); 1915 | reset(); 1916 | return ret; 1917 | } 1918 | 1919 | using value_type = T &; 1920 | 1921 | /// Constructs an optional that does not contain a value. 1922 | constexpr optional() noexcept : m_value(nullptr) {} 1923 | 1924 | constexpr optional(nullopt_t) noexcept : m_value(nullptr) {} 1925 | 1926 | /// Copy constructor 1927 | /// 1928 | /// If `rhs` contains a value, the stored value is direct-initialized with 1929 | /// it. Otherwise, the constructed optional is empty. 1930 | TL_OPTIONAL_11_CONSTEXPR optional(const optional &rhs) noexcept = default; 1931 | 1932 | /// Move constructor 1933 | /// 1934 | /// If `rhs` contains a value, the stored value is direct-initialized with 1935 | /// it. Otherwise, the constructed optional is empty. 1936 | TL_OPTIONAL_11_CONSTEXPR optional(optional &&rhs) = default; 1937 | 1938 | /// Constructs the stored value with `u`. 1939 | template >::value> 1941 | * = nullptr> 1942 | constexpr optional(U &&u) noexcept : m_value(std::addressof(u)) { 1943 | static_assert(std::is_lvalue_reference::value, "U must be an lvalue"); 1944 | } 1945 | 1946 | template 1947 | constexpr explicit optional(const optional &rhs) noexcept : optional(*rhs) {} 1948 | 1949 | /// No-op 1950 | ~optional() = default; 1951 | 1952 | /// Assignment to empty. 1953 | /// 1954 | /// Destroys the current value if there is one. 1955 | optional &operator=(nullopt_t) noexcept { 1956 | m_value = nullptr; 1957 | return *this; 1958 | } 1959 | 1960 | /// Copy assignment. 1961 | /// 1962 | /// Rebinds this optional to the referee of `rhs` if there is one. Otherwise 1963 | /// resets the stored value in `*this`. 1964 | optional &operator=(const optional &rhs) = default; 1965 | 1966 | /// Rebinds this optional to `u`. 1967 | template >::value> 1969 | * = nullptr> 1970 | optional &operator=(U &&u) { 1971 | static_assert(std::is_lvalue_reference::value, "U must be an lvalue"); 1972 | m_value = std::addressof(u); 1973 | return *this; 1974 | } 1975 | 1976 | /// Converting copy assignment operator. 1977 | /// 1978 | /// Rebinds this optional to the referee of `rhs` if there is one. Otherwise 1979 | /// resets the stored value in `*this`. 1980 | template optional &operator=(const optional &rhs) noexcept { 1981 | m_value = std::addressof(rhs.value()); 1982 | return *this; 1983 | } 1984 | 1985 | /// Rebinds this optional to `u`. 1986 | template >::value> 1988 | * = nullptr> 1989 | optional &emplace(U &&u) noexcept { 1990 | return *this = std::forward(u); 1991 | } 1992 | 1993 | void swap(optional &rhs) noexcept { std::swap(m_value, rhs.m_value); } 1994 | 1995 | /// Returns a pointer to the stored value 1996 | constexpr const T *operator->() const noexcept { return m_value; } 1997 | 1998 | TL_OPTIONAL_11_CONSTEXPR T *operator->() noexcept { return m_value; } 1999 | 2000 | /// Returns the stored value 2001 | TL_OPTIONAL_11_CONSTEXPR T &operator*() noexcept { return *m_value; } 2002 | 2003 | constexpr const T &operator*() const noexcept { return *m_value; } 2004 | 2005 | constexpr bool has_value() const noexcept { return m_value != nullptr; } 2006 | 2007 | constexpr explicit operator bool() const noexcept { 2008 | return m_value != nullptr; 2009 | } 2010 | 2011 | /// Returns the contained value if there is one, otherwise throws bad_optional_access 2012 | TL_OPTIONAL_11_CONSTEXPR T &value() { 2013 | if (has_value()) 2014 | return *m_value; 2015 | throw bad_optional_access(); 2016 | } 2017 | TL_OPTIONAL_11_CONSTEXPR const T &value() const { 2018 | if (has_value()) 2019 | return *m_value; 2020 | throw bad_optional_access(); 2021 | } 2022 | 2023 | /// Returns the stored value if there is one, otherwise returns `u` 2024 | template constexpr T value_or(U &&u) const & noexcept { 2025 | static_assert(std::is_copy_constructible::value && 2026 | std::is_convertible::value, 2027 | "T must be copy constructible and convertible from U"); 2028 | return has_value() ? **this : static_cast(std::forward(u)); 2029 | } 2030 | 2031 | /// \group value_or 2032 | template TL_OPTIONAL_11_CONSTEXPR T value_or(U &&u) && noexcept { 2033 | static_assert(std::is_move_constructible::value && 2034 | std::is_convertible::value, 2035 | "T must be move constructible and convertible from U"); 2036 | return has_value() ? **this : static_cast(std::forward(u)); 2037 | } 2038 | 2039 | /// Destroys the stored value if one exists, making the optional empty 2040 | void reset() noexcept { m_value = nullptr; } 2041 | 2042 | private: 2043 | T *m_value; 2044 | }; // namespace tl 2045 | 2046 | 2047 | 2048 | } // namespace tl 2049 | 2050 | namespace std { 2051 | // TODO SFINAE 2052 | template struct hash> { 2053 | ::std::size_t operator()(const tl::optional &o) const { 2054 | if (!o.has_value()) 2055 | return 0; 2056 | 2057 | return std::hash>()(*o); 2058 | } 2059 | }; 2060 | } // namespace std 2061 | 2062 | #endif 2063 | -------------------------------------------------------------------------------- /include/dehancer/histogram.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by denn nevera on 2019-09-16. 3 | // 4 | 5 | #pragma once 6 | 7 | #include "armadillo" 8 | #include 9 | #include 10 | 11 | namespace dehancer::math { 12 | 13 | /** 14 | * Histogram Channel 15 | */ 16 | class Channel: public arma::frowvec { 17 | public: 18 | using arma::frowvec::frowvec; 19 | 20 | enum class Index:int { 21 | red = 0, 22 | green = 1, 23 | blue = 2, 24 | luma = 3 25 | }; 26 | 27 | /** 28 | * Integrate channel 29 | * @param s - scale integrated values 30 | * @return the channel object 31 | */ 32 | Channel& integrate(float s=1.0f); 33 | 34 | /** 35 | * Calculates single-precision vector threshold with signed constant to the specified range. 36 | * 37 | * @param lower - lower threshold 38 | * @param value - output constant 39 | * @return the channel object 40 | */ 41 | Channel& threshold(float lower, float value); 42 | 43 | /** 44 | * Scale channel 45 | * @param value - maximum value 46 | * @return the channel object 47 | */ 48 | Channel& scale(float value); 49 | 50 | /** 51 | * Clamp value 52 | * @param index 53 | * @param value 54 | * @return 55 | */ 56 | Channel& clamp(int index, float value); 57 | 58 | /** 59 | * Counts and finds the zero crossings in a single-precision vector. 60 | * @param max_crossings - maximum number of crossings to find 61 | * @return [index,count] - index of last crossing found and total number of zero crossings found as a tuple 62 | */ 63 | std::tuple find_zero_crossings(size_t max_crossings = 1 ); 64 | 65 | /** 66 | * Get the higher clipping value 67 | * @return value 68 | */ 69 | float higher(float clipping); 70 | 71 | /** 72 | * Get the lower clipping value 73 | * @return value 74 | */ 75 | float lower(float clipping); 76 | }; 77 | 78 | /** 79 | * Histogram 80 | */ 81 | class Histogram { 82 | 83 | struct Size { 84 | /** 85 | * Histogram length (256 by default) 86 | */ 87 | std::size_t size; 88 | /** 89 | * Number of channels 90 | */ 91 | std::size_t num_channels; 92 | }; 93 | 94 | public: 95 | 96 | /** 97 | * Create an empty histogram 98 | * @param num_channels - channels number 99 | * @param size - histogram length 100 | */ 101 | explicit Histogram(size_t num_channels=4, size_t size=256); 102 | 103 | /** 104 | * Create a histogram from raw data 105 | * @param buffer - vectors of channels 106 | */ 107 | explicit Histogram(const std::vector>& buffer); 108 | 109 | Histogram(const Histogram& h); 110 | 111 | Histogram(Histogram&& h) noexcept ; 112 | 113 | Histogram& operator=(const Histogram& h); 114 | 115 | /** 116 | * Update histogram from raw buffer 117 | * @param buffer 118 | */ 119 | void update(const std::vector>& buffer); 120 | 121 | /** 122 | * Get histogram channels as vectors 123 | * @return channels 124 | */ 125 | [[nodiscard]] const std::vector& get_channels() const { return channels_; }; 126 | 127 | /** 128 | * Get certain channel by index 129 | * @param i - channel index 130 | * @return channel 131 | */ 132 | [[nodiscard]] Channel get_channel(int i) const; 133 | 134 | /** 135 | * Get certain channel by named index 136 | * @param i 137 | * @return channel 138 | */ 139 | [[nodiscard]] Channel get_channel(Channel::Index i) const; 140 | 141 | /** 142 | * Histogram size 143 | * @return length and number of channels 144 | */ 145 | [[nodiscard]] Size get_size() const { return size_; } 146 | 147 | private: 148 | Size size_{0,4}; 149 | std::vector channels_; 150 | 151 | }; 152 | } 153 | -------------------------------------------------------------------------------- /include/dehancer/interpolator.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by denn nevera on 2019-08-15. 3 | // 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "dehancer/vectors.hpp" 14 | #include "dehancer/details/optional.hpp" 15 | #include "dehancer/scope_guard.hpp" 16 | #include "dehancer/details/observable_array.hpp" 17 | 18 | namespace dehancer::math { 19 | 20 | using namespace tl; 21 | 22 | struct Bounds { 23 | float2 left; 24 | float2 right; 25 | }; 26 | 27 | namespace protocol { 28 | 29 | class Interpolator { 30 | 31 | public: 32 | 33 | /*** 34 | * Control points 35 | */ 36 | observable::Array controls; 37 | 38 | /*** 39 | * Interpolation resolution 40 | */ 41 | READONLY_PROPERTY(resolution, 42 | size_t, Interpolator, 43 | { return this->resolution_; } // getter 44 | ); 45 | 46 | /** 47 | * Interpolation precision step 48 | */ 49 | READONLY_PROPERTY(step, 50 | float, Interpolator, 51 | { return 1.0f/this->resolution_; } // getter 52 | ); 53 | 54 | /*** 55 | * Lerp value 56 | * @param x - current "time" 57 | * @return interpolated value 58 | */ 59 | virtual float value(float x) const = 0; 60 | 61 | /*** 62 | * Get linear interpolation for the x "time" 63 | * @param x - "time" 64 | * @return interpolated value 65 | */ 66 | virtual float linear(float x) const; 67 | 68 | /*** 69 | * Test bounds for the x "time" 70 | * @return return nullopt if x is within bounds or closest bound 71 | */ 72 | virtual optional test_bounds(float x) const; 73 | 74 | /** 75 | * Interpolation bounds 76 | * @return by default 0,0:1,1 77 | */ 78 | virtual Bounds get_bounds() const; 79 | 80 | /*** 81 | * Minimal control points that must be set for the intrapolation method 82 | * @return size 83 | */ 84 | virtual size_t minimum_controls() const = 0; 85 | 86 | /*** 87 | * Get indices for the current interpolation control points 88 | * @param x - "time" 89 | * @return 90 | */ 91 | virtual std::tuple indices(float x) const ; 92 | 93 | /*** 94 | * Return indices of piece on linear cut from any controls sequence 95 | * @param controls - control points 96 | * @param x - "time" 97 | * @return start/end indices 98 | */ 99 | static std::tuple indices(const std::vector& controls, float x); 100 | 101 | /*** 102 | * Get linear interpolation for the x "time" over curve 103 | * @param curve 104 | * @param x 105 | * @return 106 | */ 107 | static float linear(const std::vector& curve, float x); 108 | 109 | /*** 110 | * Create interpolation object 111 | * @param resolution - interpolation resolution 112 | */ 113 | explicit Interpolator(size_t resolution = 256); 114 | 115 | explicit Interpolator(const std::vector& controls, size_t resolution = 256); 116 | 117 | virtual ~Interpolator() = default; 118 | 119 | private: 120 | size_t resolution_; 121 | }; 122 | } 123 | } 124 | 125 | -------------------------------------------------------------------------------- /include/dehancer/math.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by denn nevera on 2019-09-01. 3 | // 4 | 5 | #pragma once 6 | 7 | #include "dehancer/vectors.hpp" 8 | #include "dehancer/matrix.hpp" 9 | #include "dehancer/interpolator.hpp" 10 | #include "dehancer/spline/linear.hpp" 11 | #include "dehancer/spline/bezier.hpp" 12 | #include "dehancer/spline/catmul_rom.hpp" 13 | #include "dehancer/spline/cubic.hpp" 14 | #include "dehancer/spline/bspline.hpp" 15 | #include "dehancer/spline/utils.hpp" 16 | -------------------------------------------------------------------------------- /include/dehancer/matrix.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by denn nevera on 2019-09-03. 3 | // 4 | 5 | #pragma once 6 | 7 | #include 8 | 9 | namespace dehancer::math { 10 | using float2x2 = arma::fmat::fixed<2, 2>; 11 | using float3x3 = arma::fmat::fixed<3, 3>; 12 | using float4x4 = arma::fmat::fixed<4, 4>; 13 | } 14 | -------------------------------------------------------------------------------- /include/dehancer/properties.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by denn nevera on 2019-09-01. 3 | // 4 | 5 | #pragma once 6 | 7 | #include 8 | 9 | template 10 | struct Property 11 | { 12 | Outer *instance; 13 | 14 | Property(Outer *instance): instance(instance){} 15 | Property(): instance(nullptr){} 16 | 17 | operator T () const { return (instance->*getter)(); } 18 | operator T& () { return (instance->*getter)(); } 19 | 20 | Property& operator = (const Property& other) { *this = (other.instance->*getter)(); return *this; } 21 | 22 | Property& operator = (const T& value) { (instance->*setter)(value); return *this; } 23 | 24 | Property& operator = (Outer *value) { instance = value; return *this; } 25 | 26 | template 27 | Property& operator = (const Property& other) 28 | { 29 | *this = (other.instance->*getter2)(); return *this ; 30 | } 31 | 32 | }; 33 | 34 | #define PROPERTY(__PROPS__, __PROPS_TYPE__, __OUTER_CLASS__, __GETTER__, __SETTER__ ) \ 35 | void set_ ##__PROPS__(const __PROPS_TYPE__& value) {__PROPS__.instance = this; __SETTER__; };\ 36 | __PROPS_TYPE__& get_ ##__PROPS__() __GETTER__;\ 37 | Property<__OUTER_CLASS__, __PROPS_TYPE__,\ 38 | &__OUTER_CLASS__::get_ ##__PROPS__, &__OUTER_CLASS__::set_ ##__PROPS__> __PROPS__ = this 39 | 40 | 41 | template 42 | struct ReadOnlyProperty 43 | { 44 | Outer *instance; 45 | 46 | ReadOnlyProperty(Outer *instance) 47 | : instance(instance) 48 | { 49 | } 50 | 51 | operator T () const{ 52 | return (instance->*getter)(); 53 | } 54 | 55 | template 56 | ReadOnlyProperty& operator=(const ReadOnlyProperty& other) 57 | { 58 | *this = (other.instance->*getter2)(); return *this; 59 | } 60 | 61 | ReadOnlyProperty& operator=(const ReadOnlyProperty& other) 62 | { 63 | *this = (other.instance->*getter)(); return *this; 64 | } 65 | }; 66 | 67 | #define READONLY_PROPERTY(__PROPS__, __PROPS_TYPE__, __OUTER_CLASS__, __GETTER__) \ 68 | __PROPS_TYPE__ get_ ##__PROPS__() const __GETTER__;\ 69 | ReadOnlyProperty<__OUTER_CLASS__, __PROPS_TYPE__, &__OUTER_CLASS__::get_ ##__PROPS__> __PROPS__ = this 70 | 71 | namespace dehancer::math { 72 | 73 | template 74 | class value_property { 75 | public: 76 | 77 | [[maybe_unused]] value_property()= default; 78 | 79 | explicit value_property(const T& value) { value_=value; }; 80 | 81 | operator T() const {return (T)(value_);} 82 | 83 | const T& operator()() const { return value_(); } 84 | 85 | value_property &operator=(const T &value) { 86 | value_ = value; 87 | return *this; 88 | } 89 | 90 | private: 91 | T value_{}; 92 | }; 93 | 94 | template 95 | class property { 96 | public: 97 | 98 | [[maybe_unused]] property( 99 | std::function setter, 100 | std::function getter 101 | ) : 102 | setter_(setter), 103 | getter_(getter) 104 | {}; 105 | 106 | explicit property(const T& value) { setter_(value); }; 107 | 108 | operator T() const {return getter_();} 109 | 110 | const T& operator()() const { return getter_(); } 111 | 112 | property &operator=(const T &value) { 113 | setter_(value); 114 | return *this; 115 | } 116 | 117 | private: 118 | std::function setter_; 119 | std::function getter_; 120 | }; 121 | 122 | template 123 | class copied_property { 124 | public: 125 | 126 | [[maybe_unused]] copied_property( 127 | std::function setter, 128 | std::function getter 129 | ) : 130 | setter_(setter), 131 | getter_(getter) 132 | {}; 133 | 134 | explicit copied_property(const T& value) { setter_(value); }; 135 | 136 | explicit operator const T&() const {return getter_();} 137 | 138 | const T operator()() const { return getter_(); } 139 | 140 | copied_property &operator=(const T &value) { 141 | setter_(value); 142 | return *this; 143 | } 144 | 145 | private: 146 | std::function setter_; 147 | std::function getter_; 148 | }; 149 | 150 | template 151 | class assigned_property { 152 | public: 153 | 154 | [[maybe_unused]] assigned_property( 155 | std::function setter, 156 | std::function getter, 157 | std::function assigner 158 | ) : 159 | setter_(setter), 160 | getter_(getter), 161 | assigner_(assigner) 162 | {}; 163 | 164 | explicit assigned_property(const T& value) { setter_(value); }; 165 | 166 | operator T() const {return getter_();} 167 | 168 | const T& operator()() const { return assigner_(); } 169 | 170 | T& operator()() { return assigner_(); } 171 | 172 | assigned_property &operator=(const T &value) { 173 | setter_(value); 174 | return *this; 175 | } 176 | 177 | private: 178 | std::function setter_; 179 | std::function getter_; 180 | std::function assigner_; 181 | }; 182 | 183 | } -------------------------------------------------------------------------------- /include/dehancer/scope_guard.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by denn nevera on 2019-09-03. 3 | // 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | 10 | #if __cplusplus >= 201703L && defined(SG_REQUIRE_NOEXCEPT_IN_CPP17) 11 | #define SG_REQUIRE_NOEXCEPT 12 | #endif 13 | 14 | namespace dehancer{ 15 | namespace detail 16 | { 17 | /* --- Some custom type traits --- */ 18 | 19 | // Type trait determining whether a type is callable with no arguments 20 | template 21 | struct is_noarg_callable_t 22 | : public std::false_type 23 | {}; // in general, false 24 | 25 | template 26 | struct is_noarg_callable_t()())> 27 | : public std::true_type 28 | {}; // only true when call expression valid 29 | 30 | // Type trait determining whether a no-argument callable returns void 31 | template 32 | struct returns_void_t 33 | : public std::is_same()())> 34 | {}; 35 | 36 | /* Type trait determining whether a no-arg callable is nothrow invocable if 37 | required. This is where SG_REQUIRE_NOEXCEPT logic is encapsulated. */ 38 | template 39 | struct is_nothrow_invocable_if_required_t 40 | : public 41 | #ifdef SG_REQUIRE_NOEXCEPT 42 | std::is_nothrow_invocable /* Note: _r variants not enough to 43 | confirm void return: any return can be 44 | discarded so all returns are 45 | compatible with void */ 46 | #else 47 | std::true_type 48 | #endif 49 | {}; 50 | 51 | // logic AND of two or more type traits 52 | template 53 | struct and_t : public and_t> 54 | {}; // for more than two arguments 55 | 56 | template 57 | struct and_t : public std::conditional::type 58 | {}; // for two arguments 59 | 60 | // Type trait determining whether a type is a proper scope_guard callback. 61 | template 62 | struct is_proper_sg_callback_t 63 | : public and_t, 64 | returns_void_t, 65 | is_nothrow_invocable_if_required_t, 66 | std::is_nothrow_destructible> 67 | {}; 68 | 69 | 70 | /* --- The actual scope_guard template --- */ 71 | 72 | template::value>::type> 75 | class scope_guard; 76 | 77 | 78 | /* --- Now the friend maker --- */ 79 | 80 | template 81 | detail::scope_guard make_scope_guard(Callback&& callback) 82 | noexcept(std::is_nothrow_constructible::value); /* 83 | we need this in the inner namespace due to MSVC bugs preventing 84 | dehancer::detail::scope_guard from befriending a dehancer::make_scope_guard 85 | template instance in the parent namespace (see https://is.gd/xFfFhE). */ 86 | 87 | 88 | /* --- The template specialization that actually defines the class --- */ 89 | 90 | template 91 | class scope_guard final 92 | { 93 | public: 94 | typedef Callback callback_type; 95 | 96 | scope_guard(scope_guard&& other) noexcept (std::is_nothrow_constructible::value); 97 | 98 | ~scope_guard() noexcept; // highlight noexcept dtor 99 | 100 | void dismiss() noexcept; 101 | 102 | public: 103 | scope_guard() = delete; 104 | scope_guard(const scope_guard&) = delete; 105 | scope_guard& operator=(const scope_guard&) = delete; 106 | scope_guard& operator=(scope_guard&&) = delete; 107 | 108 | private: 109 | explicit scope_guard(Callback&& callback) 110 | noexcept(std::is_nothrow_constructible::value); /* 111 | meant for friends only */ 112 | 113 | friend scope_guard make_scope_guard(Callback&&) 114 | noexcept(std::is_nothrow_constructible::value); /* 115 | only make_scope_guard can create scope_guards from scratch (i.e. non-move) 116 | */ 117 | 118 | private: 119 | Callback m_callback; 120 | bool m_active; 121 | 122 | }; 123 | 124 | } // namespace detail 125 | 126 | 127 | /* --- Now the single public maker function --- */ 128 | 129 | using detail::make_scope_guard; // see comment on declaration above 130 | 131 | } // namespace dehancer 132 | 133 | //////////////////////////////////////////////////////////////////////////////// 134 | template 135 | dehancer::detail::scope_guard::scope_guard(Callback&& callback) 136 | noexcept(std::is_nothrow_constructible::value) 137 | : m_callback(std::forward(callback)) /* use () instead of {} because 138 | of DR 1467 (https://is.gd/WHmWuo), which still impacts older compilers 139 | (e.g. GCC 4.x and clang <=3.6, see https://godbolt.org/g/TE9tPJ and 140 | https://is.gd/Tsmh8G) */ 141 | , m_active{true} 142 | {} 143 | 144 | //////////////////////////////////////////////////////////////////////////////// 145 | template 146 | dehancer::detail::scope_guard::~scope_guard() noexcept 147 | { 148 | if(m_active) 149 | m_callback(); 150 | } 151 | 152 | //////////////////////////////////////////////////////////////////////////////// 153 | template 154 | dehancer::detail::scope_guard::scope_guard(scope_guard&& other) 155 | noexcept(std::is_nothrow_constructible::value) 156 | : m_callback(std::forward(other.m_callback)) // idem 157 | , m_active{std::move(other.m_active)} 158 | { 159 | other.m_active = false; 160 | } 161 | 162 | //////////////////////////////////////////////////////////////////////////////// 163 | template 164 | inline void dehancer::detail::scope_guard::dismiss() noexcept 165 | { 166 | m_active = false; 167 | } 168 | 169 | //////////////////////////////////////////////////////////////////////////////// 170 | template 171 | inline auto dehancer::detail::make_scope_guard(Callback&& callback) 172 | noexcept(std::is_nothrow_constructible::value) 173 | -> detail::scope_guard 174 | { 175 | return detail::scope_guard{std::forward(callback)}; 176 | } 177 | -------------------------------------------------------------------------------- /include/dehancer/spline/bezier.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by denn nevera on 2019-09-03. 3 | // 4 | 5 | #pragma once 6 | 7 | #include "dehancer/spline/matrix_based.hpp" 8 | 9 | 10 | namespace dehancer::spline { 11 | 12 | class Bezier: public MatrixBased { 13 | 14 | public: 15 | using MatrixBased::MatrixBased; 16 | explicit Bezier(const std::vector& controls, size_t resolution = 256); 17 | [[nodiscard]] const math::float4x4& get_matrix() const override ; 18 | }; 19 | } 20 | 21 | 22 | -------------------------------------------------------------------------------- /include/dehancer/spline/bspline.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by denn nevera on 2019-11-09. 3 | // 4 | 5 | #pragma once 6 | 7 | #include "dehancer/spline/matrix_based.hpp" 8 | 9 | namespace dehancer::spline { 10 | 11 | class BSpline: public MatrixBased { 12 | 13 | public: 14 | using MatrixBased::MatrixBased; 15 | explicit BSpline(const std::vector& controls, size_t resolution = 256); 16 | [[nodiscard]] const math::float4x4& get_matrix() const override ; 17 | }; 18 | } 19 | 20 | 21 | -------------------------------------------------------------------------------- /include/dehancer/spline/catmul_rom.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by denn nevera on 2019-09-06. 3 | // 4 | 5 | #pragma once 6 | 7 | #include "dehancer/spline/matrix_based.hpp" 8 | 9 | 10 | namespace dehancer::spline { 11 | 12 | class CatmulRom: public MatrixBased { 13 | 14 | public: 15 | using MatrixBased::MatrixBased; 16 | explicit CatmulRom(size_t resolution = 256, float tension=0.5); 17 | explicit CatmulRom(const std::vector& controls, size_t resolution = 256, float tension=0.5); 18 | [[nodiscard]] const math::float4x4& get_matrix() const override ; 19 | 20 | void set_tension(float tension_); 21 | [[nodiscard]] float get_tension() const { return tension_;} 22 | 23 | private: 24 | float tension_; 25 | math::float4x4 matrix_; 26 | }; 27 | } 28 | 29 | -------------------------------------------------------------------------------- /include/dehancer/spline/cubic.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by denn nevera on 2019-09-06. 3 | // 4 | 5 | #pragma once 6 | 7 | #include "dehancer/interpolator.hpp" 8 | 9 | namespace dehancer::spline { 10 | 11 | class Cubic: public math::protocol::Interpolator { 12 | 13 | public: 14 | using math::protocol::Interpolator::Interpolator; 15 | 16 | explicit Cubic(size_t resolution = 256, float second_derivative=1); 17 | explicit Cubic(const std::vector& controls, size_t resolution = 256, float second_derivative=1); 18 | 19 | void set_second_derivative(float second_derivative); 20 | [[nodiscard]] float get_second_derivative() const { return second_derivative_;} 21 | 22 | [[nodiscard]] size_t minimum_controls() const override ; 23 | 24 | [[nodiscard]] float value(float x) const override ; 25 | 26 | ~Cubic() override = default; 27 | 28 | private: 29 | std::vector coeffs_; 30 | float second_derivative_; 31 | void update_coeffs(); 32 | }; 33 | } 34 | 35 | -------------------------------------------------------------------------------- /include/dehancer/spline/linear.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by denn nevera on 2019-09-04. 3 | // 4 | 5 | #pragma once 6 | 7 | #include "dehancer/interpolator.hpp" 8 | 9 | namespace dehancer::spline { 10 | class Linear: public math::protocol::Interpolator { 11 | 12 | public: 13 | using math::protocol::Interpolator::Interpolator; 14 | [[nodiscard]] size_t minimum_controls() const override; 15 | [[nodiscard]] float value(float x) const override; 16 | }; 17 | } 18 | 19 | -------------------------------------------------------------------------------- /include/dehancer/spline/matrix_based.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by denn nevera on 2019-09-03. 3 | // 4 | #pragma once 5 | 6 | #include "dehancer/interpolator.hpp" 7 | #include "dehancer/matrix.hpp" 8 | 9 | namespace dehancer::spline { 10 | 11 | namespace detail { 12 | struct matrix_interpolator; 13 | } 14 | 15 | class MatrixBased: public math::protocol::Interpolator { 16 | 17 | public: 18 | using math::protocol::Interpolator::Interpolator; 19 | 20 | explicit MatrixBased(size_t resolution = 256); 21 | 22 | explicit MatrixBased(const std::vector& controls, size_t resolution = 256); 23 | 24 | ~MatrixBased() override = default; 25 | 26 | [[nodiscard]] size_t minimum_controls() const override ; 27 | 28 | [[nodiscard]] float value(float x) const override ; 29 | 30 | [[nodiscard]] virtual const math::float4x4& get_matrix() const = 0; 31 | 32 | protected: 33 | void evaluate_curve() ; 34 | 35 | private: 36 | std::vector curve_; 37 | void make_nps(std::vector& nps) const ; 38 | void spline(std::vector& sp, const math::float4& x, const math::float4& y, size_t np) const ; 39 | }; 40 | 41 | } 42 | -------------------------------------------------------------------------------- /include/dehancer/spline/utils.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by denn nevera on 2019-09-06. 3 | // 4 | 5 | #pragma once 6 | 7 | #include "dehancer/interpolator.hpp" 8 | #include "dehancer/vectors.hpp" 9 | 10 | namespace dehancer { 11 | 12 | namespace spline { 13 | 14 | std::vector make(const math::protocol::Interpolator& interpolator); 15 | 16 | template 17 | std::vector make(_Args&& ...__args) 18 | { 19 | static_assert( std::is_constructible<_Tp, _Args...>::value, "Can't construct object in spline::make" ); 20 | auto spline = _Tp(__args ...); 21 | return spline::make(spline); 22 | } 23 | 24 | } 25 | 26 | namespace curve { 27 | std::vector make(const math::protocol::Interpolator& interpolator); 28 | 29 | template 30 | std::vector make(_Args&& ...__args) 31 | { 32 | static_assert( std::is_constructible<_Tp, _Args...>::value, "Can't construct object in curve::make" ); 33 | auto spline = _Tp(__args ...); 34 | return curve::make(spline); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /include/dehancer/vectors.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by denn nevera on 2019-09-01. 3 | // 4 | 5 | #pragma once 6 | 7 | #include 8 | #include 9 | #include 10 | #include "dehancer/properties.hpp" 11 | #include "dehancer/details/observable_array.hpp" 12 | 13 | namespace dehancer::math { 14 | 15 | /** 16 | * N-dimensions column float vector 17 | * @tparam N 18 | */ 19 | template 20 | class float_vector: public arma::fvec::fixed { 21 | using armfloatN = arma::fvec::fixed; 22 | public: 23 | using armfloatN::armfloatN; 24 | float_vector& operator=(const observable::Aproxy &a) { 25 | *this = a.get_data(); return *this; 26 | } 27 | }; 28 | 29 | /** 30 | * 2-dimensions column float vector 31 | */ 32 | class float2: public float_vector<2> { 33 | 34 | public: 35 | 36 | using float_vector::float_vector; 37 | 38 | [[nodiscard]] float get_x() { return (*this)[0]; }; 39 | [[nodiscard]] float& assign_x() { return (*this)[0]; }; 40 | void set_x(float xx) { (*this)[0] = xx; }; 41 | 42 | [[nodiscard]] float get_y() { return (*this)[1]; }; 43 | [[nodiscard]] float& assign_y() { return (*this)[1]; }; 44 | void set_y(float yy) { (*this)[1] = yy; }; 45 | 46 | float2(const observable::Aproxy &a):float_vector(a.get_data()){}; 47 | 48 | assigned_property x { 49 | [this] (float v) { this->set_x(v); }, // Setter 50 | [this] () -> float { return this->get_x(); }, // Getter 51 | [this] () -> float& { return this->assign_x(); } // Assigner 52 | }; 53 | 54 | assigned_property y { 55 | [this] (float v) { this->set_y(v); }, // Setter 56 | [this] () -> float { return this->get_y(); }, // Getter 57 | [this] () -> float& { return this->assign_y(); } // Assigner 58 | }; 59 | }; 60 | 61 | /** 62 | * 3-dimensions column float vector 63 | */ 64 | class float3: public float_vector<3> { 65 | 66 | public: 67 | using float_vector::float_vector; 68 | 69 | float get_x() { return (*this)[0]; }; 70 | void set_x(float xx) { (*this)[0] = xx; }; 71 | [[nodiscard]] float& assign_x() { return (*this)[0]; }; 72 | 73 | float get_y() { return (*this)[1]; }; 74 | void set_y(float xx) { (*this)[1] = xx; }; 75 | [[nodiscard]] float& assign_y() { return (*this)[1]; }; 76 | 77 | float get_z() { return (*this)[2]; }; 78 | void set_z(float xx) { (*this)[2] = xx; }; 79 | [[nodiscard]] float& assign_z() { return (*this)[2]; }; 80 | 81 | float3(const observable::Aproxy &a):float_vector(a.get_data()){} 82 | 83 | assigned_property x { 84 | [this] (float v) { this->set_x(v); }, // Setter 85 | [this] () -> float { return this->get_x(); }, // Getter 86 | [this] () -> float& { return this->assign_x(); } // Assigner 87 | }; 88 | 89 | assigned_property y { 90 | [this] (float v) { this->set_y(v); }, // Setter 91 | [this] () -> float { return this->get_y(); }, // Getter 92 | [this] () -> float& { return this->assign_y(); } // Assigner 93 | }; 94 | 95 | assigned_property z { 96 | [this] (float v) { this->set_z(v); }, // Setter 97 | [this] () -> float { return this->get_z(); }, // Getter 98 | [this] () -> float& { return this->assign_z(); } // Assigner 99 | }; 100 | 101 | }; 102 | 103 | /** 104 | * 4-dimensions column float vector 105 | */ 106 | class float4: public float_vector<4> { 107 | 108 | public: 109 | using float_vector::float_vector; 110 | 111 | float get_x() { return (*this)[0]; }; 112 | void set_x(float xx) { (*this)[0] = xx; }; 113 | [[nodiscard]] float& assign_x() { return (*this)[0]; }; 114 | 115 | float get_y() { return (*this)[1]; }; 116 | void set_y(float xx) { (*this)[1] = xx; }; 117 | [[nodiscard]] float& assign_y() { return (*this)[1]; }; 118 | 119 | float get_z() { return (*this)[2]; }; 120 | void set_z(float xx) { (*this)[2] = xx; }; 121 | [[nodiscard]] float& assign_z() { return (*this)[2]; }; 122 | 123 | float get_w() { return (*this)[3]; }; 124 | void set_w(float xx) { (*this)[3] = xx; }; 125 | [[nodiscard]] float& assign_w() { return (*this)[3]; }; 126 | 127 | float4(const observable::Aproxy &a):float_vector(a.get_data()){} 128 | 129 | assigned_property x { 130 | [this] (float v) { this->set_x(v); }, // Setter 131 | [this] () -> float { return this->get_x(); }, // Getter 132 | [this] () -> float& { return this->assign_x(); } // Assigner 133 | }; 134 | 135 | assigned_property y { 136 | [this] (float v) { this->set_y(v); }, // Setter 137 | [this] () -> float { return this->get_y(); }, // Getter 138 | [this] () -> float& { return this->assign_y(); } // Assigner 139 | }; 140 | 141 | assigned_property z { 142 | [this] (float v) { this->set_z(v); }, // Setter 143 | [this] () -> float { return this->get_z(); }, // Getter 144 | [this] () -> float& { return this->assign_z(); } // Assigner 145 | }; 146 | 147 | assigned_property w { 148 | [this] (float v) { this->set_w(v); }, // Setter 149 | [this] () -> float { return this->get_w(); }, // Getter 150 | [this] () -> float& { return this->assign_w(); } // Assigner 151 | }; 152 | }; 153 | 154 | 155 | inline static float2 make_float2(float x, float y) { 156 | return {x, y}; 157 | } 158 | 159 | inline static float3 make_float3(float x, float y, float z) { 160 | return {x, y, z}; 161 | } 162 | 163 | inline static float4 make_float4(float x, float y, float z, float w) { 164 | return {x, y, z, w}; 165 | } 166 | 167 | /** 168 | * Kernel compatible function to convert single float to float2, float3, float4 169 | * @param C 170 | * @return 171 | */ 172 | static inline float2 to_float2(float C) { return make_float2(C,C); } 173 | static inline float3 to_float3(float C) { return make_float3(C,C,C); } 174 | static inline float4 to_float4(float C) { return make_float4(C,C,C,C); } 175 | 176 | static inline float2 to_float2(int C) { return make_float2(C,C); } 177 | static inline float3 to_float3(int C) { return make_float3(C,C,C); } 178 | static inline float4 to_float4(int C) { return make_float4(C,C,C,C); } 179 | 180 | static inline float2 to_float2(unsigned int C) { return make_float2(C,C); } 181 | static inline float3 to_float3(unsigned int C) { return make_float3(C,C,C); } 182 | static inline float4 to_float4(unsigned int C) { return make_float4(C,C,C,C); } 183 | 184 | static inline float4 to_float4(const float3& a, float w) { 185 | return make_float4(a.x, a.y, a.z, w); 186 | } 187 | 188 | static inline float3 to_float3(const float4& a) { 189 | return make_float3(a.x, a.y, a.z); 190 | } 191 | 192 | /** 193 | * Kernel compatible function of step 194 | * @param edge 195 | * @param x 196 | * @return 197 | */ 198 | static inline float step(float edge, float x) { 199 | return x < edge ? 0.0f : 1.0f; 200 | } 201 | 202 | static inline float2 step(const float2& edge, const float2& x) { 203 | return make_float2(step(edge.x, x.x),step(edge.y, x.y)); 204 | } 205 | 206 | static inline float3 step(const float3& edge, const float3& x) { 207 | return make_float3(step(edge.x, x.x),step(edge.y, x.y),step(edge.z, x.z)); 208 | } 209 | 210 | static inline float4 step(const float4& edge, const float4& x) { 211 | return make_float4(step(edge.x, x.x),step(edge.y, x.y),step(edge.z, x.z),step(edge.w, x.w)); 212 | } 213 | 214 | static inline float2 step(float edge, const float2& x) { 215 | return make_float2(step(edge, x.x),step(edge, x.y)); 216 | } 217 | 218 | static inline float3 step(float edge, const float3& x) { 219 | return make_float3(step(edge, x.x),step(edge, x.y),step(edge, x.z)); 220 | } 221 | 222 | static inline float4 step(float edge, const float4& x) { 223 | return make_float4(step(edge, x.x),step(edge, x.y),step(edge, x.z),step(edge, x.w)); 224 | } 225 | 226 | /*** 227 | * Kernel compatible function of clamp 228 | * @param f 229 | * @param a 230 | * @param b 231 | * @return 232 | */ 233 | static inline float clamp(float f, float a, float b) { 234 | return fmaxf(a, fminf(f, b)); 235 | } 236 | 237 | static inline float2 clamp(const float2& v, float a, float b) { 238 | return make_float2(clamp(v.x, a, b), clamp(v.y, a, b)); 239 | } 240 | 241 | static inline float2 clamp(const float2& v, const float2& a, const float2& b) { 242 | return make_float2(clamp(v.x, a.x, b.x), clamp(v.y, a.y, b.y)); 243 | } 244 | 245 | static inline float3 clamp(const float3& v, float a, float b) { 246 | return make_float3(clamp(v.x, a, b), clamp(v.y, a, b), clamp(v.z, a, b)); 247 | } 248 | 249 | static inline float3 clamp(const float3& v, const float3& a, const float3& b) { 250 | return make_float3(clamp(v.x, a.x, b.x), clamp(v.y, a.y, b.y), clamp(v.z, a.z, b.z)); 251 | } 252 | 253 | static inline float4 clamp(const float4& v, float a, float b) { 254 | return make_float4(clamp(v.x, a, b), clamp(v.y, a, b), clamp(v.z, a, b), clamp(v.w, a, b)); 255 | } 256 | 257 | static inline float4 clamp(const float4& v, const float4& a, const float4& b) { 258 | return make_float4(clamp(v.x, a.x, b.x), clamp(v.y, a.y, b.y), clamp(v.z, a.z, b.z), clamp(v.w, a.w, b.w)); 259 | } 260 | 261 | /** 262 | * Kernel compatible function of fabs 263 | * @return 264 | */ 265 | 266 | static inline float2 fabs(const float2& v) { 267 | return make_float2(std::abs(v.x), std::abs(v.y)); 268 | } 269 | 270 | static inline float3 fabs(const float3& v) { 271 | return make_float3(std::abs(v.x), std::abs(v.y), std::abs(v.z)); 272 | } 273 | 274 | static inline float4 fabs(const float4& v) { 275 | return make_float4(std::abs(v.x), std::abs(v.y), std::abs(v.z), std::abs(v.w)); 276 | } 277 | 278 | /** 279 | * Kernel compatible function of fract 280 | * @param v 281 | * @return 282 | */ 283 | static inline float fracf(float v) { 284 | return v - floorf(v); 285 | } 286 | 287 | static inline float2 fracf(const float2& v) { 288 | return make_float2(fracf(v.x), fracf(v.y)); 289 | } 290 | 291 | static inline float3 fracf(const float3& v) { 292 | return make_float3(fracf(v.x), fracf(v.y), fracf(v.z)); 293 | } 294 | 295 | static inline float4 fracf(const float4& v) { 296 | return make_float4(fracf(v.x), fracf(v.y), fracf(v.z), fracf(v.w)); 297 | } 298 | 299 | 300 | static inline float mix(float x, float y, float a) { 301 | return x + (y - x) * a; 302 | } 303 | 304 | /** 305 | * Kernel compatible function of mix 306 | * @param x 307 | * @param y 308 | * @param a 309 | * @return 310 | */ 311 | static inline float4 mix(const float4& x, const float4& y, float a) { 312 | return { 313 | mix(x.x, y.y, a), 314 | mix(x.y, y.y, a), 315 | mix(x.z, y.z, a), 316 | mix(x.w, y.w, a) 317 | }; 318 | } 319 | 320 | static inline float4 mix(const float4& x, const float4& y, const float4& a) { 321 | return { 322 | mix(x.x, y.y, a.x), 323 | mix(x.y, y.y, a.y), 324 | mix(x.z, y.z, a.z), 325 | mix(x.w, y.w, a.w) 326 | }; 327 | } 328 | 329 | static inline float3 mix(const float3& x, const float3& y, float a) { 330 | return{ 331 | mix(x.x, y.y, a), 332 | mix(x.y, y.y, a), 333 | mix(x.z, y.z, a) 334 | }; 335 | } 336 | 337 | static inline float3 mix(const float3& x, const float3& y, const float3& a) { 338 | return{ 339 | mix(x.x, y.y, a.x), 340 | mix(x.y, y.y, a.y), 341 | mix(x.z, y.z, a.z) 342 | }; 343 | } 344 | 345 | static inline float2 mix(const float2& x, const float2& y, float a) { 346 | return { 347 | mix(x.x, y.y, a), 348 | mix(x.y, y.y, a) 349 | }; 350 | } 351 | 352 | static inline float2 mix(const float2& x, const float2& y, const float2& a) { 353 | return { 354 | mix(x.x, y.y, a.x), 355 | mix(x.y, y.y, a.y) 356 | }; 357 | } 358 | 359 | } -------------------------------------------------------------------------------- /lib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include(CMakePackageConfigHelpers) 2 | 3 | include_directories( 4 | ${CMAKE_CURRENT_SOURCE_DIR}/include 5 | ../include 6 | ${CMAKE_CURRENT_SOURCE_DIR}/src/ 7 | ${EXTERNAL_LOCATION} 8 | ) 9 | 10 | FILE(GLOB PUBLIC_INCLUDE_FILES 11 | ../include/dehancer/*.hpp 12 | ) 13 | 14 | FILE(GLOB PUBLIC_SPLINE_INCLUDE_FILES 15 | ../include/dehancer/spline/*.hpp 16 | ) 17 | 18 | FILE(GLOB PUBLIC_DETAILS_INCLUDE_FILES 19 | ../include/dehancer/details/*.hpp 20 | ) 21 | 22 | FILE(GLOB INCLUDE_FILES 23 | ${PUBLIC_INCLUDE_FILES} 24 | ) 25 | 26 | FILE(GLOB SOURCES 27 | ../src/*.cpp 28 | ../src/spline/*.cpp 29 | ) 30 | 31 | add_library( 32 | ${PROJECT_LIB} 33 | ${SOURCES}) 34 | 35 | if (COMMON_DEPENDENCIES) 36 | add_dependencies(${PROJECT_LIB} ${COMMON_DEPENDENCIES}) 37 | endif () 38 | 39 | target_link_libraries ( 40 | ${PROJECT_LIB} PUBLIC 41 | ) 42 | 43 | target_include_directories( 44 | ${PROJECT_LIB} 45 | PUBLIC 46 | ../include 47 | ) 48 | 49 | set(config_install_dir "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}") 50 | set(generated_dir "${CMAKE_CURRENT_BINARY_DIR}/generated") 51 | 52 | # Configuration 53 | set(version_config "${generated_dir}/${PROJECT_NAME}ConfigVersion.cmake") 54 | set(project_config "${generated_dir}/${PROJECT_NAME}Config.cmake") 55 | set(TARGETS_EXPORT_NAME "${PROJECT_NAME}") 56 | set(namespace "${PROJECT_NAME}::") 57 | 58 | write_basic_package_version_file( 59 | "${version_config}" COMPATIBILITY SameMajorVersion 60 | ) 61 | 62 | configure_package_config_file( 63 | "cmake/Config.cmake.in" 64 | "${project_config}" 65 | INSTALL_DESTINATION "${config_install_dir}" 66 | ) 67 | 68 | if (NOT CMAKE_INSTALL_LIBDIR) 69 | set(CMAKE_INSTALL_LIBDIR lib) 70 | endif () 71 | 72 | if (NOT CMAKE_INSTALL_INCLUDEDIR) 73 | set(CMAKE_INSTALL_INCLUDEDIR include) 74 | endif () 75 | 76 | install(DIRECTORY 77 | ${EXTERNAL_INSTALL_LOCATION}/include 78 | DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/.. 79 | FILES_MATCHING 80 | PATTERN armadillo 81 | PATTERN dehancer* EXCLUDE 82 | PATTERN gtest* EXCLUDE 83 | PATTERN gmock* EXCLUDE 84 | ) 85 | 86 | install(DIRECTORY 87 | ${EXTERNAL_INSTALL_LOCATION}/lib 88 | DESTINATION ${CMAKE_INSTALL_LIBDIR}/.. 89 | FILES_MATCHING 90 | PATTERN *armadillo*.* 91 | PATTERN armadillo.pc EXCLUDE 92 | PATTERN *gtest* EXCLUDE 93 | PATTERN *gmock* EXCLUDE 94 | ) 95 | 96 | install(FILES ${PUBLIC_INCLUDE_FILES} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dehancer) 97 | install(FILES ${PUBLIC_SPLINE_INCLUDE_FILES} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dehancer/spline) 98 | install(FILES ${PUBLIC_DETAILS_INCLUDE_FILES} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dehancer/details) 99 | install(FILES ${project_config} ${version_config} DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_LIB}) 100 | install(FILES cmake/${PROJECT_LIB}.cmake DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_LIB}) 101 | install(TARGETS ${PROJECT_LIB} DESTINATION ${CMAKE_INSTALL_LIBDIR}) 102 | -------------------------------------------------------------------------------- /lib/cmake/Config.cmake.in: -------------------------------------------------------------------------------- 1 | @PACKAGE_INIT@ 2 | 3 | set(@PROJECT_NAME@_INCLUDE_PATH @CMAKE_INSTALL_PREFIX@/include) 4 | include("${CMAKE_CURRENT_LIST_DIR}/@TARGETS_EXPORT_NAME@.cmake") 5 | check_required_components("@PROJECT_NAME@") -------------------------------------------------------------------------------- /lib/cmake/dehancer_maths_cpp.cmake: -------------------------------------------------------------------------------- 1 | add_library(${PROJECT_LIB} STATIC IMPORTED) 2 | 3 | find_library(${PROJECT_LIB}_LIBRARY_PATH ${PROJECT_LIB} HINTS "../..") 4 | set_target_properties(${PROJECT_LIB} PROPERTIES IMPORTED_LOCATION "${dehancer_maths_cpp_LIBRARY_PATH}") 5 | 6 | include_directories( 7 | "${dehancer_maths_cpp_INCLUDE_PATH}" 8 | ) -------------------------------------------------------------------------------- /src/histogram.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by denn nevera on 2019-09-16. 3 | // 4 | 5 | #include "dehancer/histogram.hpp" 6 | #include 7 | 8 | namespace dehancer::math { 9 | 10 | Histogram::Histogram(size_t num_channels, size_t size): 11 | size_({.size=size,.num_channels=num_channels}), 12 | channels_(num_channels) 13 | { 14 | for (int i = 0; i < size_.num_channels ; ++i) { 15 | channels_.resize(size); 16 | } 17 | } 18 | 19 | Histogram::Histogram(const std::vector>& buffer): 20 | size_({0,0}), 21 | channels_() 22 | { 23 | update(buffer); 24 | } 25 | 26 | void Histogram::update(const std::vector> &buffer) { 27 | channels_.resize(buffer.size()); 28 | if (!buffer.empty()) { 29 | size_ = Size({.size=buffer[0].size(), .num_channels=buffer.size()}); 30 | for (size_t i = 0; i < size_.num_channels; ++i) { 31 | channels_[i] = arma::conv_to::from(buffer[i]); 32 | } 33 | } 34 | } 35 | 36 | Channel Histogram::get_channel (int i) const { 37 | return channels_[i]; 38 | } 39 | 40 | Channel Histogram::get_channel (Channel::Index i) const { 41 | return get_channel (static_cast(i)) ; 42 | } 43 | 44 | Histogram::Histogram(const Histogram &h) { 45 | *this = h; 46 | } 47 | 48 | Histogram& Histogram::operator=(const Histogram &h) { 49 | size_ = h.size_; 50 | channels_.clear(); 51 | channels_.assign(h.channels_.begin(),h.channels_.end()); 52 | return *this; 53 | } 54 | 55 | Histogram::Histogram(Histogram &&h) noexcept { 56 | std::swap(size_, h.size_); 57 | std::swap(channels_, h.channels_); 58 | } 59 | 60 | Channel& Channel::clamp(int index, float value) { 61 | if (index >= size()) return *this; 62 | if (index < 0 ) return *this; 63 | (*this)[index] = value; 64 | return *this; 65 | } 66 | 67 | Channel& Channel::integrate(float s) { 68 | Channel vec(*this); 69 | for (int i = 1; i < size() ; ++i) { 70 | vec(i) = vec(i-1) + s*(*this)(i); 71 | } 72 | *this = vec; 73 | return *this; 74 | } 75 | 76 | Channel& Channel::threshold(float lower, float value) { 77 | for (int n = 0; n < size(); ++n){ 78 | if ((*this)[n] >= lower) 79 | (*this)[n] = value; 80 | else 81 | (*this)[n] = -value; 82 | } 83 | return *this; 84 | } 85 | 86 | template int sign(T val) { 87 | return (T(0) < val) - (val < T(0)); 88 | } 89 | 90 | Channel& Channel::scale(float value) { 91 | float max_ = this->max(); 92 | transform([value,max_](float val){ 93 | return val*value/max_; 94 | }); 95 | return *this; 96 | } 97 | 98 | std::tuple Channel::find_zero_crossings(size_t max_crossings) { 99 | size_t D = 0; 100 | size_t C = 0; 101 | 102 | auto& A = *this; 103 | 104 | for(size_t n = 1; n < size(); n++) 105 | { 106 | if( sign(A[n]) != sign(A[(n - 1)]) ) 107 | { 108 | D = D + 1; 109 | if( D == max_crossings) 110 | { 111 | C = n ; 112 | break; 113 | } 114 | } 115 | } 116 | 117 | return std::make_tuple(C,D); 118 | } 119 | 120 | float Channel::higher(float clipping) { 121 | 122 | if (empty()) return 1; 123 | 124 | Channel vec(*this); 125 | 126 | auto ths = vec 127 | .clamp(static_cast(size()-1),0) 128 | .integrate(1.0f) 129 | .scale(1.0f) 130 | .threshold(1.0f-clipping, 1.0); 131 | 132 | auto [index, nums] = ths.find_zero_crossings(1); 133 | 134 | float high = index < size() ? static_cast(index+1) : static_cast(size()); 135 | 136 | return high/static_cast(size()); 137 | } 138 | 139 | float Channel::lower(float clipping) { 140 | if (empty()) return 0; 141 | 142 | Channel vec(*this); 143 | 144 | auto ths = vec 145 | .clamp(0,0) 146 | .integrate(1.0f) 147 | .scale(1.0f) 148 | .threshold(clipping, 1.0f); 149 | 150 | auto [index, nums] = ths.find_zero_crossings(1); 151 | 152 | float low = index > 0 ? static_cast(index-1) : static_cast(0); 153 | 154 | return low/static_cast(size()); 155 | 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /src/interpolator.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by denn nevera on 2019-08-15. 3 | // 4 | 5 | #include "dehancer/interpolator.hpp" 6 | 7 | namespace dehancer { 8 | 9 | namespace math { 10 | 11 | namespace protocol { 12 | 13 | Interpolator::Interpolator(size_t resolution):resolution_(resolution){} 14 | 15 | Interpolator::Interpolator(const std::vector &controlsIn, size_t resolution):resolution_(resolution) 16 | { 17 | controls = controlsIn; 18 | } 19 | 20 | float Interpolator::linear(float x) const { 21 | return linear(controls,x); 22 | } 23 | 24 | float Interpolator::linear(const std::vector &curve, float x) { 25 | auto tm = Interpolator::indices(curve,x); 26 | auto k1 = std::get<0>(tm); 27 | auto k2 = std::get<1>(tm); 28 | 29 | float2 P0 = curve[k1]; 30 | float2 P1 = curve[k2]; 31 | 32 | float d = P1.x() - P0.x(); 33 | auto t = d == 0 ? 0 : (x-P0.x())/d; 34 | 35 | return (1 - t) * P0.y() + t * P1.y(); 36 | } 37 | 38 | std::tuple Interpolator::indices(float x) const { 39 | return Interpolator::indices(controls,x); 40 | } 41 | 42 | Bounds Interpolator::get_bounds() const { 43 | return {{0,0},{1,1}}; 44 | } 45 | 46 | optional Interpolator::test_bounds(float x) const { 47 | auto bounds = get_bounds(); 48 | if (bounds.left.x()>x) { return make_optional(bounds.left.y()); } 49 | if (bounds.right.x() Interpolator::indices( 54 | const std::vector &controls, 55 | float x) 56 | { 57 | size_t left = 0; 58 | size_t right = controls.size()-1; 59 | 60 | while ( right-left > 1) { 61 | 62 | auto i = size_t(floor(double(right+left)/2.0)); 63 | 64 | const float p = controls[i][0]; 65 | 66 | if (p > x ) { right = i; } 67 | else { left = i; } 68 | } 69 | 70 | return std::make_tuple(left,right); 71 | } 72 | } 73 | } 74 | 75 | namespace spline { 76 | 77 | 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/spline/bezier.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by denn nevera on 2019-09-03. 3 | // 4 | 5 | #include "dehancer/spline/bezier.hpp" 6 | 7 | namespace dehancer::spline { 8 | 9 | static const math::float4x4 matrix = 10 | { { 1, 0, 0, 0}, 11 | {-3, 3, 0, 0}, 12 | { 3, -6, 3, 0}, 13 | {-1, 3, -3, 1} 14 | }; 15 | 16 | Bezier::Bezier(const std::vector &controls, size_t resolution): 17 | MatrixBased(controls,resolution) { 18 | evaluate_curve(); 19 | } 20 | 21 | const math::float4x4& Bezier::get_matrix() const { 22 | return matrix; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/spline/bspline.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by denn nevera on 2019-11-09. 3 | // 4 | 5 | #include "dehancer/spline/bspline.hpp" 6 | 7 | namespace dehancer::spline { 8 | 9 | static const float mul = float(1.0/6.0); 10 | 11 | static const math::float4x4 matrix = 12 | { { 1, 4, 1, 0}, 13 | { -3, 0, 3, 0}, 14 | { 3,-6, 3, 0}, 15 | { -1, 3,-3, 1} 16 | }; 17 | 18 | BSpline::BSpline(const std::vector &controls, size_t resolution): 19 | MatrixBased(controls,resolution) { 20 | evaluate_curve(); 21 | } 22 | 23 | const math::float4x4& BSpline::get_matrix() const { 24 | static math::float4x4 m = mul * matrix; 25 | return m; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/spline/catmul_rom.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by denn nevera on 2019-09-06. 3 | // 4 | 5 | #include "dehancer/spline/catmul_rom.hpp" 6 | 7 | namespace dehancer::spline { 8 | 9 | CatmulRom::CatmulRom(size_t resolution, float tension): 10 | MatrixBased(resolution) 11 | { 12 | set_tension(tension); 13 | } 14 | 15 | CatmulRom::CatmulRom(const std::vector &controls, size_t resolution, float tension): 16 | MatrixBased(controls,resolution) 17 | { 18 | set_tension(tension); 19 | evaluate_curve(); 20 | } 21 | 22 | const math::float4x4& CatmulRom::get_matrix() const { 23 | return matrix_; 24 | } 25 | 26 | void CatmulRom::set_tension(float tension) { 27 | tension_ = tension; 28 | math::float4x4 matrix = { { 0, 1, 0, 0}, 29 | {-tension_, 0, tension_, 0}, 30 | { 2*tension_, tension_-3, 3-2*tension_, -tension_}, 31 | {-tension_, 2-tension_, tension_-2, tension_} 32 | }; 33 | matrix_ = matrix; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/spline/cubic.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by denn nevera on 2019-09-06. 3 | // 4 | 5 | #include "dehancer/spline/cubic.hpp" 6 | 7 | namespace dehancer::spline { 8 | 9 | Cubic::Cubic(size_t resolution, float second_derivative): 10 | Interpolator(resolution), 11 | coeffs_(), 12 | second_derivative_(second_derivative) 13 | { 14 | controls.on_update = [this](const std::vector& cnts) { 15 | this->update_coeffs(); 16 | }; 17 | } 18 | 19 | Cubic::Cubic(const std::vector &controlsIn, size_t resolution, float second_derivative) 20 | :Interpolator(controlsIn, resolution), 21 | coeffs_() 22 | { 23 | set_second_derivative(second_derivative); 24 | controls.on_update = [this](const std::vector& cnts) { 25 | this->update_coeffs(); 26 | }; 27 | } 28 | 29 | size_t Cubic::minimum_controls() const { return 3; } 30 | 31 | void Cubic::set_second_derivative(float second_derivative) { 32 | second_derivative_ = second_derivative; 33 | update_coeffs(); 34 | } 35 | 36 | float Cubic::value(float x) const { 37 | 38 | auto Y = test_bounds(x); 39 | if (Y) return *Y; 40 | if (controls.size()(tm); 44 | size_t i1 = std::get<1>(tm); 45 | 46 | float h = controls[i1].x() - controls[i0].x(); 47 | float x0 = x - controls[i0].x(); 48 | float x1 = controls[i1].x() - x; 49 | 50 | float y = powf(x1,3) * coeffs_[i0] + powf(x0, 3) * coeffs_[i1]; 51 | y = y/6/h; 52 | float z = coeffs_[i0]*x1 + coeffs_[i1]*x0; 53 | y = y - z*h/6; 54 | y = y + (controls[i0].y()*x1 + controls[i1].y()*x0)/h; 55 | 56 | return y; 57 | } 58 | 59 | void Cubic::update_coeffs() { 60 | 61 | if (controls.size()& cnts) { 14 | this->evaluate_curve(); 15 | }; 16 | } 17 | 18 | MatrixBased::MatrixBased(const std::vector &controlsIn, size_t resolution): 19 | Interpolator(controlsIn, resolution), 20 | curve_() 21 | { 22 | controls.on_update = [this](const std::vector& cnts) { 23 | this->evaluate_curve(); 24 | }; 25 | } 26 | 27 | float MatrixBased::value(float x) const { 28 | auto y = test_bounds(x); 29 | if (y) return *y; 30 | if (controls.size()& sp, const math::float4& x, const math::float4& y, size_t np) const { 39 | 40 | arma::vec u = arma::linspace(0,1,np); 41 | arma::vec u2 = arma::pow(u,2); 42 | arma::vec u3 = arma::pow(u,3); 43 | 44 | sp.clear(); 45 | sp.resize(np); 46 | 47 | for (int n = 0; n < np; ++n) { 48 | 49 | math::float4 t = {1, static_cast(u[n]), static_cast(u2[n]), static_cast(u3[n])}; 50 | 51 | auto tm = t.t() * this->get_matrix() ; 52 | 53 | sp[n] = {arma::dot(tm,x), arma::dot(tm,y)}; 54 | } 55 | } 56 | 57 | void MatrixBased::make_nps(std::vector &nps) const { 58 | 59 | auto cpn = controls.size(); 60 | auto ni = cpn - (minimum_controls()-1); 61 | if (ni == 0) 62 | return; 63 | auto npf = resolution/ni; 64 | auto npl = resolution - (npf * (ni - 1)); 65 | 66 | nps.clear(); 67 | for (int i = 0; i < ni-1 ; ++i) { 68 | nps.push_back(npf+1); 69 | } 70 | nps.push_back(npl+1); 71 | nps[0] -= 1; 72 | 73 | } 74 | 75 | void MatrixBased::evaluate_curve() { 76 | 77 | curve_.clear(); 78 | 79 | std::vector nps; 80 | make_nps(nps); 81 | 82 | size_t ii = 0; 83 | std::vector s; 84 | 85 | auto icount = controls.size() - (minimum_controls()-2); 86 | 87 | for (int i = 1; i < icount ; ++i) { 88 | 89 | math::float2 p0 = controls[i-1]; 90 | math::float2 p1 = controls[i-0]; 91 | math::float2 p2 = controls[i+1]; 92 | math::float2 p3 = controls[i+2]; 93 | 94 | math::float4 px({p0.x(),p1.x(),p2.x(),p3.x()}); 95 | math::float4 py({p0.y(),p1.y(),p2.y(),p3.y()}); 96 | 97 | spline(s, px, py, nps[ii++]); 98 | 99 | std::copy (s.begin(), s.end(), std::back_inserter(curve_)); 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/spline/utils.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by denn nevera on 2019-09-06. 3 | // 4 | 5 | #include "dehancer/spline/utils.hpp" 6 | 7 | namespace dehancer { 8 | namespace spline { 9 | std::vector make(const math::protocol::Interpolator& interpolator){ 10 | std::vector vector; vector.resize(interpolator.resolution+1); 11 | for (size_t i = 0; i <= interpolator.resolution; ++i) { 12 | math::float2 point; 13 | point.x() = (float)i*interpolator.step; 14 | point.y() = interpolator.value(point.x()); 15 | vector[i] = point; 16 | } 17 | return vector; 18 | } 19 | } 20 | 21 | namespace curve { 22 | std::vector make(const math::protocol::Interpolator& interpolator){ 23 | std::vector vector; vector.resize(interpolator.resolution+1); 24 | for (size_t i = 0; i <= interpolator.resolution; ++i) { 25 | auto x = (float)i*interpolator.step; 26 | vector[i] = interpolator.value(x); 27 | } 28 | return vector; 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /src/vectors.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by denn nevera on 2019-09-01. 3 | // 4 | 5 | #include "dehancer/vectors.hpp" 6 | -------------------------------------------------------------------------------- /tests/CMakeCommon.in: -------------------------------------------------------------------------------- 1 | set(TEST_LIBRARIES) 2 | 3 | if (GTEST_FOUND) 4 | include_directories(${GTEST_INCLUDE_DIRS}) 5 | set(TEST_LIBRARIES ${GTEST_BOTH_LIBRARIES}) 6 | else() 7 | message("Googletest ${TEST} RELEASE MODE: ${CMAKE_BUILD_TYPE}") 8 | set(TEST_LIBRARIES gtest;gtest_main) 9 | endif() 10 | 11 | file(GLOB TESTS_SOURCES ${TESTS_SOURCES} 12 | ./*.cpp 13 | ) 14 | 15 | include_directories(./) 16 | 17 | add_executable(${TEST} ${TESTS_SOURCES}) 18 | 19 | target_link_libraries( 20 | ${TEST} 21 | ${PROJECT_LIB} 22 | ${TEST_LIBRARIES} 23 | ${COMMON_LIBRARIES} 24 | ) 25 | 26 | if (COMMON_DEPENDENCIES) 27 | message(STATUS "${TEST} DEPENDENCIES: ${COMMON_DEPENDENCIES}") 28 | add_dependencies( 29 | ${TEST} 30 | ${COMMON_DEPENDENCIES} 31 | ) 32 | endif () 33 | 34 | add_test(test ${TEST}) 35 | enable_testing() 36 | 37 | -------------------------------------------------------------------------------- /tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(initial) 2 | add_subdirectory(vector) 3 | add_subdirectory(interpolator) 4 | add_subdirectory(bezier) 5 | add_subdirectory(catmulrom) 6 | add_subdirectory(cubic) 7 | add_subdirectory(bspline) -------------------------------------------------------------------------------- /tests/bezier/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set (TEST bezier-test) 2 | include(../CMakeCommon.in) -------------------------------------------------------------------------------- /tests/bezier/bezier.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by denn nevera on 2019-09-03. 3 | // 4 | 5 | #include "gtest/gtest.h" 6 | #include "dehancer/math.hpp" 7 | #include "../common/matlab_utils.hpp" 8 | 9 | #include 10 | 11 | std::vector points = { 12 | {0,0}, 13 | {0.2,0.4}, 14 | {0.9,0.4}, 15 | {1,1} 16 | }; 17 | 18 | TEST(Interpolation, BezierTest) { 19 | 20 | std::cerr << std::endl; 21 | std::cout << std::endl; 22 | 23 | auto spline = dehancer::spline::Bezier(points); 24 | 25 | matlab::utils::print(spline,1); 26 | } 27 | 28 | 29 | TEST(Interpolation, BezierWithControlTest) { 30 | 31 | std::cerr << std::endl; 32 | std::cout << std::endl; 33 | 34 | auto spline = dehancer::spline::Bezier(); 35 | 36 | spline.controls = points; 37 | 38 | matlab::utils::print(spline,2); 39 | } -------------------------------------------------------------------------------- /tests/bspline/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set (TEST bspline-test) 2 | include(../CMakeCommon.in) -------------------------------------------------------------------------------- /tests/bspline/bspline_test.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by denn nevera on 2019-09-06. 3 | // 4 | 5 | #include "gtest/gtest.h" 6 | #include "dehancer/math.hpp" 7 | #include "../common/matlab_utils.hpp" 8 | 9 | #include 10 | 11 | std::vector points = { 12 | // {0,0}, 13 | // {0.1,0.2}, 14 | // {0.2,0.4}, 15 | // {0.5,0.7}, 16 | // {0.9,0.5}, 17 | // {1,0.3} 18 | 19 | // {0, 0}, 20 | // {0, 0}, 21 | // {0.8, 0.4}, 22 | // //{0.9, 0.9}, 23 | // {0.95, 0.95}, 24 | // {1, 1}, 25 | // {1, 1} 26 | 27 | // {0, 0}, 28 | // {0, 0}, 29 | // {0.01, 0.01}, 30 | // {0.2, 0.35}, 31 | // {1, 1}, 32 | // {1, 1} 33 | 34 | // {0, 0}, 35 | // {0, 0}, 36 | // {0.8, 0.45}, 37 | // {0.99, 0.80}, 38 | // {1, 0.81} 39 | 40 | // 41 | // {0, 0.02}, 42 | // {0, 0.02}, 43 | // {0.01, 0.05}, 44 | // {0.2, 0.4}, 45 | // {1, 1}, 46 | // {1, 1} 47 | // 48 | // {0.0, 0.20}, 49 | // {0.0, 0.20}, 50 | // {0.1, 0.50}, 51 | // {1.0, 1.0}, 52 | // {1.0, 1.0}, 53 | 54 | // {0, 0}, 55 | // {0, 0}, 56 | // {0.9, 0.40}, 57 | // {1.0, 0.75}, 58 | // {1.0, 0.75} 59 | // 60 | 61 | // {0.0, 0.35}, 62 | // {0.0, 0.35}, 63 | // {0.1, 0.55}, 64 | // {1.0, 1.0}, 65 | // {1.0, 1.0}, 66 | 67 | 68 | {0, 0}, 69 | {0, 0}, 70 | {0.85, 0.30}, 71 | {1.0, 0.75}, 72 | {1.0, 0.75} 73 | 74 | }; 75 | 76 | class ExposureSpline: public dehancer::spline::CatmulRom { 77 | public: 78 | public: 79 | using dehancer::spline::CatmulRom::CatmulRom; 80 | ExposureSpline(const std::vector& controls) : 81 | dehancer::spline::CatmulRom(controls, 256, 0.33) {} 82 | }; 83 | 84 | 85 | TEST(Interpolation, CatmulRomTest) { 86 | 87 | std::cerr << std::endl; 88 | std::cout << std::endl; 89 | 90 | auto spline = ExposureSpline(points); 91 | 92 | matlab::utils::print(spline,1); 93 | } 94 | -------------------------------------------------------------------------------- /tests/catmulrom/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set (TEST catmul-rom-test) 2 | include(../CMakeCommon.in) -------------------------------------------------------------------------------- /tests/catmulrom/catmulrom.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by denn nevera on 2019-09-06. 3 | // 4 | 5 | #include "gtest/gtest.h" 6 | #include "dehancer/math.hpp" 7 | #include "../common/matlab_utils.hpp" 8 | 9 | #include 10 | 11 | std::vector points = { 12 | // {0,0}, 13 | // {0.1,0.2}, 14 | // {0.2,0.4}, 15 | // {0.5,0.7}, 16 | // {0.9,0.5}, 17 | // {1,0.3} 18 | 19 | // {0, 0}, 20 | // {0.8, 0.6}, 21 | // {0.95, 0.95}, 22 | // {1, 1} 23 | 24 | {0, 0}, 25 | {0.01, 0.01}, 26 | {0.02, 0.02}, 27 | {0.2, 0.35}, 28 | {0.8, 0.8}, 29 | {0.9, 0.9}, 30 | {0.99, 0.99}, 31 | {1, 1} 32 | 33 | }; 34 | 35 | class ExposureCatmulRom: public dehancer::spline::CatmulRom { 36 | public: 37 | public: 38 | using dehancer::spline::CatmulRom::CatmulRom; 39 | ExposureCatmulRom(const std::vector& controls) : 40 | dehancer::spline::CatmulRom(controls,256,0.7) {} 41 | }; 42 | 43 | 44 | TEST(Interpolation, CatmulRomTest) { 45 | 46 | std::cerr << std::endl; 47 | std::cout << std::endl; 48 | 49 | auto spline = ExposureCatmulRom(points); 50 | 51 | matlab::utils::print(spline,1); 52 | } 53 | -------------------------------------------------------------------------------- /tests/common/matlab_utils.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by denn nevera on 2019-09-06. 3 | // 4 | 5 | #pragma once 6 | 7 | #include "dehancer/interpolator.hpp" 8 | 9 | namespace matlab { 10 | namespace utils { 11 | static inline void print(const dehancer::math::protocol::Interpolator& spline, int figure = 1) { 12 | 13 | std::cout << std::endl; 14 | 15 | std::cout << "% matlab script there: " << std::endl; 16 | std::cout << "x = ["; 17 | for (size_t i = 0; i <= spline.resolution; ++i) { 18 | auto x = (float)i*spline.step; 19 | std::cout << " " << x; 20 | } 21 | std::cout << "];" << std::endl; 22 | 23 | std::cout << "y = ["; 24 | for (size_t i = 0; i <= spline.resolution; ++i) { 25 | auto x = (float)i*spline.step; 26 | std::cout << " " << spline.value(x); 27 | } 28 | std::cout << "];" << std::endl; 29 | std::cout << "figure("<& spline, int figure = 1) { 34 | 35 | std::cout << std::endl; 36 | 37 | std::cout << "% matlab script there: " << std::endl; 38 | std::cout << "x = ["; 39 | for (auto xy: spline) { 40 | std::cout << " " << xy.x(); 41 | } 42 | std::cout << "];" << std::endl; 43 | 44 | std::cout << "y = ["; 45 | for (auto xy: spline) { 46 | std::cout << " " << xy.y(); 47 | } 48 | std::cout << "];" << std::endl; 49 | std::cout << "figure("<& spline, int figure = 1) { 54 | 55 | if (spline.size()<1) 56 | return; 57 | 58 | std::cout << std::endl; 59 | 60 | std::cout << "% matlab script there: " << std::endl; 61 | std::cout << "x = ["; 62 | 63 | auto step = float(1.0/float(spline.size()-1)); 64 | for (size_t i = 0; i < spline.size(); ++i) { 65 | std::cout << " " << i*step; 66 | } 67 | std::cout << "];" << std::endl; 68 | 69 | std::cout << "y = ["; 70 | for (auto y: spline) { 71 | std::cout << " " << y; 72 | } 73 | std::cout << "];" << std::endl; 74 | std::cout << "figure("< 11 | 12 | std::vector points = { 13 | {0,0}, 14 | {0.1,0.2}, 15 | {0.2,0.4}, 16 | {0.5,0.7}, 17 | {0.9,0.5}, 18 | {1,0.3} 19 | }; 20 | 21 | std::vector points2 = { 22 | {0,0}, 23 | {0.1,0.2}, 24 | {0.5,0.5}, 25 | {0.9,0.5}, 26 | {1,1} 27 | }; 28 | 29 | TEST(Interpolation, CubicSplineTest) { 30 | 31 | std::cerr << std::endl; 32 | std::cout << std::endl; 33 | 34 | auto spline = dehancer::spline::Cubic(); 35 | 36 | spline.controls = points; 37 | 38 | matlab::utils::print(spline,1); 39 | 40 | spline.controls = points2; 41 | 42 | matlab::utils::print(spline,2); 43 | 44 | } 45 | -------------------------------------------------------------------------------- /tests/initial/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set (TEST initial-test) 2 | include(../CMakeCommon.in) -------------------------------------------------------------------------------- /tests/initial/initial.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by denn nevera on 2019-08-15. 3 | // 4 | 5 | #include "gtest/gtest.h" 6 | #include "dehancer/math.hpp" 7 | #include "../common/matlab_utils.hpp" 8 | #include 9 | 10 | std::vector points = { 11 | {0,0}, 12 | {0.1,0.2}, 13 | {0.2,0.4}, 14 | {0.5,0.7}, 15 | {0.9,0.5}, 16 | {1,0.3} 17 | }; 18 | 19 | TEST(Initial, IitialTest) { 20 | 21 | std::cerr << std::endl; 22 | std::cout << std::endl; 23 | 24 | std::cout << "Armadillo version: " << arma::arma_version::as_string() << std::endl; 25 | 26 | dehancer::observable::Array array; 27 | 28 | array.on_update = [](const std::vector &vector) { 29 | std::cout << vector << std::endl; 30 | }; 31 | 32 | array[0] = {1, 42}; 33 | array[0] = {42, 1}; 34 | 35 | arma::mat A = {{1, 3}, 36 | {2, 4}}; 37 | 38 | arma::mat B = {{5, 6}, 39 | {7, 8}}; 40 | 41 | auto x = arma::solve(A, B); 42 | 43 | std::cout << "Armadillo equation solution: \n" << x << std::endl; 44 | 45 | auto invA = arma::inv(A); 46 | auto xx = invA * B; 47 | 48 | std::cout << "Armadillo equation inv solution: \n" << xx << "\n < \n" << (xx == x) << std::endl; 49 | 50 | dehancer::math::float2 f = {1, 2}; 51 | 52 | f.x() = 10; 53 | f.y() /= 2 + f.y(); 54 | std::cout << "Armadillo vector: \n" << f.t() << std::endl; 55 | 56 | auto a = f.t() * A; 57 | 58 | std::cout << "Armadillo multiple: \n" << a << std::endl; 59 | 60 | dehancer::math::float3 f3 = {1, 2, 1}; 61 | 62 | f3.x() = 2; 63 | f3.y() = 1; 64 | 65 | std::cout << "Armadillo f3: \n" << f3 << std::endl; 66 | 67 | auto a3x3 = f3 * f3.t(); 68 | 69 | std::cout << "Armadillo multiple 3x3: \n" << a3x3 << std::endl; 70 | } -------------------------------------------------------------------------------- /tests/interpolator/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set (TEST interpolator-test) 2 | include(../CMakeCommon.in) -------------------------------------------------------------------------------- /tests/interpolator/interpolator.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by denn nevera on 2019-09-01. 3 | // 4 | 5 | #include "gtest/gtest.h" 6 | #include "dehancer/math.hpp" 7 | #include "../common/matlab_utils.hpp" 8 | #include 9 | 10 | dehancer::spline::Linear spline; 11 | 12 | TEST(Interpolation, LinearTest) { 13 | 14 | std::cerr << std::endl; 15 | std::cout << std::endl; 16 | 17 | std::cout << "Armadillo version: " << arma::arma_version::as_string() << std::endl; 18 | 19 | spline.controls = {{0,0},{0.1,0.2},{0.2,0.3},{0.3,0.4}, {0.5,0.7}, {0.8,0.8} ,{1,0.1}}; 20 | 21 | spline.controls[1] = {0.1,0.25}; 22 | 23 | std::cout << "Controls: \n" << spline.controls << std::endl; 24 | 25 | std::cout << "Test bounds: " << spline.test_bounds(0.5).value_or(-100) << std::endl; 26 | 27 | matlab::utils::print(spline, 1); 28 | 29 | 30 | } 31 | 32 | TEST(Interpolation, UtilsTest) { 33 | 34 | auto spline2 = dehancer::spline::make(spline.controls, 256); 35 | 36 | matlab::utils::print(spline2, 2); 37 | 38 | auto curve = dehancer::curve::make(spline.controls, 256); 39 | 40 | matlab::utils::print(curve, 3); 41 | } 42 | 43 | TEST(Interpolation, CubicUtilsTest) { 44 | 45 | auto curve1 = dehancer::spline::make(spline.controls, 256, 2); 46 | 47 | matlab::utils::print(curve1, 4); 48 | 49 | auto curve2 = dehancer::curve::make(spline.controls, 256, 1); 50 | 51 | matlab::utils::print(curve2, 5); 52 | } 53 | 54 | TEST(Interpolation, CatmulRomUtilsTest) { 55 | 56 | auto curve1 = dehancer::spline::make(spline.controls, 256, 0.2); 57 | 58 | matlab::utils::print(curve1, 6); 59 | 60 | auto curve2 = dehancer::curve::make(spline.controls, 256, 0.9); 61 | 62 | matlab::utils::print(curve2, 7); 63 | } -------------------------------------------------------------------------------- /tests/vector/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set (TEST vector-test) 2 | include(../CMakeCommon.in) -------------------------------------------------------------------------------- /tests/vector/vector.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by denn nevera on 2019-09-05. 3 | // 4 | 5 | #include "gtest/gtest.h" 6 | #include "dehancer/math.hpp" 7 | #include 8 | 9 | TEST(Initial, VectorFloat2Test) { 10 | 11 | std::cerr << std::endl; 12 | std::cout << std::endl; 13 | 14 | std::cout << "Armadillo version: " << arma::arma_version::as_string() << std::endl; 15 | 16 | auto v = dehancer::math::float2({1,2}); 17 | 18 | std::cout << "\nfloat2:" << std::endl; 19 | std::cout << v << std::endl; 20 | 21 | v.y() = 10; 22 | v.y = 11; 23 | 24 | std::cout << v.y() << std::endl; 25 | std::cout << v.y - v.x << std::endl; 26 | } 27 | 28 | TEST(Initial, VectorFloat3Test) { 29 | 30 | std::cerr << std::endl; 31 | std::cout << std::endl; 32 | 33 | std::cout << "Armadillo version: " << arma::arma_version::as_string() << std::endl; 34 | 35 | auto v = dehancer::math::float3({1,2,3}); 36 | 37 | std::cout << "\nfloat3:" << std::endl; 38 | std::cout << v << std::endl; 39 | 40 | v.y() = 10; 41 | v.y = 11; 42 | v.z() = 1; 43 | v.z = 3; 44 | 45 | std::cout << v.y() << std::endl; 46 | std::cout << v.y - v.x - v.z << std::endl; 47 | 48 | } 49 | 50 | TEST(Initial, VectorFloat4Test) { 51 | 52 | std::cerr << std::endl; 53 | std::cout << std::endl; 54 | 55 | std::cout << "Armadillo version: " << arma::arma_version::as_string() << std::endl; 56 | 57 | auto v = dehancer::math::float4({1,2,3,4}); 58 | 59 | std::cout << "\nfloat4:" << std::endl; 60 | std::cout << v << std::endl; 61 | 62 | v.y() = 10; 63 | v.y = 11; 64 | v.z() = 1; 65 | v.z = 3; 66 | v.w() = 1; 67 | v.w = 4; 68 | 69 | std::cout << v.y() << std::endl; 70 | std::cout << v.y - v.x - v.z - v.w << std::endl; 71 | 72 | std::cout <<"dot " << arma::dot(arma::eps(v - v), dehancer::math::float4(arma::fill::ones) ) << std::endl; 73 | 74 | } 75 | -------------------------------------------------------------------------------- /version.txt: -------------------------------------------------------------------------------- 1 | dehancer_maths_cpp 0.12.0 --------------------------------------------------------------------------------