3rdParty: Add FastSignals library.
This commit is contained in:
102
src/3rdParty/FastSignals/.clang-format
vendored
Normal file
102
src/3rdParty/FastSignals/.clang-format
vendored
Normal file
@@ -0,0 +1,102 @@
|
||||
---
|
||||
Language: Cpp
|
||||
# BasedOnStyle: WebKit
|
||||
AccessModifierOffset: -4
|
||||
AlignAfterOpenBracket: DontAlign
|
||||
AlignConsecutiveAssignments: false
|
||||
AlignConsecutiveDeclarations: false
|
||||
AlignEscapedNewlinesLeft: false
|
||||
AlignOperands: false
|
||||
AlignTrailingComments: false
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
AllowShortBlocksOnASingleLine: false
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: All
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: false
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
BraceWrapping:
|
||||
AfterClass: true
|
||||
AfterControlStatement: true
|
||||
AfterEnum: true
|
||||
AfterFunction: true
|
||||
AfterNamespace: true
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: true
|
||||
AfterUnion: true
|
||||
BeforeCatch: true
|
||||
BeforeElse: true
|
||||
IndentBraces: false
|
||||
BreakBeforeBinaryOperators: All
|
||||
BreakBeforeBraces: Custom
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializersBeforeComma: true
|
||||
BreakAfterJavaFieldAnnotations: false
|
||||
BreakStringLiterals: true
|
||||
ColumnLimit: 0
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
BreakBeforeInheritanceComma: true
|
||||
FixNamespaceComments: true
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: false
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
# FixNamespaceComments: false
|
||||
ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
|
||||
IncludeCategories:
|
||||
- Regex: '^"(stdafx|PrecompiledHeader)'
|
||||
Priority: -2
|
||||
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
|
||||
Priority: 4
|
||||
- Regex: '^(<|"(gtest|isl|json)/)'
|
||||
Priority: 3
|
||||
- Regex: '.*'
|
||||
Priority: 2
|
||||
IncludeIsMainRegex: '$'
|
||||
IndentCaseLabels: false
|
||||
IndentWidth: 4
|
||||
IndentWrappedFunctionNames: false
|
||||
JavaScriptQuotes: Leave
|
||||
JavaScriptWrapImports: true
|
||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||
MacroBlockBegin: 'BEGIN_MESSAGE_MAP_CUSTOM$|BEGIN_MSG_MAP$|BEGIN_SINK_MAP$|BEGIN_MESSAGE_MAP$|BOOST_FIXTURE_TEST_SUITE$|BOOST_AUTO_TEST_SUITE$|BEGIN_DLGRESIZE_MAP$|BEGIN_MSG_MAP_EX$|BEGIN_DDX_MAP$|BEGIN_COM_MAP$|BEGIN_CONNECTION_POINT_MAP$|WTL_BEGIN_LAYOUT_MAP$|WTL_BEGIN_LAYOUT_CONTAINER$'
|
||||
MacroBlockEnd: 'END_MESSAGE_MAP_CUSTOM$|END_MSG_MAP$|END_SINK_MAP$|END_MESSAGE_MAP$|BOOST_AUTO_TEST_SUITE_END$|END_DLGRESIZE_MAP$|END_DDX_MAP$|END_COM_MAP$|END_CONNECTION_POINT_MAP$|WTL_END_LAYOUT_MAP$|WTL_END_LAYOUT_CONTAINER$'
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: None
|
||||
ObjCBlockIndentWidth: 4
|
||||
ObjCSpaceAfterProperty: true
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
PenaltyBreakBeforeFirstCallParameter: 19
|
||||
PenaltyBreakComment: 300
|
||||
PenaltyBreakFirstLessLess: 120
|
||||
PenaltyBreakString: 1000
|
||||
PenaltyExcessCharacter: 100
|
||||
PenaltyReturnTypeOnItsOwnLine: 10000000
|
||||
PointerAlignment: Left
|
||||
ReflowComments: true
|
||||
SortIncludes: true
|
||||
SortUsingDeclarations: true
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterTemplateKeyword: true
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 1
|
||||
SpacesInAngles: false
|
||||
SpacesInContainerLiterals: true
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: Cpp11
|
||||
TabWidth: 4
|
||||
UseTab: Always
|
||||
IndentPPDirectives: AfterHash
|
||||
...
|
||||
367
src/3rdParty/FastSignals/.gitignore
vendored
Normal file
367
src/3rdParty/FastSignals/.gitignore
vendored
Normal file
@@ -0,0 +1,367 @@
|
||||
# Prerequisites
|
||||
*.d
|
||||
|
||||
# Compiled Object files
|
||||
*.slo
|
||||
*.lo
|
||||
*.o
|
||||
*.obj
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Compiled Dynamic libraries
|
||||
*.so
|
||||
*.dylib
|
||||
*.dll
|
||||
|
||||
# Fortran module files
|
||||
*.mod
|
||||
*.smod
|
||||
|
||||
# Compiled Static libraries
|
||||
*.lai
|
||||
*.la
|
||||
*.a
|
||||
*.lib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
##
|
||||
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||
|
||||
# User-specific files
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
|
||||
# Visual Studio 2015/2017 cache/options directory
|
||||
.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
|
||||
# Visual Studio 2017 auto generated files
|
||||
Generated\ Files/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
# NUNIT
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
|
||||
# Build Results of an ATL Project
|
||||
[Dd]ebugPS/
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
# Benchmark Results
|
||||
BenchmarkDotNet.Artifacts/
|
||||
|
||||
# .NET Core
|
||||
project.lock.json
|
||||
project.fragment.lock.json
|
||||
artifacts/
|
||||
|
||||
# StyleCop
|
||||
StyleCopReport.xml
|
||||
|
||||
# Files built by Visual Studio
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_i.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.iobj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.ipdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*.log
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Chutzpah Test files
|
||||
_Chutzpah*
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opendb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
*.VC.db
|
||||
*.VC.VC.opendb
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
*.sap
|
||||
|
||||
# Visual Studio Trace Files
|
||||
*.e2e
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# JustCode is a .NET coding add-in
|
||||
.JustCode
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# AxoCover is a Code Coverage Tool
|
||||
.axoCover/*
|
||||
!.axoCover/settings.json
|
||||
|
||||
# Visual Studio code coverage results
|
||||
*.coverage
|
||||
*.coveragexml
|
||||
|
||||
# NCrunch
|
||||
_NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
nCrunchTemp_*
|
||||
|
||||
# MightyMoose
|
||||
*.mm.*
|
||||
AutoTest.Net/
|
||||
|
||||
# Web workbench (sass)
|
||||
.sass-cache/
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||
# in these scripts will be unencrypted
|
||||
PublishScripts/
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/[Pp]ackages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/[Pp]ackages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/[Pp]ackages/repositories.config
|
||||
# NuGet v3's project.json files produces more ignorable files
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# Microsoft Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Microsoft Azure Emulator
|
||||
ecf/
|
||||
rcf/
|
||||
|
||||
# Windows Store app package directories and files
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
Package.StoreAssociation.xml
|
||||
_pkginfo.txt
|
||||
*.appx
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!*.[Cc]ache/
|
||||
|
||||
# Others
|
||||
ClientBin/
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.jfm
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
orleans.codegen.cs
|
||||
|
||||
# Including strong name files can present a security risk
|
||||
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||
#*.snk
|
||||
|
||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||
#bower_components/
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file
|
||||
# to a newer Visual Studio version. Backup files are not needed,
|
||||
# because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
ServiceFabricBackup/
|
||||
*.rptproj.bak
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
*.ndf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
*.rptproj.rsuser
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# GhostDoc plugin setting file
|
||||
*.GhostDoc.xml
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
node_modules/
|
||||
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||
*.vbw
|
||||
|
||||
# Visual Studio LightSwitch build output
|
||||
**/*.HTMLClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/ModelManifest.xml
|
||||
**/*.Server/GeneratedArtifacts
|
||||
**/*.Server/ModelManifest.xml
|
||||
_Pvt_Extensions
|
||||
|
||||
# Paket dependency manager
|
||||
.paket/paket.exe
|
||||
paket-files/
|
||||
|
||||
# FAKE - F# Make
|
||||
.fake/
|
||||
|
||||
# JetBrains Rider
|
||||
.idea/
|
||||
*.sln.iml
|
||||
|
||||
# CodeRush
|
||||
.cr/
|
||||
|
||||
# Python Tools for Visual Studio (PTVS)
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
# Cake - Uncomment if you are using it
|
||||
# tools/**
|
||||
# !tools/packages.config
|
||||
|
||||
# Tabs Studio
|
||||
*.tss
|
||||
|
||||
# Telerik's JustMock configuration file
|
||||
*.jmconfig
|
||||
|
||||
# BizTalk build output
|
||||
*.btp.cs
|
||||
*.btm.cs
|
||||
*.odx.cs
|
||||
*.xsd.cs
|
||||
|
||||
# OpenCover UI analysis results
|
||||
OpenCover/
|
||||
|
||||
# Azure Stream Analytics local run output
|
||||
ASALocalRun/
|
||||
|
||||
# MSBuild Binary and Structured Log
|
||||
*.binlog
|
||||
|
||||
# NVidia Nsight GPU debugger configuration file
|
||||
*.nvuser
|
||||
|
||||
# MFractors (Xamarin productivity tool) working folder
|
||||
.mfractor/
|
||||
|
||||
# ------------
|
||||
# Custom Rules
|
||||
|
||||
build/
|
||||
27
src/3rdParty/FastSignals/.travis.yml
vendored
Normal file
27
src/3rdParty/FastSignals/.travis.yml
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
dist: trusty
|
||||
sudo: required
|
||||
language: cpp
|
||||
|
||||
os:
|
||||
- linux
|
||||
|
||||
compiler:
|
||||
- gcc
|
||||
# TODO: - clang
|
||||
|
||||
env:
|
||||
- TARGET_CPU=amd64 BUILD_CONFIGURATION=Release CI_NAME=TRAVIS
|
||||
# TODO: - TARGET_CPU=x86 BUILD_CONFIGURATION=Release
|
||||
|
||||
before_install:
|
||||
# build environment setup script
|
||||
- source build/travis-install-env-$TRAVIS_OS_NAME.sh
|
||||
|
||||
script:
|
||||
# Build project
|
||||
- mkdir -p build && cd build
|
||||
- cmake .. -DCMAKE_BUILD_TYPE=$BUILD_CONFIGURATION -DTARGET_CPU=$TARGET_CPU -DBUILD_TESTING=ON
|
||||
- cmake --build .
|
||||
|
||||
# Run tests
|
||||
- tests/libfastsignals_unit_tests/libfastsignals_unit_tests
|
||||
25
src/3rdParty/FastSignals/CMakeLists.txt
vendored
Normal file
25
src/3rdParty/FastSignals/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
cmake_minimum_required(VERSION 3.8 FATAL_ERROR)
|
||||
|
||||
project(FastSignals)
|
||||
|
||||
# Use `-DBUILD_TESTING=OFF` to disable testing/benchmarking.
|
||||
enable_testing()
|
||||
|
||||
include(cmake/functions.cmake)
|
||||
|
||||
add_subdirectory(libfastsignals)
|
||||
|
||||
if(BUILD_TESTING)
|
||||
# add_subdirectory(tests/benchmark)
|
||||
# add_subdirectory(tests/libfastsignals_bench)
|
||||
#add_subdirectory(tests/libfastsignals_stress_tests)
|
||||
add_subdirectory(tests/libfastsignals_unit_tests)
|
||||
endif()
|
||||
|
||||
# Trace variables, both environment and internal.
|
||||
execute_process(COMMAND "${CMAKE_COMMAND}" "-E" "environment")
|
||||
get_cmake_property(_variableNames VARIABLES)
|
||||
list (SORT _variableNames)
|
||||
foreach (_variableName ${_variableNames})
|
||||
message(STATUS "${_variableName}=${${_variableName}}")
|
||||
endforeach()
|
||||
57
src/3rdParty/FastSignals/FastSignals.sln
vendored
Normal file
57
src/3rdParty/FastSignals/FastSignals.sln
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.27703.2035
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libfastsignals", "libfastsignals\libfastsignals.vcxproj", "{32BD918F-EDBC-4057-A033-10DC361DA4A0}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libfastsignals_unit_tests", "tests\libfastsignals_unit_tests\libfastsignals_unit_tests.vcxproj", "{BAC23A51-8DC1-4589-940F-9923D8E12718}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{6BBDE9AD-AF40-4DDF-8DA6-BEAD0A204033}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libfastsignals_stress_tests", "tests\libfastsignals_stress_tests\libfastsignals_stress_tests.vcxproj", "{751DC150-1907-4D9F-8566-AA4E24FDFA64}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{32BD918F-EDBC-4057-A033-10DC361DA4A0}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{32BD918F-EDBC-4057-A033-10DC361DA4A0}.Debug|x64.Build.0 = Debug|x64
|
||||
{32BD918F-EDBC-4057-A033-10DC361DA4A0}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{32BD918F-EDBC-4057-A033-10DC361DA4A0}.Debug|x86.Build.0 = Debug|Win32
|
||||
{32BD918F-EDBC-4057-A033-10DC361DA4A0}.Release|x64.ActiveCfg = Release|x64
|
||||
{32BD918F-EDBC-4057-A033-10DC361DA4A0}.Release|x64.Build.0 = Release|x64
|
||||
{32BD918F-EDBC-4057-A033-10DC361DA4A0}.Release|x86.ActiveCfg = Release|Win32
|
||||
{32BD918F-EDBC-4057-A033-10DC361DA4A0}.Release|x86.Build.0 = Release|Win32
|
||||
{BAC23A51-8DC1-4589-940F-9923D8E12718}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{BAC23A51-8DC1-4589-940F-9923D8E12718}.Debug|x64.Build.0 = Debug|x64
|
||||
{BAC23A51-8DC1-4589-940F-9923D8E12718}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{BAC23A51-8DC1-4589-940F-9923D8E12718}.Debug|x86.Build.0 = Debug|Win32
|
||||
{BAC23A51-8DC1-4589-940F-9923D8E12718}.Release|x64.ActiveCfg = Release|x64
|
||||
{BAC23A51-8DC1-4589-940F-9923D8E12718}.Release|x64.Build.0 = Release|x64
|
||||
{BAC23A51-8DC1-4589-940F-9923D8E12718}.Release|x86.ActiveCfg = Release|Win32
|
||||
{BAC23A51-8DC1-4589-940F-9923D8E12718}.Release|x86.Build.0 = Release|Win32
|
||||
{751DC150-1907-4D9F-8566-AA4E24FDFA64}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{751DC150-1907-4D9F-8566-AA4E24FDFA64}.Debug|x64.Build.0 = Debug|x64
|
||||
{751DC150-1907-4D9F-8566-AA4E24FDFA64}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{751DC150-1907-4D9F-8566-AA4E24FDFA64}.Debug|x86.Build.0 = Debug|Win32
|
||||
{751DC150-1907-4D9F-8566-AA4E24FDFA64}.Release|x64.ActiveCfg = Release|x64
|
||||
{751DC150-1907-4D9F-8566-AA4E24FDFA64}.Release|x64.Build.0 = Release|x64
|
||||
{751DC150-1907-4D9F-8566-AA4E24FDFA64}.Release|x86.ActiveCfg = Release|Win32
|
||||
{751DC150-1907-4D9F-8566-AA4E24FDFA64}.Release|x86.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{BAC23A51-8DC1-4589-940F-9923D8E12718} = {6BBDE9AD-AF40-4DDF-8DA6-BEAD0A204033}
|
||||
{751DC150-1907-4D9F-8566-AA4E24FDFA64} = {6BBDE9AD-AF40-4DDF-8DA6-BEAD0A204033}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {12A1931D-508E-41C2-BAC6-B68CC62A710E}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
21
src/3rdParty/FastSignals/LICENSE
vendored
Normal file
21
src/3rdParty/FastSignals/LICENSE
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018 iSpring Solutions Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
17
src/3rdParty/FastSignals/README.md
vendored
Normal file
17
src/3rdParty/FastSignals/README.md
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
# FastSignals
|
||||
|
||||
Yet another C++ signals and slots library
|
||||
|
||||
* Works as drop-in replacement for Boost.Signals2 with the same API
|
||||
* Has better performance and more compact binary code
|
||||
* Thread-safe in most operations, including concurrent connects/disconnects/emits
|
||||
* Implemented with compact, pure C++17 code
|
||||
|
||||
[](https://travis-ci.org/ispringteam/FastSignals)
|
||||
[](https://opensource.org/licenses/MIT)
|
||||
|
||||
## Documentation
|
||||
|
||||
* [Why FastSignals?](docs/why-fastsignals.md)
|
||||
* [Simple Examples](docs/simple-examples.md)
|
||||
* [Migration from Boost.Signals2](docs/migration-from-boost-signals2.md)
|
||||
22
src/3rdParty/FastSignals/build/travis-install-env-linux.sh
vendored
Normal file
22
src/3rdParty/FastSignals/build/travis-install-env-linux.sh
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
|
||||
# install GCC
|
||||
sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
|
||||
sudo apt-get update -qq
|
||||
sudo apt-get install -qq g++-8
|
||||
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-8 90
|
||||
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-8 90
|
||||
sudo update-alternatives --install /usr/bin/cpp cpp /usr/bin/cpp-8 90
|
||||
g++ --version
|
||||
|
||||
# install cmake
|
||||
CMAKE_VERSION=3.12.1
|
||||
CMAKE_VERSION_DIR=v3.12
|
||||
CMAKE_OS=Linux-x86_64
|
||||
CMAKE_TAR=cmake-$CMAKE_VERSION-$CMAKE_OS.tar.gz
|
||||
CMAKE_URL=http://www.cmake.org/files/$CMAKE_VERSION_DIR/$CMAKE_TAR
|
||||
CMAKE_DIR=$(pwd)/cmake-$CMAKE_VERSION
|
||||
wget --quiet $CMAKE_URL
|
||||
mkdir -p $CMAKE_DIR
|
||||
tar --strip-components=1 -xzf $CMAKE_TAR -C $CMAKE_DIR
|
||||
export PATH=$CMAKE_DIR/bin:$PATH
|
||||
cmake --version
|
||||
39
src/3rdParty/FastSignals/cmake/functions.cmake
vendored
Normal file
39
src/3rdParty/FastSignals/cmake/functions.cmake
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
# В текущей версии CMake не может включить режим C++17 в некоторых компиляторах.
|
||||
# Функция использует обходной манёвр.
|
||||
function(custom_enable_cxx17 TARGET)
|
||||
# Включаем C++17 везде, где CMake может.
|
||||
target_compile_features(${TARGET} PUBLIC cxx_std_17)
|
||||
# Включаем режим C++latest в Visual Studio
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
|
||||
set_target_properties(${TARGET} PROPERTIES COMPILE_FLAGS "/std:c++latest")
|
||||
# Включаем компоновку с libc++, libc++experimental и pthread для Clang
|
||||
elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
set_target_properties(${TARGET} PROPERTIES COMPILE_FLAGS "-stdlib=libc++ -pthread")
|
||||
target_link_libraries(${TARGET} c++experimental pthread)
|
||||
endif()
|
||||
endfunction(custom_enable_cxx17)
|
||||
|
||||
# Функция добавляет цель-библиотеку.
|
||||
function(custom_add_library_from_dir TARGET)
|
||||
# Собираем файлы с текущего каталога
|
||||
file(GLOB TARGET_SRC "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/*.h")
|
||||
add_library(${TARGET} ${TARGET_SRC})
|
||||
endfunction()
|
||||
|
||||
# Функция добавляет цель исполняемого файла.
|
||||
function(custom_add_executable_from_dir TARGET)
|
||||
# Собираем файлы с текущего каталога
|
||||
file(GLOB TARGET_SRC "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/*.h")
|
||||
add_executable(${TARGET} ${TARGET_SRC})
|
||||
endfunction()
|
||||
|
||||
# Функция добавляет цель исполняемого файла, содержащего тесты библиотеки.
|
||||
function(custom_add_test_from_dir TARGET LIBRARY)
|
||||
custom_add_executable_from_dir(${TARGET})
|
||||
# Добавляем путь к заголовку фреймворка Catch
|
||||
target_include_directories(${TARGET} PRIVATE "${CMAKE_SOURCE_DIR}/libs/catch")
|
||||
# Добавляем компоновку с проверяемой библиотекой
|
||||
target_link_libraries(${TARGET} ${LIBRARY})
|
||||
# Регистрируем исполняемый файл в CMake как набор тестов.
|
||||
add_test(${TARGET} ${TARGET})
|
||||
endfunction()
|
||||
94
src/3rdParty/FastSignals/docs/bind_weak.md
vendored
Normal file
94
src/3rdParty/FastSignals/docs/bind_weak.md
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
# Function bind_weak
|
||||
|
||||
## Usage
|
||||
|
||||
* Use `is::signals::bind_weak` instead of `std::bind` to ensure that nothing happens if method called when binded object already destroyed
|
||||
* Pass pointer to T class method as first argument, `shared_ptr<T>` or `weak_ptr<T>` as second argument
|
||||
* Example: `bind_weak(&Document::save(), document, std::placeholders::_1)`, where `document` is a `weak_ptr<Document>` or `shared_ptr<Document>`
|
||||
|
||||
## Weak this idiom
|
||||
|
||||
The `is::signals::bind_weak(...)` function implements "weak this" idiom. This idiom helps to avoid dangling pointers and memory access wiolations in asynchronous and/or multithreaded programs.
|
||||
|
||||
In the following example, we use weak this idiom to avoid using dangling pointer wehn calling `print()` method of the `Enityt`:
|
||||
|
||||
```cpp
|
||||
struct Entity : std::enable_shared_from_this<Entity>
|
||||
{
|
||||
int value = 42;
|
||||
|
||||
void print()
|
||||
{
|
||||
std::cout << "print called, num = " << value << std::endl;
|
||||
}
|
||||
|
||||
std::function<void()> print_later()
|
||||
{
|
||||
// ! weak this idiom here !
|
||||
auto weak_this = weak_from_this();
|
||||
return [weak_this] {
|
||||
if (auto shared_this = weak_this.lock())
|
||||
{
|
||||
shared_this->print();
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
auto entity = std::make_shared<Entity>();
|
||||
auto print = entity->print_later();
|
||||
|
||||
// Prints OK.
|
||||
print();
|
||||
|
||||
// Prints nothing - last shared_ptr to the Entity destroyed, so `weak_this.lock()` will return nullptr.
|
||||
entity = nullptr;
|
||||
print();
|
||||
}
|
||||
```
|
||||
|
||||
## Using bind_weak to avoid signal receiver lifetime issues
|
||||
|
||||
In the following example, `Entity::print()` method connected to the signal. Signal emmited once before and once after the `Entity` instance destroyed. However, no memory access violation happens: once `Entity` destoryed, no slot will be called because `bind_weak` doesn't call binded method if it cannot lock `std::weak_ptr` to binded object. The second `event()` expression just does nothing.
|
||||
|
||||
```cpp
|
||||
#include "fastsignals/signal.h"
|
||||
#include "fastsignals/bind_weak.h"
|
||||
#include <iostream>
|
||||
|
||||
using VoidSignal = is::signals::signal<void()>;
|
||||
using VoidSlot = VoidSignal::slot_type;
|
||||
|
||||
struct Entity : std::enable_shared_from_this<Entity>
|
||||
{
|
||||
int value = 42;
|
||||
|
||||
VoidSlot get_print_slot()
|
||||
{
|
||||
// Here is::signals::bind_weak() used instead of std::bind.
|
||||
return is::signals::bind_weak(&Entity::print, weak_from_this());
|
||||
}
|
||||
|
||||
void print()
|
||||
{
|
||||
std::cout << "print called, num = " << value << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
VoidSignal event;
|
||||
auto entity = std::make_shared<Entity>();
|
||||
event.connect(entity->get_print_slot());
|
||||
|
||||
// Here slot called - it prints `slot called, num = 42`
|
||||
event();
|
||||
entity = nullptr;
|
||||
|
||||
// Here nothing happens - no exception, no slot call.
|
||||
event();
|
||||
}
|
||||
|
||||
```
|
||||
163
src/3rdParty/FastSignals/docs/migration-from-boost-signals2.md
vendored
Normal file
163
src/3rdParty/FastSignals/docs/migration-from-boost-signals2.md
vendored
Normal file
@@ -0,0 +1,163 @@
|
||||
# Migration from Boost.Signals2
|
||||
|
||||
This guide helps to migrate large codebase from Boost.Signals2 to `FastSignals` signals/slots library. It helps to solve known migration issues in the right way.
|
||||
|
||||
During migrations, you will probably face with following things:
|
||||
|
||||
* You code uses `boost::signals2::` namespace and `<boost/signals2.hpp>` header directly
|
||||
* You code uses third-party headers included implicitly by the `<boost/signals2.hpp>` header
|
||||
|
||||
## Reasons migrate from Boost.Signals2 to FastSignals
|
||||
|
||||
FastSignals API mostly compatible with Boost.Signals2 - there are differences, and all differences has their reasons explained below.
|
||||
|
||||
Comparing to Boost.Signals2, FastSignals has following pros:
|
||||
|
||||
* FastSignals is not header-only - so binary code will be more compact
|
||||
* FastSignals implemented using C++17 with variadic templates, `constexpr if` and other modern metaprogramming techniques - so it compiles faster and, again, binary code will be more compact
|
||||
* FastSignals probably will faster than Boost.Signals2 for your codebase because with FastSignals you don't pay for things that you don't use, with one exception: you always pay for the multithreading support
|
||||
|
||||
## Step 1: Create header with aliases
|
||||
|
||||
## Step 2: Rebuild and fix compile errors
|
||||
|
||||
### 2.1 Add missing includes
|
||||
|
||||
Boost.Signals2 is header-only library. It includes a lot of STL/Boost stuff while FastSignals does not:
|
||||
|
||||
```cpp
|
||||
#include <boost/signals2.hpp>
|
||||
// Also includes std::map, boost::variant, boost::optional, etc.
|
||||
|
||||
// Compiled OK even without `#include <map>`!
|
||||
std::map CreateMyMap();
|
||||
```
|
||||
|
||||
With FastSignals, you must include headers like `<map>` manually. The following table shows which files should be included explicitly if you see compile erros after migration.
|
||||
|
||||
| Class | Header |
|
||||
|--------------------|:--------------------------------------:|
|
||||
| std::map | `#include <map>` |
|
||||
| boost::variant | `#include <boost/variant/variant.hpp>` |
|
||||
| boost::optional | `#include <boost/optional/optional.hpp>` |
|
||||
| boost::scoped_ptr | `#include <boost/scoped_ptr.hpp>` |
|
||||
| boost::noncopyable | `#include <boost/noncopyable.hpp>` |
|
||||
| boost::bind | `#include <boost/bind.hpp>` |
|
||||
| boost::function | `#include <boost/function.hpp>` |
|
||||
|
||||
If you just want to compile you code, you can add following includes in you `signals.h` header:
|
||||
|
||||
```cpp
|
||||
// WARNING: [libfastsignals] we do not recommend to include following extra headers.
|
||||
#include <map>
|
||||
#include <boost/variant/variant.hpp>
|
||||
#include <boost/optional/optional.hpp>
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/function.hpp>
|
||||
```
|
||||
|
||||
### 2.2 Remove redundant returns for void signals
|
||||
|
||||
With Boost.Signals2, following code compiled without any warning:
|
||||
|
||||
```cpp
|
||||
boost::signals2::signal<void()> event;
|
||||
event.connect([] {
|
||||
return true;
|
||||
});
|
||||
```
|
||||
|
||||
With FastSignals, slot cannot return non-void value when for `signal<void(...)>`. You must fix your code: just remove returns from your slots or add lambdas to wrap slot and ignore it result.
|
||||
|
||||
### 2.3 Replace track() and track_foreign() with bind_weak_ptr()
|
||||
|
||||
Boost.Signals2 [can track connected objects lifetype](https://www.boost.org/doc/libs/1_55_0/doc/html/signals2/tutorial.html#idp204830936) using `track(...)` and `track_foreign(...)` methods. In the following example `Entity` created with `make_shared`, and `Entity::get_print_slot()` creates slot function which tracks weak pointer to Entity:
|
||||
|
||||
```cpp
|
||||
#include <boost/signals2.hpp>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
|
||||
using VoidSignal = boost::signals2::signal<void()>;
|
||||
using VoidSlot = VoidSignal::slot_type;
|
||||
|
||||
struct Entity : std::enable_shared_from_this<Entity>
|
||||
{
|
||||
int value = 42;
|
||||
|
||||
VoidSlot get_print_slot()
|
||||
{
|
||||
// Here track() tracks object itself.
|
||||
return VoidSlot(std::bind(&Entity::print, this)).track_foreign(shared_from_this());
|
||||
}
|
||||
|
||||
void print()
|
||||
{
|
||||
std::cout << "print called, num = " << value << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
VoidSignal event;
|
||||
auto entity = std::make_shared<Entity>();
|
||||
event.connect(entity->get_print_slot());
|
||||
|
||||
// Here slot called - it prints `print called, num = 42`
|
||||
event();
|
||||
entity = nullptr;
|
||||
|
||||
// This call does nothing.
|
||||
event();
|
||||
}
|
||||
```
|
||||
|
||||
FastSignals uses another approach: `bind_weak` function:
|
||||
|
||||
```cpp
|
||||
#include "fastsignals/bind_weak.h"
|
||||
#include <iostream>
|
||||
|
||||
using VoidSignal = is::signals::signal<void()>;
|
||||
using VoidSlot = VoidSignal::slot_type;
|
||||
|
||||
struct Entity : std::enable_shared_from_this<Entity>
|
||||
{
|
||||
int value = 42;
|
||||
|
||||
VoidSlot get_print_slot()
|
||||
{
|
||||
// Here is::signals::bind_weak() used instead of std::bind.
|
||||
return is::signals::bind_weak(&Entity::print, weak_from_this());
|
||||
}
|
||||
|
||||
void print()
|
||||
{
|
||||
std::cout << "print called, num = " << value << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
VoidSignal event;
|
||||
auto entity = std::make_shared<Entity>();
|
||||
event.connect(entity->get_print_slot());
|
||||
|
||||
// Here slot called - it prints `slot called, num = 42`
|
||||
event();
|
||||
entity = nullptr;
|
||||
|
||||
// Here nothing happens - no exception, no slot call.
|
||||
event();
|
||||
}
|
||||
```
|
||||
|
||||
### FastSignals Differences in Result Combiners
|
||||
|
||||
## Step 3: Run Tests
|
||||
|
||||
Run all automated tests that you have (unit tests, integration tests, system tests, stress tests, benchmarks, UI tests).
|
||||
|
||||
Probably you will see no errors. If you see any, please report an issue.
|
||||
55
src/3rdParty/FastSignals/docs/simple-examples.md
vendored
Normal file
55
src/3rdParty/FastSignals/docs/simple-examples.md
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
# Simple Examples
|
||||
|
||||
>If you are not familar with Boost.Signals2, please read [Boost.Signals2: Connections](https://theboostcpplibraries.com/boost.signals2-connections)
|
||||
|
||||
## Example with signal<> and connection
|
||||
|
||||
```cpp
|
||||
// Creates signal and connects 1 slot, calls 2 times, disconnects, calls again.
|
||||
// Outputs:
|
||||
// 13
|
||||
// 17
|
||||
#include "libfastsignals/signal.h"
|
||||
|
||||
using namespace is::signals;
|
||||
|
||||
int main()
|
||||
{
|
||||
signal<void(int)> valueChanged;
|
||||
connection conn;
|
||||
conn = valueChanged.connect([](int value) {
|
||||
cout << value << endl;
|
||||
});
|
||||
valueChanged(13);
|
||||
valueChanged(17);
|
||||
conn.disconnect();
|
||||
valueChanged(42);
|
||||
}
|
||||
```
|
||||
|
||||
## Example with scoped_connection
|
||||
|
||||
```cpp
|
||||
// Creates signal and connects 1 slot, calls 2 times, calls again after scoped_connection destroyed.
|
||||
// - note: scoped_connection closes connection in destructor
|
||||
// Outputs:
|
||||
// 13
|
||||
// 17
|
||||
#include "libfastsignals/signal.h"
|
||||
|
||||
using namespace is::signals;
|
||||
|
||||
int main()
|
||||
{
|
||||
signal<void(int)> valueChanged;
|
||||
{
|
||||
scoped_connection conn;
|
||||
conn = valueChanged.connect([](int value) {
|
||||
cout << value << endl;
|
||||
});
|
||||
valueChanged(13);
|
||||
valueChanged(17);
|
||||
}
|
||||
valueChanged(42);
|
||||
}
|
||||
```
|
||||
40
src/3rdParty/FastSignals/docs/why-fastsignals.md
vendored
Normal file
40
src/3rdParty/FastSignals/docs/why-fastsignals.md
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
# Why FastSignals?
|
||||
|
||||
FastSignals is a C++17 signals/slots implementation which API is compatible with Boost.Signals2.
|
||||
|
||||
FastSignals pros:
|
||||
|
||||
* Faster than Boost.Signals2
|
||||
* Has more compact binary code
|
||||
* Has the same API as Boost.Signals2
|
||||
|
||||
FastSignals cons:
|
||||
|
||||
* Supports only C++17 compatible compilers: Visual Studio 2017, modern Clang, modern GCC
|
||||
* Lacks a few rarely used features presented in Boost.Signals2
|
||||
* No access to connection from slot with `signal::connect_extended` method
|
||||
* No connected object tracking with `slot::track` method
|
||||
* Use [bind_weak](bind_weak.md) instead
|
||||
* No temporary signal blocking with `shared_connection_block` class
|
||||
* Cannot disconnect equivalent slots since no `disconnect(slot)` function overload
|
||||
* Any other API difference is a bug - please report it!
|
||||
|
||||
See also [Migration from Boost.Signals2](migration-from-boost-signals2.md).
|
||||
|
||||
## Benchmark results
|
||||
|
||||
Directory `tests/libfastsignals_bench` contains simple benchmark with compares two signal/slot implementations:
|
||||
|
||||
* Boost.Signals2
|
||||
* libfastsignals
|
||||
|
||||
Benchmark compairs performance when signal emitted frequently with 0, 1 and 8 active connections. In these cases libfastsignals is 3-6 times faster.
|
||||
|
||||
```
|
||||
*** Results:
|
||||
measure emit_boost emit_fastsignals
|
||||
emit_boost/0 1.00 3.00
|
||||
emit_boost/1 1.00 5.76
|
||||
emit_boost/8 1.00 3.70
|
||||
***
|
||||
```
|
||||
5
src/3rdParty/FastSignals/libfastsignals/CMakeLists.txt
vendored
Normal file
5
src/3rdParty/FastSignals/libfastsignals/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
|
||||
file(GLOB LIBFASTSIGNALS_SRC "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/include/*.h")
|
||||
add_library(libfastsignals ${LIBFASTSIGNALS_SRC})
|
||||
custom_enable_cxx17(libfastsignals)
|
||||
target_include_directories(libfastsignals INTERFACE "${CMAKE_SOURCE_DIR}")
|
||||
75
src/3rdParty/FastSignals/libfastsignals/include/bind_weak.h
vendored
Normal file
75
src/3rdParty/FastSignals/libfastsignals/include/bind_weak.h
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
#pragma once
|
||||
|
||||
namespace is::signals
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
template <class ReturnType, class ClassType, bool AddConst, class... Args>
|
||||
struct weak_binder
|
||||
{
|
||||
using ConstMethodType = ReturnType (ClassType::*)(Args... args) const;
|
||||
using NonConstMethodType = ReturnType (ClassType::*)(Args... args);
|
||||
using MethodType = std::conditional_t<AddConst, ConstMethodType, NonConstMethodType>;
|
||||
using WeakPtrType = std::weak_ptr<ClassType>;
|
||||
|
||||
weak_binder(MethodType pMethod, WeakPtrType&& pObject)
|
||||
: m_pMethod(pMethod)
|
||||
, m_pObject(pObject)
|
||||
{
|
||||
}
|
||||
|
||||
ReturnType operator()(Args... args) const
|
||||
{
|
||||
if (auto pThis = m_pObject.lock())
|
||||
{
|
||||
return (pThis.get()->*m_pMethod)(std::forward<Args>(args)...);
|
||||
}
|
||||
return ReturnType();
|
||||
}
|
||||
|
||||
MethodType m_pMethod;
|
||||
WeakPtrType m_pObject;
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
/// Weak this binding of non-const methods.
|
||||
template <typename ReturnType, typename ClassType, typename... Params, typename... Args>
|
||||
decltype(auto) bind_weak(ReturnType (ClassType::*memberFn)(Params... args), std::shared_ptr<ClassType> const& pThis, Args... args)
|
||||
{
|
||||
using weak_binder_alias = detail::weak_binder<ReturnType, ClassType, false, Params...>;
|
||||
|
||||
weak_binder_alias invoker(memberFn, std::weak_ptr<ClassType>(pThis));
|
||||
return std::bind(invoker, args...);
|
||||
}
|
||||
|
||||
/// Weak this binding of const methods.
|
||||
template <typename ReturnType, typename ClassType, typename... Params, typename... Args>
|
||||
decltype(auto) bind_weak(ReturnType (ClassType::*memberFn)(Params... args) const, std::shared_ptr<ClassType> const& pThis, Args... args)
|
||||
{
|
||||
using weak_binder_alias = detail::weak_binder<ReturnType, ClassType, true, Params...>;
|
||||
|
||||
weak_binder_alias invoker(memberFn, std::weak_ptr<ClassType>(pThis));
|
||||
return std::bind(invoker, args...);
|
||||
}
|
||||
|
||||
/// Weak this binding of non-const methods.
|
||||
template <typename ReturnType, typename ClassType, typename... Params, typename... Args>
|
||||
decltype(auto) bind_weak(ReturnType (ClassType::*memberFn)(Params... args), std::weak_ptr<ClassType> pThis, Args... args)
|
||||
{
|
||||
using weak_binder_alias = detail::weak_binder<ReturnType, ClassType, false, Params...>;
|
||||
|
||||
weak_binder_alias invoker(memberFn, std::move(pThis));
|
||||
return std::bind(invoker, args...);
|
||||
}
|
||||
|
||||
/// Weak this binding of const methods.
|
||||
template <typename ReturnType, typename ClassType, typename... Params, typename... Args>
|
||||
decltype(auto) bind_weak(ReturnType (ClassType::*memberFn)(Params... args) const, std::weak_ptr<ClassType> pThis, Args... args)
|
||||
{
|
||||
using weak_binder_alias = detail::weak_binder<ReturnType, ClassType, true, Params...>;
|
||||
|
||||
weak_binder_alias invoker(memberFn, std::move(pThis));
|
||||
return std::bind(invoker, args...);
|
||||
}
|
||||
|
||||
} // namespace is::signals
|
||||
40
src/3rdParty/FastSignals/libfastsignals/include/combiners.h
vendored
Normal file
40
src/3rdParty/FastSignals/libfastsignals/include/combiners.h
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
|
||||
namespace is::signals
|
||||
{
|
||||
|
||||
/**
|
||||
* This results combiner reduces results collection into last value of this collection.
|
||||
* In other words, it keeps only result of the last slot call.
|
||||
*/
|
||||
template <class T>
|
||||
class optional_last_value
|
||||
{
|
||||
public:
|
||||
using result_type = std::optional<T>;
|
||||
|
||||
template <class TRef>
|
||||
void operator()(TRef&& value)
|
||||
{
|
||||
m_result = std::forward<TRef>(value);
|
||||
}
|
||||
|
||||
result_type get_value() const
|
||||
{
|
||||
return m_result;
|
||||
}
|
||||
|
||||
private:
|
||||
result_type m_result = {};
|
||||
};
|
||||
|
||||
template <>
|
||||
class optional_last_value<void>
|
||||
{
|
||||
public:
|
||||
using result_type = void;
|
||||
};
|
||||
|
||||
} // namespace is::signals
|
||||
114
src/3rdParty/FastSignals/libfastsignals/include/connection.h
vendored
Normal file
114
src/3rdParty/FastSignals/libfastsignals/include/connection.h
vendored
Normal file
@@ -0,0 +1,114 @@
|
||||
#pragma once
|
||||
|
||||
#include "signal_impl.h"
|
||||
|
||||
namespace is::signals
|
||||
{
|
||||
|
||||
// Connection keeps link between signal and slot and can disconnect them.
|
||||
// Disconnect operation is thread-safe: any thread can disconnect while
|
||||
// slots called on other thread.
|
||||
// This class itself is not thread-safe: you can't use the same connection
|
||||
// object from different threads at the same time.
|
||||
class connection
|
||||
{
|
||||
public:
|
||||
connection() noexcept;
|
||||
explicit connection(detail::signal_impl_weak_ptr storage, uint64_t id) noexcept;
|
||||
connection(const connection& other) noexcept;
|
||||
connection& operator=(const connection& other) noexcept;
|
||||
connection(connection&& other) noexcept;
|
||||
connection& operator=(connection&& other) noexcept;
|
||||
|
||||
bool connected() const noexcept;
|
||||
void disconnect() noexcept;
|
||||
|
||||
protected:
|
||||
detail::signal_impl_weak_ptr m_storage;
|
||||
uint64_t m_id = 0;
|
||||
};
|
||||
|
||||
// Connection class that supports blocking callback execution
|
||||
class advanced_connection : public connection
|
||||
{
|
||||
public:
|
||||
struct advanced_connection_impl
|
||||
{
|
||||
void block() noexcept;
|
||||
void unblock() noexcept;
|
||||
bool is_blocked() const noexcept;
|
||||
|
||||
private:
|
||||
std::atomic<int> m_blockCounter = ATOMIC_VAR_INIT(0);
|
||||
};
|
||||
using impl_ptr = std::shared_ptr<advanced_connection_impl>;
|
||||
|
||||
advanced_connection() noexcept;
|
||||
explicit advanced_connection(connection&& conn, impl_ptr&& impl) noexcept;
|
||||
advanced_connection(const advanced_connection&) noexcept;
|
||||
advanced_connection& operator=(const advanced_connection&) noexcept;
|
||||
advanced_connection(advanced_connection&& other) noexcept;
|
||||
advanced_connection& operator=(advanced_connection&& other) noexcept;
|
||||
|
||||
protected:
|
||||
impl_ptr m_impl;
|
||||
};
|
||||
|
||||
// Blocks advanced connection, so its callback will not be executed
|
||||
class shared_connection_block
|
||||
{
|
||||
public:
|
||||
shared_connection_block(const advanced_connection& connection = advanced_connection(), bool initially_blocked = true) noexcept;
|
||||
shared_connection_block(const shared_connection_block& other) noexcept;
|
||||
shared_connection_block(shared_connection_block&& other) noexcept;
|
||||
shared_connection_block& operator=(const shared_connection_block& other) noexcept;
|
||||
shared_connection_block& operator=(shared_connection_block&& other) noexcept;
|
||||
~shared_connection_block();
|
||||
|
||||
void block() noexcept;
|
||||
void unblock() noexcept;
|
||||
bool blocking() const noexcept;
|
||||
|
||||
private:
|
||||
void increment_if_blocked() const noexcept;
|
||||
|
||||
std::weak_ptr<advanced_connection::advanced_connection_impl> m_connection;
|
||||
std::atomic<bool> m_blocked = ATOMIC_VAR_INIT(false);
|
||||
};
|
||||
|
||||
// Scoped connection keeps link between signal and slot and disconnects them in destructor.
|
||||
// Scoped connection is movable, but not copyable.
|
||||
class scoped_connection : public connection
|
||||
{
|
||||
public:
|
||||
scoped_connection() noexcept;
|
||||
scoped_connection(const connection& conn) noexcept;
|
||||
scoped_connection(connection&& conn) noexcept;
|
||||
scoped_connection(const advanced_connection& conn) = delete;
|
||||
scoped_connection(advanced_connection&& conn) noexcept = delete;
|
||||
scoped_connection(const scoped_connection&) = delete;
|
||||
scoped_connection& operator=(const scoped_connection&) = delete;
|
||||
scoped_connection(scoped_connection&& other) noexcept;
|
||||
scoped_connection& operator=(scoped_connection&& other) noexcept;
|
||||
~scoped_connection();
|
||||
|
||||
connection release() noexcept;
|
||||
};
|
||||
|
||||
// scoped connection for advanced connections
|
||||
class advanced_scoped_connection : public advanced_connection
|
||||
{
|
||||
public:
|
||||
advanced_scoped_connection() noexcept;
|
||||
advanced_scoped_connection(const advanced_connection& conn) noexcept;
|
||||
advanced_scoped_connection(advanced_connection&& conn) noexcept;
|
||||
advanced_scoped_connection(const advanced_scoped_connection&) = delete;
|
||||
advanced_scoped_connection& operator=(const advanced_scoped_connection&) = delete;
|
||||
advanced_scoped_connection(advanced_scoped_connection&& other) noexcept;
|
||||
advanced_scoped_connection& operator=(advanced_scoped_connection&& other) noexcept;
|
||||
~advanced_scoped_connection();
|
||||
|
||||
advanced_connection release() noexcept;
|
||||
};
|
||||
|
||||
} // namespace is::signals
|
||||
54
src/3rdParty/FastSignals/libfastsignals/include/function.h
vendored
Normal file
54
src/3rdParty/FastSignals/libfastsignals/include/function.h
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
#pragma once
|
||||
|
||||
#include "function_detail.h"
|
||||
|
||||
namespace is::signals
|
||||
{
|
||||
// Derive your class from not_directly_callable to prevent function from wrapping it using its template constructor
|
||||
// Useful if your class provides custom operator for casting to function
|
||||
struct not_directly_callable
|
||||
{
|
||||
};
|
||||
|
||||
template <class Fn, class Function, class Return, class... Arguments>
|
||||
using enable_if_callable_t = typename std::enable_if_t<
|
||||
!std::is_same_v<std::decay_t<Fn>, Function> && !std::is_base_of_v<not_directly_callable, std::decay_t<Fn>> && std::is_same_v<std::invoke_result_t<Fn, Arguments...>, Return>>;
|
||||
|
||||
template <class Signature>
|
||||
class function;
|
||||
|
||||
// Compact function class - causes minimal code bloat when compiled.
|
||||
// Replaces std::function in this library.
|
||||
template <class Return, class... Arguments>
|
||||
class function<Return(Arguments...)>
|
||||
{
|
||||
public:
|
||||
function() = default;
|
||||
|
||||
function(const function& other) = default;
|
||||
function(function&& other) noexcept = default;
|
||||
function& operator=(const function& other) = default;
|
||||
function& operator=(function&& other) noexcept = default;
|
||||
|
||||
template <class Fn, typename = enable_if_callable_t<Fn, function<Return(Arguments...)>, Return, Arguments...>>
|
||||
function(Fn&& function) noexcept(detail::is_noexcept_packed_function_init<Fn, Return, Arguments...>)
|
||||
{
|
||||
m_packed.init<Fn, Return, Arguments...>(std::forward<Fn>(function));
|
||||
}
|
||||
|
||||
Return operator()(Arguments&&... args) const
|
||||
{
|
||||
auto& proxy = m_packed.get<Return(Arguments...)>();
|
||||
return proxy(std::forward<Arguments>(args)...);
|
||||
}
|
||||
|
||||
detail::packed_function release() noexcept
|
||||
{
|
||||
return std::move(m_packed);
|
||||
}
|
||||
|
||||
private:
|
||||
detail::packed_function m_packed;
|
||||
};
|
||||
|
||||
} // namespace is::signals
|
||||
163
src/3rdParty/FastSignals/libfastsignals/include/function_detail.h
vendored
Normal file
163
src/3rdParty/FastSignals/libfastsignals/include/function_detail.h
vendored
Normal file
@@ -0,0 +1,163 @@
|
||||
#pragma once
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace is::signals::detail
|
||||
{
|
||||
/// Buffer for callable object in-place construction,
|
||||
/// helps to implement Small Buffer Optimization.
|
||||
static constexpr size_t inplace_buffer_size = (sizeof(int) == sizeof(void*) ? 8 : 6) * sizeof(void*);
|
||||
|
||||
/// Structure that has size enough to keep type "T" including vtable.
|
||||
template <class T>
|
||||
struct type_container
|
||||
{
|
||||
T data;
|
||||
};
|
||||
|
||||
/// Type that has enough space to keep type "T" (including vtable) with suitable alignment.
|
||||
using function_buffer_t = std::aligned_storage_t<inplace_buffer_size>;
|
||||
|
||||
/// Constantly is true if callable fits function buffer, false otherwise.
|
||||
template <class T>
|
||||
inline constexpr bool fits_inplace_buffer = (sizeof(type_container<T>) <= inplace_buffer_size);
|
||||
|
||||
// clang-format off
|
||||
/// Constantly is true if callable fits function buffer and can be safely moved, false otherwise
|
||||
template <class T>
|
||||
inline constexpr bool can_use_inplace_buffer =
|
||||
fits_inplace_buffer<T> &&
|
||||
std::is_nothrow_move_constructible_v<T>;
|
||||
// clang format on
|
||||
|
||||
/// Type that is suitable to keep copy of callable object.
|
||||
/// - equal to pointer-to-function if Callable is pointer-to-function
|
||||
/// - otherwise removes const/volatile and references to allow copying callable.
|
||||
template <class Callable>
|
||||
using callable_copy_t = std::conditional_t<std::is_function_v<std::remove_reference_t<Callable>>,
|
||||
Callable,
|
||||
std::remove_cv_t<std::remove_reference_t<Callable>>>;
|
||||
|
||||
class base_function_proxy
|
||||
{
|
||||
public:
|
||||
virtual ~base_function_proxy() = default;
|
||||
virtual base_function_proxy* clone(void* buffer) const = 0;
|
||||
virtual base_function_proxy* move(void* buffer) noexcept = 0;
|
||||
};
|
||||
|
||||
template <class Signature>
|
||||
class function_proxy;
|
||||
|
||||
template <class Return, class... Arguments>
|
||||
class function_proxy<Return(Arguments...)> : public base_function_proxy
|
||||
{
|
||||
public:
|
||||
virtual Return operator()(Arguments&&...) = 0;
|
||||
};
|
||||
|
||||
template <class Callable, class Return, class... Arguments>
|
||||
class function_proxy_impl final : public function_proxy<Return(Arguments...)>
|
||||
{
|
||||
public:
|
||||
// If you see this error, probably your function returns value and you're trying to
|
||||
// connect it to `signal<void(...)>`. Just remove return value from callback.
|
||||
static_assert(std::is_same_v<std::invoke_result_t<Callable, Arguments...>, Return>,
|
||||
"cannot construct function<> class from callable object with different return type");
|
||||
|
||||
template <class FunctionObject>
|
||||
explicit function_proxy_impl(FunctionObject&& function)
|
||||
: m_callable(std::forward<FunctionObject>(function))
|
||||
{
|
||||
}
|
||||
|
||||
Return operator()(Arguments&&... args) final
|
||||
{
|
||||
return m_callable(std::forward<Arguments>(args)...);
|
||||
}
|
||||
|
||||
base_function_proxy* clone(void* buffer) const final
|
||||
{
|
||||
if constexpr (can_use_inplace_buffer<function_proxy_impl>)
|
||||
{
|
||||
return new (buffer) function_proxy_impl(*this);
|
||||
}
|
||||
else
|
||||
{
|
||||
(void)buffer;
|
||||
return new function_proxy_impl(*this);
|
||||
}
|
||||
}
|
||||
|
||||
base_function_proxy* move(void* buffer) noexcept final
|
||||
{
|
||||
if constexpr (can_use_inplace_buffer<function_proxy_impl>)
|
||||
{
|
||||
base_function_proxy* moved = new (buffer) function_proxy_impl(std::move(*this));
|
||||
this->~function_proxy_impl();
|
||||
return moved;
|
||||
}
|
||||
else
|
||||
{
|
||||
(void)buffer;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
callable_copy_t<Callable> m_callable;
|
||||
};
|
||||
|
||||
template <class Fn, class Return, class... Arguments>
|
||||
inline constexpr bool is_noexcept_packed_function_init = can_use_inplace_buffer<function_proxy_impl<Fn, Return, Arguments...>>;
|
||||
|
||||
class packed_function final
|
||||
{
|
||||
public:
|
||||
packed_function() = default;
|
||||
packed_function(packed_function&& other) noexcept;
|
||||
packed_function(const packed_function& other);
|
||||
packed_function& operator=(packed_function&& other) noexcept;
|
||||
packed_function& operator=(const packed_function& other);
|
||||
~packed_function() noexcept;
|
||||
|
||||
// Initializes packed function.
|
||||
// Cannot be called without reset().
|
||||
template <class Callable, class Return, class... Arguments>
|
||||
void init(Callable&& function) noexcept(is_noexcept_packed_function_init<Callable, Return, Arguments...>)
|
||||
{
|
||||
using proxy_t = function_proxy_impl<Callable, Return, Arguments...>;
|
||||
|
||||
assert(m_proxy == nullptr);
|
||||
if constexpr (can_use_inplace_buffer<proxy_t>)
|
||||
{
|
||||
m_proxy = new (&m_buffer) proxy_t{ std::forward<Callable>(function) };
|
||||
}
|
||||
else
|
||||
{
|
||||
m_proxy = new proxy_t{ std::forward<Callable>(function) };
|
||||
}
|
||||
}
|
||||
|
||||
template <class Signature>
|
||||
function_proxy<Signature>& get() const
|
||||
{
|
||||
return static_cast<function_proxy<Signature>&>(unwrap());
|
||||
}
|
||||
|
||||
void reset() noexcept;
|
||||
|
||||
private:
|
||||
base_function_proxy* move_proxy_from(packed_function&& other) noexcept;
|
||||
base_function_proxy* clone_proxy_from(const packed_function &other);
|
||||
base_function_proxy& unwrap() const;
|
||||
bool is_buffer_allocated() const noexcept;
|
||||
|
||||
function_buffer_t m_buffer[1] = {};
|
||||
base_function_proxy* m_proxy = nullptr;
|
||||
};
|
||||
|
||||
} // namespace is::signals::detail
|
||||
31
src/3rdParty/FastSignals/libfastsignals/include/msvc_autolink.h
vendored
Normal file
31
src/3rdParty/FastSignals/libfastsignals/include/msvc_autolink.h
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
|
||||
# if defined(__clang__)
|
||||
# if defined(_DEBUG) && defined(_WIN64)
|
||||
# pragma comment(lib, "libfastsignalsd-llvm-x64.lib")
|
||||
# elif defined(_DEBUG)
|
||||
# pragma comment(lib, "libfastsignalsd-llvm-x32.lib")
|
||||
# elif defined(_WIN64)
|
||||
# pragma comment(lib, "libfastsignals-llvm-x64.lib")
|
||||
# else
|
||||
# pragma comment(lib, "libfastsignals-llvm-x32.lib")
|
||||
# endif
|
||||
# elif _MSC_VER <= 1900
|
||||
# error this library needs Visual Studio 2017 and higher
|
||||
# elif _MSC_VER < 2000
|
||||
# if defined(_DEBUG) && defined(_WIN64)
|
||||
# pragma comment(lib, "libfastsignalsd-v141-x64.lib")
|
||||
# elif defined(_DEBUG)
|
||||
# pragma comment(lib, "libfastsignalsd-v141-x32.lib")
|
||||
# elif defined(_WIN64)
|
||||
# pragma comment(lib, "libfastsignals-v141-x64.lib")
|
||||
# else
|
||||
# pragma comment(lib, "libfastsignals-v141-x32.lib")
|
||||
# endif
|
||||
# else
|
||||
# error unknown Visual Studio version, auto-linking setup failed
|
||||
# endif
|
||||
|
||||
#endif
|
||||
153
src/3rdParty/FastSignals/libfastsignals/include/signal.h
vendored
Normal file
153
src/3rdParty/FastSignals/libfastsignals/include/signal.h
vendored
Normal file
@@ -0,0 +1,153 @@
|
||||
#pragma once
|
||||
|
||||
#include "combiners.h"
|
||||
#include "connection.h"
|
||||
#include "function.h"
|
||||
#include "signal_impl.h"
|
||||
#include "type_traits.h"
|
||||
#include <type_traits>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# include "msvc_autolink.h"
|
||||
#endif
|
||||
|
||||
namespace is::signals
|
||||
{
|
||||
template <class Signature, template <class T> class Combiner = optional_last_value>
|
||||
class signal;
|
||||
|
||||
struct advanced_tag
|
||||
{
|
||||
};
|
||||
|
||||
/// Signal allows to fire events to many subscribers (slots).
|
||||
/// In other words, it implements one-to-many relation between event and listeners.
|
||||
/// Signal implements observable object from Observable pattern.
|
||||
template <class Return, class... Arguments, template <class T> class Combiner>
|
||||
class signal<Return(Arguments...), Combiner> : private not_directly_callable
|
||||
{
|
||||
public:
|
||||
using signature_type = Return(signal_arg_t<Arguments>...);
|
||||
using slot_type = function<signature_type>;
|
||||
using combiner_type = Combiner<Return>;
|
||||
using result_type = typename combiner_type::result_type;
|
||||
|
||||
signal()
|
||||
: m_slots(std::make_shared<detail::signal_impl>())
|
||||
{
|
||||
}
|
||||
|
||||
/// No copy construction
|
||||
signal(const signal&) = delete;
|
||||
|
||||
/// Moves signal from other. Any operations on other except destruction, move, and swap are invalid
|
||||
signal(signal&& other) = default;
|
||||
|
||||
/// No copy assignment
|
||||
signal& operator=(const signal&) = delete;
|
||||
|
||||
/// Moves signal from other. Any operations on other except destruction, move, and swap are invalid
|
||||
signal& operator=(signal&& other) = default;
|
||||
|
||||
/**
|
||||
* connect(slot) method subscribes slot to signal emission event.
|
||||
* Each time you call signal as functor, all slots are also called with given arguments.
|
||||
* @returns connection - object which manages signal-slot connection lifetime
|
||||
*/
|
||||
connection connect(slot_type slot)
|
||||
{
|
||||
const uint64_t id = m_slots->add(slot.release());
|
||||
return connection(m_slots, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* connect(slot, advanced_tag) method subscribes slot to signal emission event with the ability to temporarily block slot execution
|
||||
* Each time you call signal as functor, all non-blocked slots are also called with given arguments.
|
||||
* You can temporarily block slot execution using shared_connection_block
|
||||
* @returns advanced_connection - object which manages signal-slot connection lifetime
|
||||
*/
|
||||
advanced_connection connect(slot_type slot, advanced_tag)
|
||||
{
|
||||
static_assert(std::is_void_v<Return>, "Advanced connect can only be used with slots returning void (implementation limitation)");
|
||||
auto conn_impl = std::make_shared<advanced_connection::advanced_connection_impl>();
|
||||
slot_type slot_impl = [this, slot, weak_conn_impl = std::weak_ptr(conn_impl)](signal_arg_t<Arguments>... args) {
|
||||
auto conn_impl = weak_conn_impl.lock();
|
||||
if (!conn_impl || !conn_impl->is_blocked())
|
||||
{
|
||||
slot(args...);
|
||||
}
|
||||
};
|
||||
auto conn = connect(std::move(slot_impl));
|
||||
return advanced_connection(std::move(conn), std::move(conn_impl));
|
||||
}
|
||||
|
||||
/**
|
||||
* disconnect_all_slots() method disconnects all slots from signal emission event.
|
||||
*/
|
||||
void disconnect_all_slots() noexcept
|
||||
{
|
||||
m_slots->remove_all();
|
||||
}
|
||||
|
||||
/**
|
||||
* num_slots() method returns number of slots attached to this singal
|
||||
*/
|
||||
[[nodiscard]] std::size_t num_slots() const noexcept
|
||||
{
|
||||
return m_slots->count();
|
||||
}
|
||||
|
||||
/**
|
||||
* empty() method returns true if signal has any slots attached
|
||||
*/
|
||||
[[nodiscard]] bool empty() const noexcept
|
||||
{
|
||||
return m_slots->count() == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* operator(args...) calls all slots connected to this signal.
|
||||
* Logically, it fires signal emission event.
|
||||
*/
|
||||
result_type operator()(signal_arg_t<Arguments>... args) const
|
||||
{
|
||||
return detail::signal_impl_ptr(m_slots)->invoke<combiner_type, result_type, signature_type, signal_arg_t<Arguments>...>(args...);
|
||||
}
|
||||
|
||||
void swap(signal& other) noexcept
|
||||
{
|
||||
m_slots.swap(other.m_slots);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows using signals as slots for another signal
|
||||
*/
|
||||
operator slot_type() const noexcept
|
||||
{
|
||||
return [weakSlots = detail::signal_impl_weak_ptr(m_slots)](signal_arg_t<Arguments>... args) {
|
||||
if (auto slots = weakSlots.lock())
|
||||
{
|
||||
return slots->invoke<combiner_type, result_type, signature_type, signal_arg_t<Arguments>...>(args...);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private:
|
||||
detail::signal_impl_ptr m_slots;
|
||||
};
|
||||
|
||||
} // namespace is::signals
|
||||
|
||||
namespace std
|
||||
{
|
||||
|
||||
// free swap function, findable by ADL
|
||||
template <class Signature, template <class T> class Combiner>
|
||||
void swap(
|
||||
::is::signals::signal<Signature, Combiner>& sig1,
|
||||
::is::signals::signal<Signature, Combiner>& sig2)
|
||||
{
|
||||
sig1.swap(sig2);
|
||||
}
|
||||
|
||||
} // namespace std
|
||||
59
src/3rdParty/FastSignals/libfastsignals/include/signal_impl.h
vendored
Normal file
59
src/3rdParty/FastSignals/libfastsignals/include/signal_impl.h
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
#pragma once
|
||||
|
||||
#include "function_detail.h"
|
||||
#include "spin_mutex.h"
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace is::signals::detail
|
||||
{
|
||||
|
||||
class signal_impl
|
||||
{
|
||||
public:
|
||||
uint64_t add(packed_function fn);
|
||||
|
||||
void remove(uint64_t id) noexcept;
|
||||
|
||||
void remove_all() noexcept;
|
||||
|
||||
size_t count() const noexcept;
|
||||
|
||||
template <class Combiner, class Result, class Signature, class... Args>
|
||||
Result invoke(Args... args) const
|
||||
{
|
||||
packed_function slot;
|
||||
size_t slotIndex = 0;
|
||||
uint64_t slotId = 1;
|
||||
|
||||
if constexpr (std::is_same_v<Result, void>)
|
||||
{
|
||||
while (get_next_slot(slot, slotIndex, slotId))
|
||||
{
|
||||
slot.get<Signature>()(std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Combiner combiner;
|
||||
while (get_next_slot(slot, slotIndex, slotId))
|
||||
{
|
||||
combiner(slot.get<Signature>()(std::forward<Args>(args)...));
|
||||
}
|
||||
return combiner.get_value();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
bool get_next_slot(packed_function& slot, size_t& expectedIndex, uint64_t& nextId) const;
|
||||
|
||||
mutable spin_mutex m_mutex;
|
||||
std::vector<packed_function> m_functions;
|
||||
std::vector<uint64_t> m_ids;
|
||||
uint64_t m_nextId = 1;
|
||||
};
|
||||
|
||||
using signal_impl_ptr = std::shared_ptr<signal_impl>;
|
||||
using signal_impl_weak_ptr = std::weak_ptr<signal_impl>;
|
||||
|
||||
} // namespace is::signals::detail
|
||||
38
src/3rdParty/FastSignals/libfastsignals/include/spin_mutex.h
vendored
Normal file
38
src/3rdParty/FastSignals/libfastsignals/include/spin_mutex.h
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
#include <atomic>
|
||||
|
||||
namespace is::signals::detail
|
||||
{
|
||||
|
||||
class spin_mutex
|
||||
{
|
||||
public:
|
||||
spin_mutex() = default;
|
||||
spin_mutex(const spin_mutex&) = delete;
|
||||
spin_mutex& operator=(const spin_mutex&) = delete;
|
||||
spin_mutex(spin_mutex&&) = delete;
|
||||
spin_mutex& operator=(spin_mutex&&) = delete;
|
||||
|
||||
inline bool try_lock() noexcept
|
||||
{
|
||||
return !m_busy.test_and_set(std::memory_order_acquire);
|
||||
}
|
||||
|
||||
inline void lock() noexcept
|
||||
{
|
||||
while (!try_lock())
|
||||
{
|
||||
/* do nothing */;
|
||||
}
|
||||
}
|
||||
|
||||
inline void unlock() noexcept
|
||||
{
|
||||
m_busy.clear(std::memory_order_release);
|
||||
}
|
||||
|
||||
private:
|
||||
std::atomic_flag m_busy = ATOMIC_FLAG_INIT;
|
||||
};
|
||||
|
||||
} // namespace is::signals::detail
|
||||
24
src/3rdParty/FastSignals/libfastsignals/include/type_traits.h
vendored
Normal file
24
src/3rdParty/FastSignals/libfastsignals/include/type_traits.h
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
namespace is::signals
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template <typename T>
|
||||
struct signal_arg
|
||||
{
|
||||
using type = const T&;
|
||||
};
|
||||
|
||||
template <typename U>
|
||||
struct signal_arg<U&>
|
||||
{
|
||||
using type = U&;
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
template <typename T>
|
||||
using signal_arg_t = typename detail::signal_arg<T>::type;
|
||||
|
||||
} // namespace is::signals
|
||||
200
src/3rdParty/FastSignals/libfastsignals/libfastsignals.vcxproj
vendored
Normal file
200
src/3rdParty/FastSignals/libfastsignals/libfastsignals.vcxproj
vendored
Normal file
@@ -0,0 +1,200 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>15.0</VCProjectVersion>
|
||||
<ProjectGuid>{32BD918F-EDBC-4057-A033-10DC361DA4A0}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>FastSignals</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\libfastsignals_build_options.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\libfastsignals_build_options.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\libfastsignals_build_options.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\libfastsignals_build_options.props" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)build\bin\$(ProjectName)\$(Platform)\$(Configuration)\</OutDir>
|
||||
<IntDir>$(SolutionDir)build\tmp\$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
|
||||
<TargetName>$(ProjectName)$(DebugSuffixOpt)-$(PlatformToolset)$(PlatformSuffix)</TargetName>
|
||||
<RunCodeAnalysis>true</RunCodeAnalysis>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<IncludePath>$(SolutionDir)3rdparty;$(IncludePath)</IncludePath>
|
||||
<OutDir>$(SolutionDir)build\bin\$(ProjectName)\$(Platform)\$(Configuration)\</OutDir>
|
||||
<IntDir>$(SolutionDir)build\tmp\$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
|
||||
<TargetName>$(ProjectName)$(DebugSuffixOpt)-$(PlatformToolset)$(PlatformSuffix)</TargetName>
|
||||
<CodeAnalysisRuleSet>NativeRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
<RunCodeAnalysis>true</RunCodeAnalysis>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)build\bin\$(ProjectName)\$(Platform)\$(Configuration)\</OutDir>
|
||||
<IntDir>$(SolutionDir)build\tmp\$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
|
||||
<TargetName>$(ProjectName)$(DebugSuffixOpt)-$(PlatformToolset)$(PlatformSuffix)</TargetName>
|
||||
<RunCodeAnalysis>true</RunCodeAnalysis>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<IncludePath>$(SolutionDir)3rdparty;$(IncludePath)</IncludePath>
|
||||
<OutDir>$(SolutionDir)build\bin\$(ProjectName)\$(Platform)\$(Configuration)\</OutDir>
|
||||
<IntDir>$(SolutionDir)build\tmp\$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
|
||||
<TargetName>$(ProjectName)$(DebugSuffixOpt)-$(PlatformToolset)$(PlatformSuffix)</TargetName>
|
||||
<CodeAnalysisRuleSet>NativeRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
<RunCodeAnalysis>true</RunCodeAnalysis>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<EnablePREfast>true</EnablePREfast>
|
||||
<DisableSpecificWarnings>26495;26439;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<EnablePREfast>true</EnablePREfast>
|
||||
<DisableSpecificWarnings>26495;26439;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<EnablePREfast>true</EnablePREfast>
|
||||
<DisableSpecificWarnings>26495;26439;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<EnablePREfast>true</EnablePREfast>
|
||||
<DisableSpecificWarnings>26495;26439;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="include/combiners.h" />
|
||||
<ClInclude Include="include/connection.h" />
|
||||
<ClInclude Include="include/function.h" />
|
||||
<ClInclude Include="include/function_detail.h" />
|
||||
<ClInclude Include="include/signal.h" />
|
||||
<ClInclude Include="include/signal_impl.h" />
|
||||
<ClInclude Include="include/spin_mutex.h" />
|
||||
<ClInclude Include="include/type_traits.h" />
|
||||
<ClInclude Include="include\bind_weak.h" />
|
||||
<ClInclude Include="include\msvc_autolink.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\connection.cpp" />
|
||||
<ClCompile Include="src\function_detail.cpp" />
|
||||
<ClCompile Include="src\signal_impl.cpp" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
54
src/3rdParty/FastSignals/libfastsignals/libfastsignals.vcxproj.filters
vendored
Normal file
54
src/3rdParty/FastSignals/libfastsignals/libfastsignals.vcxproj.filters
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<ClInclude Include="include/combiners.h">
|
||||
<Filter>include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include/connection.h">
|
||||
<Filter>include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include/function.h">
|
||||
<Filter>include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include/function_detail.h">
|
||||
<Filter>include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include/signal.h">
|
||||
<Filter>include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include/signal_impl.h">
|
||||
<Filter>include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include/spin_mutex.h">
|
||||
<Filter>include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include/type_traits.h">
|
||||
<Filter>include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\msvc_autolink.h">
|
||||
<Filter>include</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\bind_weak.h">
|
||||
<Filter>include</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="include">
|
||||
<UniqueIdentifier>{474d3307-8dbe-47d6-a12f-35f944912d9d}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="src">
|
||||
<UniqueIdentifier>{ac074187-2f8f-44b9-a170-24568deb06e6}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\function_detail.cpp">
|
||||
<Filter>src</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\signal_impl.cpp">
|
||||
<Filter>src</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\connection.cpp">
|
||||
<Filter>src</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
251
src/3rdParty/FastSignals/libfastsignals/src/connection.cpp
vendored
Normal file
251
src/3rdParty/FastSignals/libfastsignals/src/connection.cpp
vendored
Normal file
@@ -0,0 +1,251 @@
|
||||
#include "../include/connection.h"
|
||||
|
||||
namespace is::signals
|
||||
{
|
||||
namespace
|
||||
{
|
||||
|
||||
auto get_advanced_connection_impl(const advanced_connection& connection) noexcept
|
||||
{
|
||||
struct advanced_connection_impl_getter : private advanced_connection
|
||||
{
|
||||
advanced_connection_impl_getter(const advanced_connection& connection) noexcept
|
||||
: advanced_connection(connection)
|
||||
{
|
||||
}
|
||||
using advanced_connection::m_impl;
|
||||
};
|
||||
return advanced_connection_impl_getter(connection).m_impl;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
connection::connection(connection&& other) noexcept
|
||||
: m_storage(other.m_storage)
|
||||
, m_id(other.m_id)
|
||||
{
|
||||
other.m_storage.reset();
|
||||
other.m_id = 0;
|
||||
}
|
||||
|
||||
connection::connection(detail::signal_impl_weak_ptr storage, uint64_t id) noexcept
|
||||
: m_storage(std::move(storage))
|
||||
, m_id(id)
|
||||
{
|
||||
}
|
||||
|
||||
connection::connection() noexcept = default;
|
||||
|
||||
connection::connection(const connection& other) noexcept = default;
|
||||
|
||||
connection& connection::operator=(connection&& other) noexcept
|
||||
{
|
||||
m_storage = other.m_storage;
|
||||
m_id = other.m_id;
|
||||
other.m_storage.reset();
|
||||
other.m_id = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
connection& connection::operator=(const connection& other) noexcept = default;
|
||||
|
||||
bool connection::connected() const noexcept
|
||||
{
|
||||
return (m_id != 0);
|
||||
}
|
||||
|
||||
void connection::disconnect() noexcept
|
||||
{
|
||||
if (auto storage = m_storage.lock())
|
||||
{
|
||||
storage->remove(m_id);
|
||||
m_storage.reset();
|
||||
}
|
||||
m_id = 0;
|
||||
}
|
||||
|
||||
scoped_connection::scoped_connection(connection&& conn) noexcept
|
||||
: connection(std::move(conn))
|
||||
{
|
||||
}
|
||||
|
||||
scoped_connection::scoped_connection(const connection& conn) noexcept
|
||||
: connection(conn)
|
||||
{
|
||||
}
|
||||
|
||||
scoped_connection::scoped_connection() noexcept = default;
|
||||
|
||||
scoped_connection::scoped_connection(scoped_connection&& other) noexcept = default;
|
||||
|
||||
scoped_connection& scoped_connection::operator=(scoped_connection&& other) noexcept
|
||||
{
|
||||
disconnect();
|
||||
static_cast<connection&>(*this) = std::move(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
scoped_connection::~scoped_connection()
|
||||
{
|
||||
disconnect();
|
||||
}
|
||||
|
||||
connection scoped_connection::release() noexcept
|
||||
{
|
||||
connection conn = std::move(static_cast<connection&>(*this));
|
||||
return conn;
|
||||
}
|
||||
|
||||
bool advanced_connection::advanced_connection_impl::is_blocked() const noexcept
|
||||
{
|
||||
return m_blockCounter.load(std::memory_order_acquire) != 0;
|
||||
}
|
||||
|
||||
void advanced_connection::advanced_connection_impl::block() noexcept
|
||||
{
|
||||
++m_blockCounter;
|
||||
}
|
||||
|
||||
void advanced_connection::advanced_connection_impl::unblock() noexcept
|
||||
{
|
||||
--m_blockCounter;
|
||||
}
|
||||
|
||||
advanced_connection::advanced_connection() noexcept = default;
|
||||
|
||||
advanced_connection::advanced_connection(connection&& conn, impl_ptr&& impl) noexcept
|
||||
: connection(std::move(conn))
|
||||
, m_impl(std::move(impl))
|
||||
{
|
||||
}
|
||||
|
||||
advanced_connection::advanced_connection(const advanced_connection&) noexcept = default;
|
||||
|
||||
advanced_connection::advanced_connection(advanced_connection&& other) noexcept = default;
|
||||
|
||||
advanced_connection& advanced_connection::operator=(const advanced_connection&) noexcept = default;
|
||||
|
||||
advanced_connection& advanced_connection::operator=(advanced_connection&& other) noexcept = default;
|
||||
|
||||
shared_connection_block::shared_connection_block(const advanced_connection& connection, bool initially_blocked) noexcept
|
||||
: m_connection(get_advanced_connection_impl(connection))
|
||||
{
|
||||
if (initially_blocked)
|
||||
{
|
||||
block();
|
||||
}
|
||||
}
|
||||
|
||||
shared_connection_block::shared_connection_block(const shared_connection_block& other) noexcept
|
||||
: m_connection(other.m_connection)
|
||||
, m_blocked(other.m_blocked.load(std::memory_order_acquire))
|
||||
{
|
||||
increment_if_blocked();
|
||||
}
|
||||
|
||||
shared_connection_block::shared_connection_block(shared_connection_block&& other) noexcept
|
||||
: m_connection(other.m_connection)
|
||||
, m_blocked(other.m_blocked.load(std::memory_order_acquire))
|
||||
{
|
||||
other.m_connection.reset();
|
||||
other.m_blocked.store(false, std::memory_order_release);
|
||||
}
|
||||
|
||||
shared_connection_block& shared_connection_block::operator=(const shared_connection_block& other) noexcept
|
||||
{
|
||||
if (&other != this)
|
||||
{
|
||||
unblock();
|
||||
m_connection = other.m_connection;
|
||||
m_blocked = other.m_blocked.load(std::memory_order_acquire);
|
||||
increment_if_blocked();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
shared_connection_block& shared_connection_block::operator=(shared_connection_block&& other) noexcept
|
||||
{
|
||||
if (&other != this)
|
||||
{
|
||||
unblock();
|
||||
m_connection = other.m_connection;
|
||||
m_blocked = other.m_blocked.load(std::memory_order_acquire);
|
||||
other.m_connection.reset();
|
||||
other.m_blocked.store(false, std::memory_order_release);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
shared_connection_block::~shared_connection_block()
|
||||
{
|
||||
unblock();
|
||||
}
|
||||
|
||||
void shared_connection_block::block() noexcept
|
||||
{
|
||||
bool blocked = false;
|
||||
if (m_blocked.compare_exchange_strong(blocked, true, std::memory_order_acq_rel, std::memory_order_relaxed))
|
||||
{
|
||||
if (auto connection = m_connection.lock())
|
||||
{
|
||||
connection->block();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void shared_connection_block::unblock() noexcept
|
||||
{
|
||||
bool blocked = true;
|
||||
if (m_blocked.compare_exchange_strong(blocked, false, std::memory_order_acq_rel, std::memory_order_relaxed))
|
||||
{
|
||||
if (auto connection = m_connection.lock())
|
||||
{
|
||||
connection->unblock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool shared_connection_block::blocking() const noexcept
|
||||
{
|
||||
return m_blocked;
|
||||
}
|
||||
|
||||
void shared_connection_block::increment_if_blocked() const noexcept
|
||||
{
|
||||
if (m_blocked)
|
||||
{
|
||||
if (auto connection = m_connection.lock())
|
||||
{
|
||||
connection->block();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
advanced_scoped_connection::advanced_scoped_connection() noexcept = default;
|
||||
|
||||
advanced_scoped_connection::advanced_scoped_connection(const advanced_connection& conn) noexcept
|
||||
: advanced_connection(conn)
|
||||
{
|
||||
}
|
||||
|
||||
advanced_scoped_connection::advanced_scoped_connection(advanced_connection&& conn) noexcept
|
||||
: advanced_connection(std::move(conn))
|
||||
{
|
||||
}
|
||||
|
||||
advanced_scoped_connection::advanced_scoped_connection(advanced_scoped_connection&& other) noexcept = default;
|
||||
|
||||
advanced_scoped_connection& advanced_scoped_connection::operator=(advanced_scoped_connection&& other) noexcept = default;
|
||||
|
||||
advanced_scoped_connection::~advanced_scoped_connection()
|
||||
{
|
||||
disconnect();
|
||||
}
|
||||
|
||||
advanced_connection advanced_scoped_connection::release() noexcept
|
||||
{
|
||||
advanced_connection conn = std::move(static_cast<advanced_connection&>(*this));
|
||||
return conn;
|
||||
}
|
||||
|
||||
} // namespace is::signals
|
||||
96
src/3rdParty/FastSignals/libfastsignals/src/function_detail.cpp
vendored
Normal file
96
src/3rdParty/FastSignals/libfastsignals/src/function_detail.cpp
vendored
Normal file
@@ -0,0 +1,96 @@
|
||||
#include "../include/function_detail.h"
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
|
||||
namespace is::signals::detail
|
||||
{
|
||||
|
||||
packed_function::packed_function(packed_function&& other) noexcept
|
||||
: m_proxy(move_proxy_from(std::move(other)))
|
||||
{
|
||||
}
|
||||
|
||||
packed_function::packed_function(const packed_function& other)
|
||||
: m_proxy(clone_proxy_from(other))
|
||||
{
|
||||
}
|
||||
|
||||
packed_function& packed_function::operator=(packed_function&& other) noexcept
|
||||
{
|
||||
assert(this != &other);
|
||||
reset();
|
||||
m_proxy = move_proxy_from(std::move(other));
|
||||
return *this;
|
||||
}
|
||||
|
||||
base_function_proxy* packed_function::move_proxy_from(packed_function&& other) noexcept
|
||||
{
|
||||
auto proxy = other.m_proxy ? other.m_proxy->move(&m_buffer) : nullptr;
|
||||
other.m_proxy = nullptr;
|
||||
return proxy;
|
||||
}
|
||||
|
||||
base_function_proxy* packed_function::clone_proxy_from(const packed_function& other)
|
||||
{
|
||||
return other.m_proxy ? other.m_proxy->clone(&m_buffer) : nullptr;
|
||||
}
|
||||
|
||||
packed_function& packed_function::operator=(const packed_function& other)
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
if (other.is_buffer_allocated() && is_buffer_allocated())
|
||||
{
|
||||
// "This" and "other" are using SBO. Safe assignment must use copy+move
|
||||
*this = packed_function(other);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Buffer is used either by "this" or by "other" or not used at all.
|
||||
// If this uses buffer then other's proxy is null or allocated on heap, so clone won't overwrite buffer
|
||||
// If this uses heap or null then other's proxy can safely use buffer because reset() won't access buffer
|
||||
auto newProxy = clone_proxy_from(other);
|
||||
reset();
|
||||
m_proxy = newProxy;
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
packed_function::~packed_function() noexcept
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
void packed_function::reset() noexcept
|
||||
{
|
||||
if (m_proxy != nullptr)
|
||||
{
|
||||
if (is_buffer_allocated())
|
||||
{
|
||||
m_proxy->~base_function_proxy();
|
||||
}
|
||||
else
|
||||
{
|
||||
delete m_proxy;
|
||||
}
|
||||
m_proxy = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
base_function_proxy& packed_function::unwrap() const
|
||||
{
|
||||
if (m_proxy == nullptr)
|
||||
{
|
||||
throw std::bad_function_call();
|
||||
}
|
||||
return *m_proxy;
|
||||
}
|
||||
|
||||
bool packed_function::is_buffer_allocated() const noexcept
|
||||
{
|
||||
return std::less_equal<const void*>()(&m_buffer[0], m_proxy)
|
||||
&& std::less<const void*>()(m_proxy, &m_buffer[1]);
|
||||
}
|
||||
|
||||
} // namespace is::signals::detail
|
||||
84
src/3rdParty/FastSignals/libfastsignals/src/signal_impl.cpp
vendored
Normal file
84
src/3rdParty/FastSignals/libfastsignals/src/signal_impl.cpp
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
#include "../include/signal_impl.h"
|
||||
#include <algorithm>
|
||||
#include <mutex>
|
||||
|
||||
namespace is::signals::detail
|
||||
{
|
||||
|
||||
uint64_t signal_impl::add(packed_function fn)
|
||||
{
|
||||
std::lock_guard lock(m_mutex);
|
||||
|
||||
m_functions.emplace_back(std::move(fn));
|
||||
|
||||
try
|
||||
{
|
||||
m_ids.emplace_back(m_nextId);
|
||||
}
|
||||
catch (const std::bad_alloc& /*e*/)
|
||||
{
|
||||
// Remove function since we failed to add its id
|
||||
m_functions.pop_back();
|
||||
throw;
|
||||
}
|
||||
|
||||
return m_nextId++;
|
||||
}
|
||||
|
||||
void signal_impl::remove(uint64_t id) noexcept
|
||||
{
|
||||
std::lock_guard lock(m_mutex);
|
||||
|
||||
// We use binary search because ids array is always sorted.
|
||||
auto it = std::lower_bound(m_ids.begin(), m_ids.end(), id);
|
||||
if (it != m_ids.end() && *it == id)
|
||||
{
|
||||
size_t i = std::distance(m_ids.begin(), it);
|
||||
m_ids.erase(m_ids.begin() + i);
|
||||
m_functions.erase(m_functions.begin() + i);
|
||||
}
|
||||
}
|
||||
|
||||
void signal_impl::remove_all() noexcept
|
||||
{
|
||||
std::lock_guard lock(m_mutex);
|
||||
m_functions.clear();
|
||||
m_ids.clear();
|
||||
}
|
||||
|
||||
bool signal_impl::get_next_slot(packed_function& slot, size_t& expectedIndex, uint64_t& nextId) const
|
||||
{
|
||||
// Slots always arranged by ID, so we can use a simple algorithm which avoids races:
|
||||
// - on each step find first slot with ID >= slotId
|
||||
// - after each call increment slotId
|
||||
|
||||
std::lock_guard lock(m_mutex);
|
||||
|
||||
// Avoid binary search if next slot wasn't moved between mutex locks.
|
||||
if (expectedIndex >= m_ids.size() || m_ids[expectedIndex] != nextId)
|
||||
{
|
||||
auto it = (nextId < m_nextId)
|
||||
? std::lower_bound(m_ids.cbegin(), m_ids.cend(), nextId)
|
||||
: m_ids.end();
|
||||
if (it == m_ids.end())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
expectedIndex = std::distance(m_ids.cbegin(), it);
|
||||
}
|
||||
|
||||
slot.reset();
|
||||
slot = m_functions[expectedIndex];
|
||||
nextId = (expectedIndex + 1 < m_ids.size()) ? m_ids[expectedIndex + 1] : m_ids[expectedIndex] + 1;
|
||||
++expectedIndex;
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t signal_impl::count() const noexcept
|
||||
{
|
||||
std::lock_guard lock(m_mutex);
|
||||
|
||||
return m_functions.size();
|
||||
}
|
||||
|
||||
} // namespace is::signals::detail
|
||||
30
src/3rdParty/FastSignals/libfastsignals_build_options.props
vendored
Normal file
30
src/3rdParty/FastSignals/libfastsignals_build_options.props
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ImportGroup Label="PropertySheets" />
|
||||
<PropertyGroup Label="UserMacros">
|
||||
<!--debug suffix-->
|
||||
<DebugSuffixOpt Condition="$(Configuration.StartsWith('Debug'))">d</DebugSuffixOpt>
|
||||
<DebugSuffixOpt Condition="$(Configuration.StartsWith('Release'))">
|
||||
</DebugSuffixOpt>
|
||||
<PlatformSuffix Condition="'$(Platform)'=='Win32'">-x32</PlatformSuffix>
|
||||
<PlatformSuffix Condition="'$(Platform)'=='x64'">-x64</PlatformSuffix>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup />
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
|
||||
<ClCompile>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<LinkTimeCodeGeneration>Default</LinkTimeCodeGeneration>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
|
||||
<ClCompile>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup />
|
||||
</Project>
|
||||
13287
src/3rdParty/FastSignals/tests/catch2/catch.hpp
vendored
Normal file
13287
src/3rdParty/FastSignals/tests/catch2/catch.hpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
2
src/3rdParty/FastSignals/tests/libfastsignals_stress_tests/CMakeLists.txt
vendored
Normal file
2
src/3rdParty/FastSignals/tests/libfastsignals_stress_tests/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
|
||||
custom_add_test_from_dir(libfastsignals_stress_tests libfastsignals)
|
||||
180
src/3rdParty/FastSignals/tests/libfastsignals_stress_tests/libfastsignals_stress_tests.vcxproj
vendored
Normal file
180
src/3rdParty/FastSignals/tests/libfastsignals_stress_tests/libfastsignals_stress_tests.vcxproj
vendored
Normal file
@@ -0,0 +1,180 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>15.0</VCProjectVersion>
|
||||
<ProjectGuid>{751DC150-1907-4D9F-8566-AA4E24FDFA64}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>libfastsignalsstresstests</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\..\libfastsignals_build_options.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\..\libfastsignals_build_options.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\..\libfastsignals_build_options.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\..\libfastsignals_build_options.props" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<IncludePath>$(SolutionDir);$(SolutionDir)tests;$(IncludePath)</IncludePath>
|
||||
<OutDir>$(SolutionDir)build\bin\$(ProjectName)\$(Platform)\$(Configuration)\</OutDir>
|
||||
<IntDir>$(SolutionDir)build\tmp\$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<IncludePath>$(SolutionDir);$(SolutionDir)tests;$(IncludePath)</IncludePath>
|
||||
<OutDir>$(SolutionDir)build\bin\$(ProjectName)\$(Platform)\$(Configuration)\</OutDir>
|
||||
<IntDir>$(SolutionDir)build\tmp\$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<IncludePath>$(SolutionDir);$(SolutionDir)tests;$(IncludePath)</IncludePath>
|
||||
<OutDir>$(SolutionDir)build\bin\$(ProjectName)\$(Platform)\$(Configuration)\</OutDir>
|
||||
<IntDir>$(SolutionDir)build\tmp\$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<IncludePath>$(SolutionDir);$(SolutionDir)tests;$(IncludePath)</IncludePath>
|
||||
<OutDir>$(SolutionDir)build\bin\$(ProjectName)\$(Platform)\$(Configuration)\</OutDir>
|
||||
<IntDir>$(SolutionDir)build\tmp\$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="main.cpp" />
|
||||
<ClCompile Include="signal_stress_tests.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\libfastsignals\libfastsignals.vcxproj">
|
||||
<Project>{32bd918f-edbc-4057-a033-10dc361da4a0}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<ClCompile Include="main.cpp" />
|
||||
<ClCompile Include="signal_stress_tests.cpp" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
2
src/3rdParty/FastSignals/tests/libfastsignals_stress_tests/main.cpp
vendored
Normal file
2
src/3rdParty/FastSignals/tests/libfastsignals_stress_tests/main.cpp
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
#define CATCH_CONFIG_MAIN
|
||||
#include "catch2/catch.hpp"
|
||||
123
src/3rdParty/FastSignals/tests/libfastsignals_stress_tests/signal_stress_tests.cpp
vendored
Normal file
123
src/3rdParty/FastSignals/tests/libfastsignals_stress_tests/signal_stress_tests.cpp
vendored
Normal file
@@ -0,0 +1,123 @@
|
||||
#include "catch2/catch.hpp"
|
||||
#include "libfastsignals/include/signal.h"
|
||||
#include <array>
|
||||
#include <mutex>
|
||||
#include <random>
|
||||
#include <vector>
|
||||
|
||||
using namespace is::signals;
|
||||
|
||||
namespace
|
||||
{
|
||||
using string_signal = signal<void(std::string)>;
|
||||
using string_slot = string_signal::slot_type;
|
||||
using void_signal = signal<void()>;
|
||||
using void_slot = void_signal::slot_type;
|
||||
|
||||
class named_entity
|
||||
{
|
||||
public:
|
||||
std::string name() const
|
||||
{
|
||||
std::lock_guard lock(m_nameMutex);
|
||||
return m_name;
|
||||
}
|
||||
|
||||
void fire_changed(std::string value)
|
||||
{
|
||||
bool fire = false;
|
||||
{
|
||||
std::lock_guard lock(m_nameMutex);
|
||||
if (m_name != value)
|
||||
{
|
||||
m_name = std::move(value);
|
||||
fire = true;
|
||||
}
|
||||
}
|
||||
if (fire)
|
||||
{
|
||||
m_nameChanged(value);
|
||||
}
|
||||
}
|
||||
|
||||
connection on_name_changed(string_slot slot)
|
||||
{
|
||||
return m_nameChanged.connect(std::move(slot));
|
||||
}
|
||||
|
||||
private:
|
||||
mutable std::mutex m_nameMutex;
|
||||
std::string m_name;
|
||||
signal<void(std::string)> m_nameChanged;
|
||||
};
|
||||
|
||||
unsigned get_next_seed()
|
||||
{
|
||||
static std::minstd_rand seedEngine(777);
|
||||
return seedEngine();
|
||||
}
|
||||
|
||||
size_t get_random_index(size_t size)
|
||||
{
|
||||
thread_local std::minstd_rand disconnectRandomEngine{ get_next_seed() };
|
||||
std::uniform_int_distribution<size_t> disconnectIndexDistribution{ 0, size - 1 };
|
||||
|
||||
return disconnectIndexDistribution(disconnectRandomEngine);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("Can work in a few threads", "[signal]")
|
||||
{
|
||||
constexpr unsigned fireThreadCount = 8;
|
||||
constexpr unsigned signalsCount = 7;
|
||||
constexpr unsigned fireCountPerThread = 100'000;
|
||||
constexpr unsigned connectCallsCount = 80'000;
|
||||
constexpr unsigned totalRunCount = 10;
|
||||
|
||||
for (unsigned i = 0; i < totalRunCount; ++i)
|
||||
{
|
||||
std::array<void_signal, signalsCount> signals;
|
||||
|
||||
std::mutex connectionsMutex;
|
||||
std::vector<connection> connections;
|
||||
connections.reserve(connectCallsCount);
|
||||
|
||||
std::vector<std::thread> threads;
|
||||
|
||||
auto slot = [&] {
|
||||
std::lock_guard lock(connectionsMutex);
|
||||
if (!connections.empty())
|
||||
{
|
||||
const size_t index = get_random_index(connections.size());
|
||||
connections.at(index).disconnect();
|
||||
}
|
||||
};
|
||||
|
||||
threads.emplace_back([&] {
|
||||
for (unsigned cci = 0; cci < connectCallsCount; ++cci)
|
||||
{
|
||||
const size_t index = get_random_index(signalsCount);
|
||||
connection conn = signals.at(index).connect(slot);
|
||||
{
|
||||
std::lock_guard lock(connectionsMutex);
|
||||
connections.emplace_back(conn);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
for (unsigned fti = 0; fti < fireThreadCount; ++fti)
|
||||
{
|
||||
threads.emplace_back([&] {
|
||||
for (unsigned fi = 0; fi < fireCountPerThread; ++fi)
|
||||
{
|
||||
const size_t index = get_random_index(signalsCount);
|
||||
signals.at(index)();
|
||||
}
|
||||
});
|
||||
}
|
||||
for (auto& thread : threads)
|
||||
{
|
||||
thread.join();
|
||||
}
|
||||
}
|
||||
}
|
||||
4
src/3rdParty/FastSignals/tests/libfastsignals_unit_tests/CMakeLists.txt
vendored
Normal file
4
src/3rdParty/FastSignals/tests/libfastsignals_unit_tests/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
|
||||
custom_add_test_from_dir(libfastsignals_unit_tests libfastsignals)
|
||||
custom_enable_cxx17(libfastsignals_unit_tests)
|
||||
target_include_directories(libfastsignals_unit_tests PRIVATE "${CMAKE_SOURCE_DIR}/tests")
|
||||
618
src/3rdParty/FastSignals/tests/libfastsignals_unit_tests/Function_tests.cpp
vendored
Normal file
618
src/3rdParty/FastSignals/tests/libfastsignals_unit_tests/Function_tests.cpp
vendored
Normal file
@@ -0,0 +1,618 @@
|
||||
#include "catch2/catch.hpp"
|
||||
#include "libfastsignals/include/function.h"
|
||||
#include <array>
|
||||
|
||||
using namespace is::signals;
|
||||
|
||||
namespace
|
||||
{
|
||||
int Abs(int x)
|
||||
{
|
||||
return x >= 0 ? x : -x;
|
||||
}
|
||||
|
||||
int Sum(int a, int b)
|
||||
{
|
||||
return a + b;
|
||||
}
|
||||
|
||||
void InplaceAbs(int& x)
|
||||
{
|
||||
x = Abs(x);
|
||||
}
|
||||
|
||||
std::string GetStringHello()
|
||||
{
|
||||
return "hello";
|
||||
}
|
||||
|
||||
class AbsFunctor
|
||||
{
|
||||
public:
|
||||
int operator()(int x) const
|
||||
{
|
||||
return Abs(x);
|
||||
}
|
||||
};
|
||||
|
||||
class SumFunctor
|
||||
{
|
||||
public:
|
||||
int operator()(int a, int b) const
|
||||
{
|
||||
return Sum(a, b);
|
||||
}
|
||||
};
|
||||
|
||||
class InplaceAbsFunctor
|
||||
{
|
||||
public:
|
||||
void operator()(int& x) /* non-const */
|
||||
{
|
||||
if (m_calledOnce)
|
||||
{
|
||||
abort();
|
||||
}
|
||||
m_calledOnce = true;
|
||||
InplaceAbs(x);
|
||||
}
|
||||
|
||||
private:
|
||||
bool m_calledOnce = false;
|
||||
};
|
||||
|
||||
class GetStringFunctor
|
||||
{
|
||||
public:
|
||||
explicit GetStringFunctor(const std::string& value)
|
||||
: m_value(value)
|
||||
{
|
||||
}
|
||||
|
||||
std::string operator()() /* non-const */
|
||||
{
|
||||
if (m_calledOnce)
|
||||
{
|
||||
abort();
|
||||
}
|
||||
m_calledOnce = true;
|
||||
return m_value;
|
||||
}
|
||||
|
||||
private:
|
||||
bool m_calledOnce = false;
|
||||
std::string m_value;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("Can use free function with 1 argument", "[function]")
|
||||
{
|
||||
function<int(int)> fn = Abs;
|
||||
REQUIRE(fn(10) == 10);
|
||||
REQUIRE(fn(-10) == 10);
|
||||
REQUIRE(fn(0) == 0);
|
||||
}
|
||||
|
||||
TEST_CASE("Can use free function with 2 arguments", "[function]")
|
||||
{
|
||||
function<int(int, int)> fn = Sum;
|
||||
REQUIRE(fn(10, 5) == 15);
|
||||
REQUIRE(fn(-10, 0) == -10);
|
||||
}
|
||||
|
||||
TEST_CASE("Can use free function without arguments", "[function]")
|
||||
{
|
||||
function<std::string()> fn = GetStringHello;
|
||||
REQUIRE(fn() == "hello");
|
||||
}
|
||||
|
||||
TEST_CASE("Can use free function without return value", "[function]")
|
||||
{
|
||||
function<void(int&)> fn = InplaceAbs;
|
||||
int a = -10;
|
||||
fn(a);
|
||||
REQUIRE(a == 10);
|
||||
}
|
||||
|
||||
TEST_CASE("Can use lambda with 1 argument", "[function]")
|
||||
{
|
||||
function<int(int)> fn = [](int value) {
|
||||
return Abs(value);
|
||||
};
|
||||
REQUIRE(fn(10) == 10);
|
||||
REQUIRE(fn(-10) == 10);
|
||||
REQUIRE(fn(0) == 0);
|
||||
}
|
||||
|
||||
TEST_CASE("Can use lambda with 2 arguments", "[function]")
|
||||
{
|
||||
function<int(int, int)> fn = [](auto&& a, auto&& b) {
|
||||
return Sum(a, b);
|
||||
};
|
||||
REQUIRE(fn(10, 5) == 15);
|
||||
REQUIRE(fn(-10, 0) == -10);
|
||||
}
|
||||
|
||||
TEST_CASE("Can use lambda without arguments", "[function]")
|
||||
{
|
||||
function<std::string()> fn = [] {
|
||||
return GetStringHello();
|
||||
};
|
||||
REQUIRE(fn() == "hello");
|
||||
}
|
||||
|
||||
TEST_CASE("Can use lambda without return value", "[function]")
|
||||
{
|
||||
bool calledOnce = false;
|
||||
function<void(int&)> fn = [calledOnce](auto& value) mutable {
|
||||
if (calledOnce)
|
||||
{
|
||||
abort();
|
||||
}
|
||||
calledOnce = true;
|
||||
InplaceAbs(value);
|
||||
};
|
||||
int a = -10;
|
||||
fn(a);
|
||||
REQUIRE(a == 10);
|
||||
}
|
||||
|
||||
TEST_CASE("Can use functor with 1 argument", "[function]")
|
||||
{
|
||||
function<int(int)> fn = AbsFunctor();
|
||||
REQUIRE(fn(10) == 10);
|
||||
REQUIRE(fn(-10) == 10);
|
||||
REQUIRE(fn(0) == 0);
|
||||
}
|
||||
|
||||
TEST_CASE("Can use functor with 2 arguments", "[function]")
|
||||
{
|
||||
function<int(int, int)> fn = SumFunctor();
|
||||
REQUIRE(fn(10, 5) == 15);
|
||||
REQUIRE(fn(-10, 0) == -10);
|
||||
}
|
||||
|
||||
TEST_CASE("Can use functor without arguments", "[function]")
|
||||
{
|
||||
function<std::string()> fn = GetStringFunctor("hello");
|
||||
REQUIRE(fn() == "hello");
|
||||
}
|
||||
|
||||
TEST_CASE("Can use functor without return value", "[function]")
|
||||
{
|
||||
function<void(int&)> fn = InplaceAbsFunctor();
|
||||
int a = -10;
|
||||
fn(a);
|
||||
REQUIRE(a == 10);
|
||||
}
|
||||
|
||||
TEST_CASE("Can construct function with cons std::function<>&", "[function]")
|
||||
{
|
||||
using BoolCallback = std::function<void(bool succeed)>;
|
||||
bool value = false;
|
||||
const BoolCallback& cb = [&value](bool succeed) {
|
||||
value = succeed;
|
||||
};
|
||||
|
||||
function<void(bool)> fn = cb;
|
||||
fn(true);
|
||||
REQUIRE(value == true);
|
||||
fn(false);
|
||||
REQUIRE(value == false);
|
||||
fn(true);
|
||||
REQUIRE(value == true);
|
||||
}
|
||||
|
||||
TEST_CASE("Can copy function", "[function]")
|
||||
{
|
||||
unsigned calledCount = 0;
|
||||
bool value = false;
|
||||
function<void(bool)> callback = [&](bool gotValue) {
|
||||
++calledCount;
|
||||
value = gotValue;
|
||||
};
|
||||
auto callback2 = callback;
|
||||
REQUIRE(calledCount == 0);
|
||||
CHECK(!value);
|
||||
callback(true);
|
||||
REQUIRE(calledCount == 1);
|
||||
CHECK(value);
|
||||
callback2(false);
|
||||
REQUIRE(calledCount == 2);
|
||||
CHECK(!value);
|
||||
}
|
||||
|
||||
TEST_CASE("Can move function", "[function]")
|
||||
{
|
||||
bool called = false;
|
||||
function<void()> callback = [&] {
|
||||
called = true;
|
||||
};
|
||||
auto callback2(std::move(callback));
|
||||
REQUIRE_THROWS(callback());
|
||||
REQUIRE(!called);
|
||||
callback2();
|
||||
REQUIRE(called);
|
||||
}
|
||||
|
||||
TEST_CASE("Works when copying self", "[function]")
|
||||
{
|
||||
bool called = false;
|
||||
function<void()> callback = [&] {
|
||||
called = true;
|
||||
};
|
||||
callback = callback;
|
||||
callback();
|
||||
REQUIRE(called);
|
||||
}
|
||||
|
||||
TEST_CASE("Can release packed function", "[function]")
|
||||
{
|
||||
function<int()> iota = [v = 0]() mutable {
|
||||
return v++;
|
||||
};
|
||||
REQUIRE(iota() == 0);
|
||||
|
||||
auto packedFn = std::move(iota).release();
|
||||
REQUIRE_THROWS_AS(iota(), std::bad_function_call);
|
||||
|
||||
auto&& proxy = packedFn.get<int()>();
|
||||
REQUIRE(proxy() == 1);
|
||||
REQUIRE(proxy() == 2);
|
||||
}
|
||||
|
||||
TEST_CASE("Function copy has its own packed function", "[function]")
|
||||
{
|
||||
function<int()> iota = [v = 0]() mutable {
|
||||
return v++;
|
||||
};
|
||||
|
||||
REQUIRE(iota() == 0);
|
||||
|
||||
auto iotaCopy(iota);
|
||||
|
||||
REQUIRE(iota() == 1);
|
||||
REQUIRE(iota() == 2);
|
||||
|
||||
REQUIRE(iotaCopy() == 1);
|
||||
REQUIRE(iotaCopy() == 2);
|
||||
}
|
||||
|
||||
TEST_CASE("can work with callables that have vtable", "[function]")
|
||||
{
|
||||
class Base
|
||||
{
|
||||
};
|
||||
|
||||
class Interface : public Base
|
||||
{
|
||||
public:
|
||||
virtual ~Interface() = default;
|
||||
virtual void operator()() const = 0;
|
||||
};
|
||||
class Class : public Interface
|
||||
{
|
||||
public:
|
||||
Class(bool* destructorCalled)
|
||||
: m_destructorCalled(destructorCalled)
|
||||
{
|
||||
}
|
||||
|
||||
~Class()
|
||||
{
|
||||
*m_destructorCalled = true;
|
||||
}
|
||||
|
||||
void operator()() const override
|
||||
{
|
||||
}
|
||||
|
||||
bool* m_destructorCalled = nullptr;
|
||||
};
|
||||
bool destructorCalled = false;
|
||||
{
|
||||
function<void()> f = Class(&destructorCalled);
|
||||
f();
|
||||
auto packed = f.release();
|
||||
destructorCalled = false;
|
||||
}
|
||||
CHECK(destructorCalled);
|
||||
}
|
||||
|
||||
TEST_CASE("can work with callables with virtual inheritance", "[function]")
|
||||
{
|
||||
struct A
|
||||
{
|
||||
void operator()() const
|
||||
{
|
||||
m_called = true;
|
||||
}
|
||||
|
||||
~A()
|
||||
{
|
||||
*m_destructorCalled = true;
|
||||
}
|
||||
|
||||
mutable bool m_called = false;
|
||||
bool* m_destructorCalled = nullptr;
|
||||
};
|
||||
struct B : public virtual A
|
||||
{
|
||||
};
|
||||
struct C : public virtual A
|
||||
{
|
||||
};
|
||||
struct D : virtual public B
|
||||
, virtual public C
|
||||
{
|
||||
D(bool* destructorCalled)
|
||||
{
|
||||
m_destructorCalled = destructorCalled;
|
||||
}
|
||||
|
||||
using A::operator();
|
||||
};
|
||||
bool destructorCalled = false;
|
||||
{
|
||||
function<void()> f = D(&destructorCalled);
|
||||
f();
|
||||
auto packed = f.release();
|
||||
destructorCalled = false;
|
||||
}
|
||||
CHECK(destructorCalled);
|
||||
}
|
||||
|
||||
TEST_CASE("uses copy constructor if callable's move constructor throws", "[function]")
|
||||
{
|
||||
struct Callable
|
||||
{
|
||||
Callable() = default;
|
||||
Callable(Callable&&)
|
||||
{
|
||||
throw std::runtime_error("throw");
|
||||
}
|
||||
Callable(const Callable& other) = default;
|
||||
void operator()() const
|
||||
{
|
||||
}
|
||||
};
|
||||
Callable c;
|
||||
function<void()> f(c);
|
||||
auto f2 = std::move(f);
|
||||
f2();
|
||||
CHECK_THROWS(f());
|
||||
}
|
||||
|
||||
TEST_CASE("uses move constructor if it is noexcept", "[function]")
|
||||
{
|
||||
struct Callable
|
||||
{
|
||||
Callable() = default;
|
||||
Callable(Callable&& other) noexcept = default;
|
||||
Callable(const Callable&)
|
||||
{
|
||||
throw std::runtime_error("throw");
|
||||
}
|
||||
void operator()() const
|
||||
{
|
||||
}
|
||||
};
|
||||
Callable c;
|
||||
function<void()> f(std::move(c));
|
||||
auto f2 = std::move(f);
|
||||
f2();
|
||||
CHECK_THROWS(f());
|
||||
}
|
||||
|
||||
TEST_CASE("can copy and move empty function", "[function]")
|
||||
{
|
||||
function<void()> f;
|
||||
auto f2 = f;
|
||||
auto f3 = std::move(f);
|
||||
}
|
||||
|
||||
TEST_CASE("properly copies callable on assignment", "[function]")
|
||||
{
|
||||
struct Callable
|
||||
{
|
||||
Callable(int& aliveCounter)
|
||||
: m_aliveCounter(&aliveCounter)
|
||||
{
|
||||
++*m_aliveCounter;
|
||||
}
|
||||
Callable(const Callable& other)
|
||||
: m_aliveCounter(other.m_aliveCounter)
|
||||
{
|
||||
if (m_aliveCounter)
|
||||
{
|
||||
++*m_aliveCounter;
|
||||
}
|
||||
}
|
||||
Callable(Callable&& other) noexcept
|
||||
: m_aliveCounter(other.m_aliveCounter)
|
||||
{
|
||||
other.m_aliveCounter = nullptr;
|
||||
}
|
||||
~Callable()
|
||||
{
|
||||
if (m_aliveCounter)
|
||||
{
|
||||
--*m_aliveCounter;
|
||||
}
|
||||
}
|
||||
void operator()() const
|
||||
{
|
||||
}
|
||||
|
||||
int* m_aliveCounter = nullptr;
|
||||
};
|
||||
int aliveCounter1 = 0;
|
||||
int aliveCounter2 = 0;
|
||||
function<void()> f = Callable(aliveCounter1);
|
||||
function<void()> f2 = Callable(aliveCounter2);
|
||||
CHECK(aliveCounter1 == 1);
|
||||
CHECK(aliveCounter2 == 1);
|
||||
f = f2;
|
||||
CHECK(aliveCounter1 == 0);
|
||||
CHECK(aliveCounter2 == 2);
|
||||
f = function<void()>();
|
||||
f2 = function<void()>();
|
||||
CHECK(aliveCounter1 == 0);
|
||||
CHECK(aliveCounter2 == 0);
|
||||
}
|
||||
|
||||
TEST_CASE("copy assignment operator provides strong exception safety", "[function]")
|
||||
{
|
||||
struct State
|
||||
{
|
||||
int callCount = 0;
|
||||
bool throwOnCopy = false;
|
||||
};
|
||||
struct Callable
|
||||
{
|
||||
Callable(State& state)
|
||||
: state(&state)
|
||||
{
|
||||
}
|
||||
void operator()()
|
||||
{
|
||||
++state->callCount;
|
||||
}
|
||||
Callable(const Callable& other)
|
||||
: state(other.state)
|
||||
{
|
||||
if (state->throwOnCopy)
|
||||
{
|
||||
throw std::runtime_error("throw on request");
|
||||
}
|
||||
}
|
||||
State* state = nullptr;
|
||||
};
|
||||
static_assert(!detail::can_use_inplace_buffer<Callable>);
|
||||
|
||||
State srcState;
|
||||
State dstState;
|
||||
|
||||
function<void()> srcFn(Callable{ srcState });
|
||||
function<void()> dstFn(Callable{ dstState });
|
||||
|
||||
srcFn();
|
||||
dstFn();
|
||||
|
||||
REQUIRE(srcState.callCount == 1);
|
||||
REQUIRE(dstState.callCount == 1);
|
||||
|
||||
srcState.throwOnCopy = true;
|
||||
|
||||
REQUIRE_THROWS_AS(dstFn = srcFn, std::runtime_error);
|
||||
|
||||
// srcFn and dstFn must not be emptied even if assignment throws
|
||||
REQUIRE_NOTHROW(srcFn());
|
||||
REQUIRE_NOTHROW(dstFn());
|
||||
|
||||
// srcFn and dstFn must keep their state
|
||||
REQUIRE(srcState.callCount == 2);
|
||||
REQUIRE(dstState.callCount == 2);
|
||||
|
||||
// The next copy will succeed
|
||||
srcState.throwOnCopy = false;
|
||||
REQUIRE_NOTHROW(dstFn = srcFn);
|
||||
|
||||
// Both functions are usable
|
||||
REQUIRE_NOTHROW(srcFn());
|
||||
REQUIRE_NOTHROW(dstFn());
|
||||
|
||||
// After assignment, dstFn and srcFn refer the same state - srcState
|
||||
REQUIRE(srcState.callCount == 4);
|
||||
REQUIRE(dstState.callCount == 2);
|
||||
}
|
||||
|
||||
TEST_CASE("assignment of variously allocated functions", "[function]")
|
||||
{
|
||||
int heapCalls = 0;
|
||||
auto onHeap = [&heapCalls, largeVar = std::array<std::string, 1000>()]() mutable {
|
||||
std::fill(largeVar.begin(), largeVar.end(), "large string to be allocated on heap instead of stack");
|
||||
++heapCalls;
|
||||
};
|
||||
int stackCalls = 0;
|
||||
auto onStack = [&stackCalls] {
|
||||
++stackCalls;
|
||||
};
|
||||
|
||||
static_assert(detail::can_use_inplace_buffer<detail::function_proxy_impl<decltype(onStack), void>>);
|
||||
static_assert(!detail::can_use_inplace_buffer<detail::function_proxy_impl<decltype(onHeap), void>>);
|
||||
|
||||
using Fn = function<void()>;
|
||||
{
|
||||
Fn heap(onHeap);
|
||||
Fn stack(onStack);
|
||||
heap = stack;
|
||||
heap();
|
||||
REQUIRE(stackCalls == 1);
|
||||
REQUIRE(heapCalls == 0);
|
||||
}
|
||||
{
|
||||
Fn heap(onHeap);
|
||||
Fn stack(onStack);
|
||||
stack = heap;
|
||||
stack();
|
||||
REQUIRE(stackCalls == 1);
|
||||
REQUIRE(heapCalls == 1);
|
||||
}
|
||||
{
|
||||
Fn heap(onHeap);
|
||||
Fn heap1(onHeap);
|
||||
heap = heap1;
|
||||
heap();
|
||||
REQUIRE(stackCalls == 1);
|
||||
REQUIRE(heapCalls == 2);
|
||||
}
|
||||
{
|
||||
Fn stack(onStack);
|
||||
Fn stack1(onStack);
|
||||
stack = stack1;
|
||||
stack();
|
||||
REQUIRE(stackCalls == 2);
|
||||
REQUIRE(heapCalls == 2);
|
||||
}
|
||||
{
|
||||
Fn heap(onHeap);
|
||||
Fn empty;
|
||||
heap = empty;
|
||||
REQUIRE_THROWS(heap());
|
||||
REQUIRE(stackCalls == 2);
|
||||
REQUIRE(heapCalls == 2);
|
||||
}
|
||||
{
|
||||
Fn stack(onStack);
|
||||
Fn empty;
|
||||
stack = empty;
|
||||
REQUIRE_THROWS(stack());
|
||||
REQUIRE(stackCalls == 2);
|
||||
REQUIRE(heapCalls == 2);
|
||||
}
|
||||
{
|
||||
Fn empty;
|
||||
Fn heap(onHeap);
|
||||
empty = heap;
|
||||
empty();
|
||||
REQUIRE(stackCalls == 2);
|
||||
REQUIRE(heapCalls == 3);
|
||||
}
|
||||
{
|
||||
Fn empty;
|
||||
Fn stack(onStack);
|
||||
empty = stack;
|
||||
empty();
|
||||
REQUIRE(stackCalls == 3);
|
||||
REQUIRE(heapCalls == 3);
|
||||
}
|
||||
{
|
||||
Fn empty;
|
||||
Fn empty1;
|
||||
empty = empty1;
|
||||
REQUIRE_THROWS(empty());
|
||||
REQUIRE(stackCalls == 3);
|
||||
REQUIRE(heapCalls == 3);
|
||||
}
|
||||
}
|
||||
132
src/3rdParty/FastSignals/tests/libfastsignals_unit_tests/bind_weak_tests.cpp
vendored
Normal file
132
src/3rdParty/FastSignals/tests/libfastsignals_unit_tests/bind_weak_tests.cpp
vendored
Normal file
@@ -0,0 +1,132 @@
|
||||
#include "catch2/catch.hpp"
|
||||
#include "libfastsignals/include/bind_weak.h"
|
||||
|
||||
using namespace is::signals;
|
||||
|
||||
namespace
|
||||
{
|
||||
class Testbed
|
||||
{
|
||||
public:
|
||||
Testbed(unsigned& counter)
|
||||
: m_pCounter(&counter)
|
||||
{
|
||||
}
|
||||
|
||||
void IncrementNonConst()
|
||||
{
|
||||
++(*m_pCounter);
|
||||
}
|
||||
|
||||
void IncrementsConst() const
|
||||
{
|
||||
++(*m_pCounter);
|
||||
}
|
||||
|
||||
int ReflectInt(int value) const
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned* m_pCounter = nullptr;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("can bind const methods", "[bind_weak]")
|
||||
{
|
||||
unsigned counter = 0;
|
||||
auto pSharedBed = std::make_shared<Testbed>(counter);
|
||||
auto boundFn = bind_weak(&Testbed::IncrementNonConst, pSharedBed);
|
||||
REQUIRE(counter == 0u);
|
||||
boundFn();
|
||||
REQUIRE(counter == 1u);
|
||||
boundFn();
|
||||
REQUIRE(counter == 2u);
|
||||
pSharedBed = nullptr;
|
||||
boundFn();
|
||||
REQUIRE(counter == 2u);
|
||||
boundFn();
|
||||
REQUIRE(counter == 2u);
|
||||
}
|
||||
|
||||
TEST_CASE("can bind non const methods", "[bind_weak]")
|
||||
{
|
||||
unsigned counter = 0;
|
||||
auto pSharedBed = std::make_shared<Testbed>(counter);
|
||||
auto boundFn = bind_weak(&Testbed::IncrementsConst, pSharedBed);
|
||||
REQUIRE(counter == 0u);
|
||||
boundFn();
|
||||
REQUIRE(counter == 1u);
|
||||
boundFn();
|
||||
REQUIRE(counter == 2u);
|
||||
pSharedBed = nullptr;
|
||||
boundFn();
|
||||
REQUIRE(counter == 2u);
|
||||
boundFn();
|
||||
REQUIRE(counter == 2u);
|
||||
}
|
||||
|
||||
TEST_CASE("can bind method with argument value", "[bind_weak]")
|
||||
{
|
||||
unsigned counter = 0;
|
||||
auto pSharedBed = std::make_shared<Testbed>(counter);
|
||||
auto boundFn = bind_weak(&Testbed::ReflectInt, pSharedBed, 42);
|
||||
REQUIRE(boundFn() == 42);
|
||||
REQUIRE(boundFn() == 42);
|
||||
pSharedBed = nullptr;
|
||||
REQUIRE(boundFn() == 0);
|
||||
REQUIRE(boundFn() == 0);
|
||||
}
|
||||
|
||||
TEST_CASE("copies value when bind method with argument const reference value", "[bind_weak]")
|
||||
{
|
||||
unsigned counter = 0;
|
||||
auto pSharedBed = std::make_shared<Testbed>(counter);
|
||||
auto makeBoundFn = [&]() {
|
||||
int value = 15;
|
||||
const int& valueRef = value;
|
||||
auto result = bind_weak(&Testbed::ReflectInt, pSharedBed, valueRef);
|
||||
value = 25;
|
||||
return result;
|
||||
};
|
||||
|
||||
auto boundFn = makeBoundFn();
|
||||
REQUIRE(boundFn(42) == 15);
|
||||
REQUIRE(boundFn(42) == 15);
|
||||
pSharedBed = nullptr;
|
||||
REQUIRE(boundFn(42) == 0);
|
||||
REQUIRE(boundFn(42) == 0);
|
||||
}
|
||||
|
||||
TEST_CASE("copies value when bind method with argument reference value", "[bind_weak]")
|
||||
{
|
||||
unsigned counter = 0;
|
||||
auto pSharedBed = std::make_shared<Testbed>(counter);
|
||||
auto makeBoundFn = [&]() {
|
||||
int value = 15;
|
||||
int& valueRef = value;
|
||||
auto result = bind_weak(&Testbed::ReflectInt, pSharedBed, valueRef);
|
||||
valueRef = 25;
|
||||
return result;
|
||||
};
|
||||
|
||||
auto boundFn = makeBoundFn();
|
||||
REQUIRE(boundFn(42) == 15);
|
||||
REQUIRE(boundFn(42) == 15);
|
||||
pSharedBed = nullptr;
|
||||
REQUIRE(boundFn(42) == 0);
|
||||
REQUIRE(boundFn(42) == 0);
|
||||
}
|
||||
|
||||
TEST_CASE("can bind method with placeholder", "[bind_weak]")
|
||||
{
|
||||
unsigned counter = 0;
|
||||
auto pSharedBed = std::make_shared<Testbed>(counter);
|
||||
auto boundFn = bind_weak(&Testbed::ReflectInt, pSharedBed, std::placeholders::_1);
|
||||
REQUIRE(boundFn(42) == 42);
|
||||
REQUIRE(boundFn(42) == 42);
|
||||
pSharedBed = nullptr;
|
||||
REQUIRE(boundFn(42) == 0);
|
||||
REQUIRE(boundFn(42) == 0);
|
||||
}
|
||||
190
src/3rdParty/FastSignals/tests/libfastsignals_unit_tests/libfastsignals_unit_tests.vcxproj
vendored
Normal file
190
src/3rdParty/FastSignals/tests/libfastsignals_unit_tests/libfastsignals_unit_tests.vcxproj
vendored
Normal file
@@ -0,0 +1,190 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>15.0</VCProjectVersion>
|
||||
<ProjectGuid>{BAC23A51-8DC1-4589-940F-9923D8E12718}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>libfastsignals_unit_tests</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\..\libfastsignals_build_options.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\..\libfastsignals_build_options.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\..\libfastsignals_build_options.props" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\..\libfastsignals_build_options.props" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<IncludePath>$(SolutionDir);$(SolutionDir)tests;$(IncludePath)</IncludePath>
|
||||
<OutDir>$(SolutionDir)build\bin\$(ProjectName)\$(Platform)\$(Configuration)\</OutDir>
|
||||
<IntDir>$(SolutionDir)build\tmp\$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<IncludePath>$(SolutionDir);$(SolutionDir)tests;$(IncludePath)</IncludePath>
|
||||
<OutDir>$(SolutionDir)build\bin\$(ProjectName)\$(Platform)\$(Configuration)\</OutDir>
|
||||
<IntDir>$(SolutionDir)build\tmp\$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<IncludePath>$(SolutionDir);$(SolutionDir)tests;$(IncludePath)</IncludePath>
|
||||
<OutDir>$(SolutionDir)build\bin\$(ProjectName)\$(Platform)\$(Configuration)\</OutDir>
|
||||
<IntDir>$(SolutionDir)build\tmp\$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<IncludePath>$(SolutionDir);$(SolutionDir)tests;$(IncludePath)</IncludePath>
|
||||
<OutDir>$(SolutionDir)build\bin\$(ProjectName)\$(Platform)\$(Configuration)\</OutDir>
|
||||
<IntDir>$(SolutionDir)build\tmp\$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>$(TargetPath)</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>$(TargetPath)</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>$(TargetPath)</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>$(TargetPath)</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="bind_weak_tests.cpp" />
|
||||
<ClCompile Include="function_tests.cpp" />
|
||||
<ClCompile Include="main.cpp" />
|
||||
<ClCompile Include="signal_tests.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\libfastsignals\libfastsignals.vcxproj">
|
||||
<Project>{32bd918f-edbc-4057-a033-10dc361da4a0}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<ClCompile Include="main.cpp" />
|
||||
<ClCompile Include="signal_tests.cpp" />
|
||||
<ClCompile Include="function_tests.cpp" />
|
||||
<ClCompile Include="bind_weak_tests.cpp" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
2
src/3rdParty/FastSignals/tests/libfastsignals_unit_tests/main.cpp
vendored
Normal file
2
src/3rdParty/FastSignals/tests/libfastsignals_unit_tests/main.cpp
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
#define CATCH_CONFIG_MAIN
|
||||
#include "catch2/catch.hpp"
|
||||
707
src/3rdParty/FastSignals/tests/libfastsignals_unit_tests/signal_tests.cpp
vendored
Normal file
707
src/3rdParty/FastSignals/tests/libfastsignals_unit_tests/signal_tests.cpp
vendored
Normal file
@@ -0,0 +1,707 @@
|
||||
#include "catch2/catch.hpp"
|
||||
#include "libfastsignals/include/signal.h"
|
||||
#include <string>
|
||||
|
||||
using namespace is::signals;
|
||||
using namespace std::literals;
|
||||
|
||||
namespace
|
||||
{
|
||||
template <class T>
|
||||
class any_of_combiner
|
||||
{
|
||||
public:
|
||||
static_assert(std::is_same_v<T, bool>);
|
||||
|
||||
using result_type = bool;
|
||||
|
||||
template <class TRef>
|
||||
void operator()(TRef&& value)
|
||||
{
|
||||
m_result = m_result || bool(value);
|
||||
}
|
||||
|
||||
result_type get_value() const
|
||||
{
|
||||
return m_result;
|
||||
}
|
||||
|
||||
private:
|
||||
result_type m_result = {};
|
||||
};
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("Can connect a few slots and emit", "[signal]")
|
||||
{
|
||||
signal<void(int)> valueChanged;
|
||||
|
||||
int value1 = 0;
|
||||
int value2 = 0;
|
||||
valueChanged.connect([&value1](int value) {
|
||||
value1 = value;
|
||||
});
|
||||
valueChanged.connect([&value2](int value) {
|
||||
value2 = value;
|
||||
});
|
||||
REQUIRE(value1 == 0);
|
||||
REQUIRE(value2 == 0);
|
||||
|
||||
valueChanged(10);
|
||||
REQUIRE(value1 == 10);
|
||||
REQUIRE(value2 == 10);
|
||||
}
|
||||
|
||||
TEST_CASE("Can safely pass rvalues", "[signal]")
|
||||
{
|
||||
const std::string expected = "If the type T is a reference type, provides the member typedef type which is the type referred to by T. Otherwise type is T.";
|
||||
std::string passedValue = expected;
|
||||
signal<void(std::string)> valueChanged;
|
||||
|
||||
std::string value1;
|
||||
std::string value2;
|
||||
valueChanged.connect([&value1](std::string value) {
|
||||
value1 = value;
|
||||
});
|
||||
valueChanged.connect([&value2](std::string value) {
|
||||
value2 = value;
|
||||
});
|
||||
|
||||
valueChanged(std::move(passedValue));
|
||||
REQUIRE(value1 == expected);
|
||||
REQUIRE(value2 == expected);
|
||||
}
|
||||
|
||||
TEST_CASE("Can pass mutable ref", "[signal]")
|
||||
{
|
||||
const std::string expected = "If the type T is a reference type, provides the member typedef type which is the type referred to by T. Otherwise type is T.";
|
||||
signal<void(std::string&)> valueChanged;
|
||||
|
||||
std::string passedValue;
|
||||
valueChanged.connect([expected](std::string& value) {
|
||||
value = expected;
|
||||
});
|
||||
valueChanged(passedValue);
|
||||
|
||||
REQUIRE(passedValue == expected);
|
||||
}
|
||||
|
||||
TEST_CASE("Can disconnect slot with explicit call", "[signal]")
|
||||
{
|
||||
signal<void(int)> valueChanged;
|
||||
|
||||
int value1 = 0;
|
||||
int value2 = 0;
|
||||
int value3 = 0;
|
||||
auto conn1 = valueChanged.connect([&value1](int value) {
|
||||
value1 = value;
|
||||
});
|
||||
auto conn2 = valueChanged.connect([&value2](int value) {
|
||||
value2 = value;
|
||||
});
|
||||
valueChanged.connect([&value3](int value) {
|
||||
value3 = value;
|
||||
});
|
||||
REQUIRE(value1 == 0);
|
||||
REQUIRE(value2 == 0);
|
||||
REQUIRE(value3 == 0);
|
||||
|
||||
valueChanged(10);
|
||||
REQUIRE(value1 == 10);
|
||||
REQUIRE(value2 == 10);
|
||||
REQUIRE(value3 == 10);
|
||||
|
||||
conn2.disconnect();
|
||||
valueChanged(-99);
|
||||
REQUIRE(value1 == -99);
|
||||
REQUIRE(value2 == 10);
|
||||
REQUIRE(value3 == -99);
|
||||
|
||||
conn1.disconnect();
|
||||
valueChanged(17);
|
||||
REQUIRE(value1 == -99);
|
||||
REQUIRE(value2 == 10);
|
||||
REQUIRE(value3 == 17);
|
||||
}
|
||||
|
||||
TEST_CASE("Can disconnect slot with scoped_connection", "[signal]")
|
||||
{
|
||||
signal<void(int)> valueChanged;
|
||||
|
||||
int value1 = 0;
|
||||
int value2 = 0;
|
||||
int value3 = 0;
|
||||
{
|
||||
scoped_connection conn1 = valueChanged.connect([&value1](int value) {
|
||||
value1 = value;
|
||||
});
|
||||
{
|
||||
scoped_connection conn2 = valueChanged.connect([&value2](int value) {
|
||||
value2 = value;
|
||||
});
|
||||
valueChanged.connect([&value3](int value) {
|
||||
value3 = value;
|
||||
});
|
||||
REQUIRE(value1 == 0);
|
||||
REQUIRE(value2 == 0);
|
||||
REQUIRE(value3 == 0);
|
||||
|
||||
valueChanged(10);
|
||||
REQUIRE(value1 == 10);
|
||||
REQUIRE(value2 == 10);
|
||||
REQUIRE(value3 == 10);
|
||||
}
|
||||
|
||||
// conn2 disconnected.
|
||||
valueChanged(-99);
|
||||
REQUIRE(value1 == -99);
|
||||
REQUIRE(value2 == 10);
|
||||
REQUIRE(value3 == -99);
|
||||
}
|
||||
|
||||
// conn1 disconnected.
|
||||
valueChanged(17);
|
||||
REQUIRE(value1 == -99);
|
||||
REQUIRE(value2 == 10);
|
||||
REQUIRE(value3 == 17);
|
||||
}
|
||||
|
||||
TEST_CASE("Can disconnect all", "[signal]")
|
||||
{
|
||||
signal<void(int)> valueChanged;
|
||||
|
||||
int value1 = 0;
|
||||
int value2 = 0;
|
||||
int value3 = 0;
|
||||
valueChanged.connect([&value1](int value) {
|
||||
value1 = value;
|
||||
});
|
||||
valueChanged.connect([&value2](int value) {
|
||||
value2 = value;
|
||||
});
|
||||
valueChanged.connect([&value3](int value) {
|
||||
value3 = value;
|
||||
});
|
||||
REQUIRE(value1 == 0);
|
||||
REQUIRE(value2 == 0);
|
||||
REQUIRE(value3 == 0);
|
||||
|
||||
valueChanged(63);
|
||||
REQUIRE(value1 == 63);
|
||||
REQUIRE(value2 == 63);
|
||||
REQUIRE(value3 == 63);
|
||||
|
||||
valueChanged.disconnect_all_slots();
|
||||
valueChanged(101);
|
||||
REQUIRE(value1 == 63);
|
||||
REQUIRE(value2 == 63);
|
||||
REQUIRE(value3 == 63);
|
||||
}
|
||||
|
||||
TEST_CASE("Can disconnect inside slot", "[signal]")
|
||||
{
|
||||
signal<void(int)> valueChanged;
|
||||
|
||||
int value1 = 0;
|
||||
int value2 = 0;
|
||||
int value3 = 0;
|
||||
connection conn2;
|
||||
valueChanged.connect([&value1](int value) {
|
||||
value1 = value;
|
||||
});
|
||||
conn2 = valueChanged.connect([&](int value) {
|
||||
value2 = value;
|
||||
conn2.disconnect();
|
||||
});
|
||||
valueChanged.connect([&value3](int value) {
|
||||
value3 = value;
|
||||
});
|
||||
REQUIRE(value1 == 0);
|
||||
REQUIRE(value2 == 0);
|
||||
REQUIRE(value3 == 0);
|
||||
|
||||
valueChanged(63);
|
||||
REQUIRE(value1 == 63);
|
||||
REQUIRE(value2 == 63);
|
||||
REQUIRE(value3 == 63);
|
||||
|
||||
valueChanged(101);
|
||||
REQUIRE(value1 == 101);
|
||||
REQUIRE(value2 == 63); // disconnected in slot.
|
||||
REQUIRE(value3 == 101);
|
||||
}
|
||||
|
||||
TEST_CASE("Disconnects OK if signal dead first", "[signal]")
|
||||
{
|
||||
connection conn2;
|
||||
{
|
||||
scoped_connection conn1;
|
||||
{
|
||||
signal<void(int)> valueChanged;
|
||||
conn2 = valueChanged.connect([](int) {
|
||||
});
|
||||
// Just unused.
|
||||
valueChanged.connect([](int) {
|
||||
});
|
||||
conn1 = valueChanged.connect([](int) {
|
||||
});
|
||||
}
|
||||
REQUIRE(conn2.connected());
|
||||
REQUIRE(conn1.connected());
|
||||
conn2.disconnect();
|
||||
REQUIRE(!conn2.connected());
|
||||
REQUIRE(conn1.connected());
|
||||
}
|
||||
conn2.disconnect();
|
||||
}
|
||||
|
||||
TEST_CASE("Returns last called slot result with default combiner", "[signal]")
|
||||
{
|
||||
connection conn2;
|
||||
{
|
||||
scoped_connection conn1;
|
||||
{
|
||||
signal<int(int)> absSignal;
|
||||
conn2 = absSignal.connect([](int value) {
|
||||
return value * value;
|
||||
});
|
||||
conn1 = absSignal.connect([](int value) {
|
||||
return abs(value);
|
||||
});
|
||||
absSignal(-1);
|
||||
|
||||
REQUIRE(absSignal(45) == 45);
|
||||
REQUIRE(absSignal(-1) == 1);
|
||||
REQUIRE(absSignal(-177) == 177);
|
||||
REQUIRE(absSignal(0) == 0);
|
||||
}
|
||||
REQUIRE(conn2.connected());
|
||||
conn2.disconnect();
|
||||
REQUIRE(!conn2.connected());
|
||||
}
|
||||
conn2.disconnect();
|
||||
REQUIRE(!conn2.connected());
|
||||
}
|
||||
|
||||
TEST_CASE("Works with custom any_of combiner", "[signal]")
|
||||
{
|
||||
using cancellable_signal = signal<bool(std::string), any_of_combiner>;
|
||||
cancellable_signal startRequested;
|
||||
auto conn1 = startRequested.connect([](std::string op) {
|
||||
return op == "1";
|
||||
});
|
||||
auto conn2 = startRequested.connect([](std::string op) {
|
||||
return op == "1" || op == "2";
|
||||
});
|
||||
REQUIRE(startRequested("0") == false);
|
||||
REQUIRE(startRequested("1") == true);
|
||||
REQUIRE(startRequested("2") == true);
|
||||
REQUIRE(startRequested("3") == false);
|
||||
conn1.disconnect();
|
||||
conn2.disconnect();
|
||||
REQUIRE(startRequested("0") == false);
|
||||
REQUIRE(startRequested("1") == false);
|
||||
REQUIRE(startRequested("2") == false);
|
||||
REQUIRE(startRequested("3") == false);
|
||||
}
|
||||
|
||||
TEST_CASE("Can release scoped connection", "[signal]")
|
||||
{
|
||||
int value2 = 0;
|
||||
int value3 = 0;
|
||||
signal<void(int)> valueChanged;
|
||||
connection conn1;
|
||||
{
|
||||
scoped_connection conn2;
|
||||
scoped_connection conn3;
|
||||
conn2 = valueChanged.connect([&value2](int x) {
|
||||
value2 = x;
|
||||
});
|
||||
conn3 = valueChanged.connect([&value3](int x) {
|
||||
value3 = x;
|
||||
});
|
||||
|
||||
valueChanged(42);
|
||||
REQUIRE(value2 == 42);
|
||||
REQUIRE(value3 == 42);
|
||||
REQUIRE(conn2.connected());
|
||||
REQUIRE(conn3.connected());
|
||||
REQUIRE(!conn1.connected());
|
||||
|
||||
conn1 = conn3.release();
|
||||
REQUIRE(conn2.connected());
|
||||
REQUIRE(!conn3.connected());
|
||||
REQUIRE(conn1.connected());
|
||||
valueChanged(144);
|
||||
REQUIRE(value2 == 144);
|
||||
REQUIRE(value3 == 144);
|
||||
}
|
||||
|
||||
// conn2 disconnected, conn1 connected.
|
||||
valueChanged(17);
|
||||
REQUIRE(value2 == 144);
|
||||
REQUIRE(value3 == 17);
|
||||
REQUIRE(conn1.connected());
|
||||
|
||||
conn1.disconnect();
|
||||
valueChanged(90);
|
||||
REQUIRE(value2 == 144);
|
||||
REQUIRE(value3 == 17);
|
||||
}
|
||||
|
||||
TEST_CASE("Can use signal with more than one argument", "[signal]")
|
||||
{
|
||||
signal<void(int, std::string, std::vector<std::string>)> event;
|
||||
|
||||
int value1 = 0;
|
||||
std::string value2;
|
||||
std::vector<std::string> value3;
|
||||
event.connect([&](int v1, const std::string& v2, const std::vector<std::string>& v3) {
|
||||
value1 = v1;
|
||||
value2 = v2;
|
||||
value3 = v3;
|
||||
});
|
||||
|
||||
event(9815, "using namespace std::literals!"s, std::vector{ "std::vector"s, "using namespace std::literals"s });
|
||||
REQUIRE(value1 == 9815);
|
||||
REQUIRE(value2 == "using namespace std::literals!"s);
|
||||
REQUIRE(value3 == std::vector{ "std::vector"s, "using namespace std::literals"s });
|
||||
}
|
||||
|
||||
TEST_CASE("Can blocks slots using shared_connection_block", "[signal]")
|
||||
{
|
||||
bool callbackShouldBeCalled = true;
|
||||
bool callbackCalled = false;
|
||||
const int value = 123;
|
||||
signal<void(int)> event;
|
||||
auto conn = event.connect([&](int gotValue) {
|
||||
CHECK(gotValue == value);
|
||||
callbackCalled = true;
|
||||
if (!callbackShouldBeCalled)
|
||||
{
|
||||
FAIL("callback is blocked and should not be called");
|
||||
}
|
||||
},
|
||||
advanced_tag{});
|
||||
event(value);
|
||||
REQUIRE(callbackCalled);
|
||||
shared_connection_block block(conn);
|
||||
callbackShouldBeCalled = false;
|
||||
callbackCalled = false;
|
||||
event(value);
|
||||
REQUIRE(!callbackCalled);
|
||||
block.unblock();
|
||||
callbackShouldBeCalled = true;
|
||||
event(value);
|
||||
REQUIRE(callbackCalled);
|
||||
}
|
||||
|
||||
TEST_CASE("Other slots are unaffected by the block", "[signal]")
|
||||
{
|
||||
bool callback1Called = false;
|
||||
bool callback2Called = false;
|
||||
const int value = 123;
|
||||
signal<void(int)> event;
|
||||
auto conn1 = event.connect([&](int gotValue) {
|
||||
CHECK(gotValue == value);
|
||||
callback1Called = true;
|
||||
},
|
||||
advanced_tag{});
|
||||
auto conn2 = event.connect([&](int) {
|
||||
callback2Called = true;
|
||||
FAIL("callback is blocked and should not be called");
|
||||
},
|
||||
advanced_tag{});
|
||||
shared_connection_block block(conn2);
|
||||
event(value);
|
||||
REQUIRE(callback1Called);
|
||||
REQUIRE(!callback2Called);
|
||||
}
|
||||
|
||||
TEST_CASE("Multiple blocks block until last one is unblocked", "[signal]")
|
||||
{
|
||||
bool callbackShouldBeCalled = false;
|
||||
bool callbackCalled = false;
|
||||
const int value = 123;
|
||||
signal<void(int)> event;
|
||||
auto conn = event.connect([&](int gotValue) {
|
||||
CHECK(gotValue == value);
|
||||
callbackCalled = true;
|
||||
if (!callbackShouldBeCalled)
|
||||
{
|
||||
FAIL("callback is blocked and should not be called");
|
||||
}
|
||||
},
|
||||
advanced_tag{});
|
||||
shared_connection_block block1(conn);
|
||||
shared_connection_block block2(conn);
|
||||
event(value);
|
||||
REQUIRE(!callbackCalled);
|
||||
block1.unblock();
|
||||
event(value);
|
||||
REQUIRE(!callbackCalled);
|
||||
block1.block();
|
||||
block2.unblock();
|
||||
event(value);
|
||||
REQUIRE(!callbackCalled);
|
||||
block1.unblock();
|
||||
callbackShouldBeCalled = true;
|
||||
event(value);
|
||||
REQUIRE(callbackCalled);
|
||||
}
|
||||
|
||||
TEST_CASE("Can copy and move shared_connection_block objects", "[signal]")
|
||||
{
|
||||
bool callbackShouldBeCalled = false;
|
||||
bool callbackCalled = false;
|
||||
const int value = 123;
|
||||
signal<void(int)> event;
|
||||
auto conn = event.connect([&](int gotValue) {
|
||||
CHECK(gotValue == value);
|
||||
callbackCalled = true;
|
||||
if (!callbackShouldBeCalled)
|
||||
{
|
||||
FAIL("callback is blocked and should not be called");
|
||||
}
|
||||
},
|
||||
advanced_tag{});
|
||||
shared_connection_block block1(conn);
|
||||
|
||||
shared_connection_block block2(block1);
|
||||
event(value);
|
||||
REQUIRE(block1.blocking());
|
||||
REQUIRE(block2.blocking());
|
||||
REQUIRE(!callbackCalled);
|
||||
|
||||
shared_connection_block block3(std::move(block2));
|
||||
event(value);
|
||||
REQUIRE(block1.blocking());
|
||||
REQUIRE(!block2.blocking());
|
||||
REQUIRE(block3.blocking());
|
||||
REQUIRE(!callbackCalled);
|
||||
|
||||
block2 = block3;
|
||||
event(value);
|
||||
REQUIRE(block1.blocking());
|
||||
REQUIRE(block2.blocking());
|
||||
REQUIRE(block3.blocking());
|
||||
REQUIRE(!callbackCalled);
|
||||
|
||||
block3 = std::move(block2);
|
||||
event(value);
|
||||
REQUIRE(block1.blocking());
|
||||
REQUIRE(!block2.blocking());
|
||||
REQUIRE(block3.blocking());
|
||||
REQUIRE(!callbackCalled);
|
||||
|
||||
block3 = shared_connection_block(conn, false);
|
||||
event(value);
|
||||
REQUIRE(block1.blocking());
|
||||
REQUIRE(!block2.blocking());
|
||||
REQUIRE(!block3.blocking());
|
||||
REQUIRE(!callbackCalled);
|
||||
|
||||
block1.unblock();
|
||||
callbackShouldBeCalled = true;
|
||||
event(value);
|
||||
REQUIRE(!block1.blocking());
|
||||
REQUIRE(!block2.blocking());
|
||||
REQUIRE(!block3.blocking());
|
||||
REQUIRE(callbackCalled);
|
||||
}
|
||||
|
||||
TEST_CASE("Unblocks when shared_connection_block goes out of scope")
|
||||
{
|
||||
bool callbackCalled = false;
|
||||
const int value = 123;
|
||||
signal<void(int)> event;
|
||||
auto conn = event.connect([&](int gotValue) {
|
||||
CHECK(gotValue == value);
|
||||
callbackCalled = true;
|
||||
},
|
||||
advanced_tag{});
|
||||
|
||||
callbackCalled = false;
|
||||
event(value);
|
||||
CHECK(callbackCalled);
|
||||
|
||||
{
|
||||
callbackCalled = false;
|
||||
shared_connection_block block(conn);
|
||||
event(value);
|
||||
CHECK(!callbackCalled);
|
||||
|
||||
{
|
||||
callbackCalled = false;
|
||||
shared_connection_block block2(conn);
|
||||
event(value);
|
||||
CHECK(!callbackCalled);
|
||||
}
|
||||
}
|
||||
|
||||
callbackCalled = false;
|
||||
event(value);
|
||||
CHECK(callbackCalled);
|
||||
}
|
||||
|
||||
TEST_CASE("Can disconnect advanced slot using advanced_scoped_connection", "[signal]")
|
||||
{
|
||||
signal<void(int)> valueChanged;
|
||||
|
||||
int value1 = 0;
|
||||
int value2 = 0;
|
||||
int value3 = 0;
|
||||
{
|
||||
advanced_scoped_connection conn1 = valueChanged.connect([&value1](int value) {
|
||||
value1 = value;
|
||||
},
|
||||
advanced_tag{});
|
||||
{
|
||||
advanced_scoped_connection conn2 = valueChanged.connect([&value2](int value) {
|
||||
value2 = value;
|
||||
},
|
||||
advanced_tag{});
|
||||
valueChanged.connect([&value3](int value) {
|
||||
value3 = value;
|
||||
});
|
||||
REQUIRE(value1 == 0);
|
||||
REQUIRE(value2 == 0);
|
||||
REQUIRE(value3 == 0);
|
||||
|
||||
valueChanged(10);
|
||||
REQUIRE(value1 == 10);
|
||||
REQUIRE(value2 == 10);
|
||||
REQUIRE(value3 == 10);
|
||||
}
|
||||
|
||||
// conn2 disconnected.
|
||||
valueChanged(-99);
|
||||
REQUIRE(value1 == -99);
|
||||
REQUIRE(value2 == 10);
|
||||
REQUIRE(value3 == -99);
|
||||
}
|
||||
|
||||
// conn1 disconnected.
|
||||
valueChanged(17);
|
||||
REQUIRE(value1 == -99);
|
||||
REQUIRE(value2 == 10);
|
||||
REQUIRE(value3 == 17);
|
||||
}
|
||||
|
||||
TEST_CASE("Can move signal", "[signal]")
|
||||
{
|
||||
signal<void()> src;
|
||||
|
||||
int srcFireCount = 0;
|
||||
auto srcConn = src.connect([&srcFireCount] {
|
||||
++srcFireCount;
|
||||
});
|
||||
|
||||
src();
|
||||
REQUIRE(srcFireCount == 1);
|
||||
|
||||
auto dst = std::move(src);
|
||||
|
||||
int dstFireCount = 0;
|
||||
auto dstConn = dst.connect([&dstFireCount] {
|
||||
++dstFireCount;
|
||||
});
|
||||
|
||||
dst();
|
||||
REQUIRE(srcFireCount == 2);
|
||||
REQUIRE(dstFireCount == 1);
|
||||
|
||||
srcConn.disconnect();
|
||||
dstConn.disconnect();
|
||||
dst();
|
||||
REQUIRE(srcFireCount == 2);
|
||||
REQUIRE(dstFireCount == 1);
|
||||
}
|
||||
|
||||
TEST_CASE("Can swap signals", "[signal]")
|
||||
{
|
||||
signal<void()> s1;
|
||||
signal<void()> s2;
|
||||
|
||||
int s1FireCount = 0;
|
||||
int s2FireCount = 0;
|
||||
|
||||
s1.connect([&s1FireCount] {
|
||||
++s1FireCount;
|
||||
});
|
||||
|
||||
s2.connect([&s2FireCount] {
|
||||
++s2FireCount;
|
||||
});
|
||||
|
||||
std::swap(s1, s2);
|
||||
|
||||
s1();
|
||||
REQUIRE(s1FireCount == 0);
|
||||
REQUIRE(s2FireCount == 1);
|
||||
|
||||
s2();
|
||||
REQUIRE(s1FireCount == 1);
|
||||
REQUIRE(s2FireCount == 1);
|
||||
}
|
||||
|
||||
TEST_CASE("Signal can be destroyed inside its slot and will call the rest of its slots", "[signal]")
|
||||
{
|
||||
std::optional<signal<void()>> s;
|
||||
s.emplace();
|
||||
s->connect([&] {
|
||||
s.reset();
|
||||
});
|
||||
bool called = false;
|
||||
s->connect([&] {
|
||||
called = true;
|
||||
});
|
||||
(*s)();
|
||||
CHECK(called);
|
||||
}
|
||||
|
||||
TEST_CASE("Signal can be used as a slot for another signal", "[signal]")
|
||||
{
|
||||
signal<void()> s1;
|
||||
bool called = false;
|
||||
s1.connect([&] {
|
||||
called = true;
|
||||
});
|
||||
|
||||
signal<void()> s2;
|
||||
s2.connect(s1);
|
||||
|
||||
s2();
|
||||
|
||||
CHECK(called);
|
||||
}
|
||||
|
||||
// memory leak fix
|
||||
TEST_CASE("Releases lambda and its captured const data", "[signal]")
|
||||
{
|
||||
struct Captured
|
||||
{
|
||||
Captured(bool& released)
|
||||
: m_released(released)
|
||||
{
|
||||
}
|
||||
|
||||
~Captured()
|
||||
{
|
||||
m_released = true;
|
||||
}
|
||||
|
||||
private:
|
||||
bool& m_released;
|
||||
};
|
||||
|
||||
bool released = false;
|
||||
|
||||
{
|
||||
const auto captured = std::make_shared<Captured>(released);
|
||||
|
||||
signal<void()> changeSignal;
|
||||
changeSignal.connect([captured]{});
|
||||
}
|
||||
|
||||
CHECK(released);
|
||||
}
|
||||
Reference in New Issue
Block a user