commit b9c17f950693427c6511d39c5af9ba2a4e63a319 Author: Timothy Prepscius Date: Wed Feb 25 12:28:38 2026 -0500 flatten 20260225 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..54958c9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.DS_Store +*.pyc +xcuserdata +.bin diff --git a/Core_Future.xcodeproj/project.pbxproj b/Core_Future.xcodeproj/project.pbxproj new file mode 100644 index 0000000..a96fb46 --- /dev/null +++ b/Core_Future.xcodeproj/project.pbxproj @@ -0,0 +1,683 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 55; + objects = { + +/* Begin PBXBuildFile section */ + F608AA822826BE2A005C276B /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F608AA812826BE2A005C276B /* main.cpp */; }; + F608AA882826BE82005C276B /* libCore_Zero.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F608AA872826BE82005C276B /* libCore_Zero.a */; }; + F608AA892826BE82005C276B /* libCore_Future.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F608A9BF2826BC54005C276B /* libCore_Future.a */; }; + F608AA8C2826BEAD005C276B /* Futures.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F608A9CF2826BCB6005C276B /* Futures.cpp */; }; + F608AA8D2826BF2A005C276B /* PromiseLocked.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F608A9CC2826BCB6005C276B /* PromiseLocked.cpp */; }; + F608AA8E2826BF2C005C276B /* FutureChain.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F608A9D62826BCB6005C276B /* FutureChain.cpp */; }; + F60A19B22845794A0040CD24 /* PromiseOfFutures.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F608A9E62826BCB6005C276B /* PromiseOfFutures.cpp */; }; + F633E93E2915BF58007A4C26 /* after.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F633E93D2915B970007A4C26 /* after.cpp */; }; + F6971F37282B119C008FBD17 /* Futures.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F608A9CF2826BCB6005C276B /* Futures.cpp */; }; + F6A8B2B52A64227F00E4FDC7 /* Future.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F608A9DC2826BCB6005C276B /* Future.cpp */; }; + F6CC6A2D2D076B7300D533B7 /* FutureErase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6CC6A2C2D076B7300D533B7 /* FutureErase.cpp */; }; + F6CC6A312D07771200D533B7 /* FutureResult.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6CC6A302D07771200D533B7 /* FutureResult.cpp */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + F608AA8A2826BE98005C276B /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = F608A9B72826BC54005C276B /* Project object */; + proxyType = 1; + remoteGlobalIDString = F608A9BE2826BC54005C276B; + remoteInfo = Core_Future; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + F608AA7D2826BE2A005C276B /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + F60582782EC24B14008FE966 /* weak_future_consume.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = weak_future_consume.hpp; sourceTree = ""; }; + F608A9BF2826BC54005C276B /* libCore_Future.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libCore_Future.a; sourceTree = BUILT_PRODUCTS_DIR; }; + F608A9C82826BCB6005C276B /* FutureChain.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FutureChain.h; sourceTree = ""; }; + F608A9C92826BCB6005C276B /* PromiseOfFutures.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PromiseOfFutures.h; sourceTree = ""; }; + F608A9CA2826BCB6005C276B /* PromiseOfFutures.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = PromiseOfFutures.hpp; sourceTree = ""; }; + F608A9CB2826BCB6005C276B /* FutureChain.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = FutureChain.hpp; sourceTree = ""; }; + F608A9CC2826BCB6005C276B /* PromiseLocked.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = PromiseLocked.cpp; sourceTree = ""; }; + F608A9CD2826BCB6005C276B /* Future.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Future.h; sourceTree = ""; }; + F608A9CE2826BCB6005C276B /* WorkPromise.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WorkPromise.h; sourceTree = ""; }; + F608A9CF2826BCB6005C276B /* Futures.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Futures.cpp; sourceTree = ""; }; + F608A9D02826BCB6005C276B /* Future.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Future.hpp; sourceTree = ""; }; + F608A9D22826BCB6005C276B /* Future.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Future.h; sourceTree = ""; }; + F608A9D32826BCB6005C276B /* FutureEvent.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = FutureEvent.hpp; sourceTree = ""; }; + F608A9D42826BCB6005C276B /* WorkPromise.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = WorkPromise.hpp; sourceTree = ""; }; + F608A9D52826BCB6005C276B /* PromiseLocked.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = PromiseLocked.hpp; sourceTree = ""; }; + F608A9D62826BCB6005C276B /* FutureChain.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = FutureChain.cpp; sourceTree = ""; }; + F608A9D72826BCB6005C276B /* Futures.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Futures.h; sourceTree = ""; }; + F608A9D82826BCB6005C276B /* PromiseLocked.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PromiseLocked.h; sourceTree = ""; }; + F608A9DA2826BCB6005C276B /* Future.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Future.h; sourceTree = ""; }; + F608A9DB2826BCB6005C276B /* Future.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Future.hpp; sourceTree = ""; }; + F608A9DC2826BCB6005C276B /* Future.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Future.cpp; sourceTree = ""; }; + F608A9DD2826BCB6005C276B /* Future_.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Future_.h; sourceTree = ""; }; + F608A9DE2826BCB6005C276B /* Future_.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Future_.hpp; sourceTree = ""; }; + F608A9DF2826BCB6005C276B /* Future_void.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Future_void.hpp; sourceTree = ""; }; + F608A9E02826BCB6005C276B /* Future_Requirements.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Future_Requirements.hpp; sourceTree = ""; }; + F608A9E22826BCB6005C276B /* Future_void.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Future_void.h; sourceTree = ""; }; + F608A9E32826BCB6005C276B /* Future.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Future.cpp; sourceTree = ""; }; + F608A9E52826BCB6005C276B /* Future.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Future.h; sourceTree = ""; }; + F608A9E62826BCB6005C276B /* PromiseOfFutures.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = PromiseOfFutures.cpp; sourceTree = ""; }; + F608A9E82826BCB6005C276B /* Future.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Future.h; sourceTree = ""; }; + F608A9E92826BCB6005C276B /* Futures.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Futures.hpp; sourceTree = ""; }; + F608AA7F2826BE2A005C276B /* Core_Future_Tests */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = Core_Future_Tests; sourceTree = BUILT_PRODUCTS_DIR; }; + F608AA812826BE2A005C276B /* main.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = ""; }; + F608AA872826BE82005C276B /* libCore_Zero.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libCore_Zero.a; sourceTree = BUILT_PRODUCTS_DIR; }; + F608AB692827F3BB005C276B /* Makefile.def */ = {isa = PBXFileReference; lastKnownFileType = text; path = Makefile.def; sourceTree = ""; }; + F608AB6A2827F3BC005C276B /* Makefile.project */ = {isa = PBXFileReference; lastKnownFileType = text; path = Makefile.project; sourceTree = ""; }; + F61F9BF12C6E4DFC00F79137 /* Makefile.project */ = {isa = PBXFileReference; lastKnownFileType = text; path = Makefile.project; sourceTree = ""; }; + F62757BA2B307D7C00655557 /* future_handle_exception.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = future_handle_exception.hpp; sourceTree = ""; }; + F633E93C2915B72B007A4C26 /* after.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = after.hpp; sourceTree = ""; }; + F633E93D2915B970007A4C26 /* after.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = after.cpp; sourceTree = ""; }; + F635F7C82E3B950B00E3D1D6 /* future_is_exception.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = future_is_exception.hpp; sourceTree = ""; }; + F63DCC5C2EDA451D003BEE7C /* future_on_exception_what.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = future_on_exception_what.hpp; sourceTree = ""; }; + F63DCC5D2EDA5CE9003BEE7C /* future_on_exception_value.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = future_on_exception_value.hpp; sourceTree = ""; }; + F66A9DEA290C641600AA74BD /* future_on_exception.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = future_on_exception.hpp; sourceTree = ""; }; + F676CAC12E9211A700BE5ACC /* future_success.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = future_success.hpp; sourceTree = ""; }; + F6865CAE289C0B5F00A46111 /* FutureResult_v1.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = FutureResult_v1.hpp; sourceTree = ""; }; + F6865CAF289C0C6700A46111 /* FutureResult.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FutureResult.h; sourceTree = ""; }; + F6971F3C282B119C008FBD17 /* libCore_Future_iOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libCore_Future_iOS.a; sourceTree = BUILT_PRODUCTS_DIR; }; + F6984F512EF34B6800718723 /* future_discard_exception.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = future_discard_exception.hpp; sourceTree = ""; }; + F6B4CFC12A6D7303004B9AB5 /* WeakFuture.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = WeakFuture.hpp; sourceTree = ""; }; + F6BF9BE52E390216002E6AF0 /* Makefile */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = ""; }; + F6CC6A2B2D076B5D00D533B7 /* FutureErase.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = FutureErase.hpp; sourceTree = ""; }; + F6CC6A2C2D076B7300D533B7 /* FutureErase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FutureErase.cpp; sourceTree = ""; }; + F6CC6A2E2D076BEB00D533B7 /* FutureResult_v2.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = FutureResult_v2.hpp; sourceTree = ""; }; + F6CC6A2F2D076C1500D533B7 /* FutureResult.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = FutureResult.hpp; sourceTree = ""; }; + F6CC6A302D07771200D533B7 /* FutureResult.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = FutureResult.cpp; sourceTree = ""; }; + F6DDE7012DAABA93005F94FC /* after_using.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = after_using.hpp; sourceTree = ""; }; + F6F53DD528F5A9F000E878EF /* FutureStrong.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = FutureStrong.hpp; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + F608A9BD2826BC54005C276B /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F608AA7C2826BE2A005C276B /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + F608AA892826BE82005C276B /* libCore_Future.a in Frameworks */, + F608AA882826BE82005C276B /* libCore_Zero.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F6971F38282B119C008FBD17 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + F608A9B62826BC54005C276B = { + isa = PBXGroup; + children = ( + F608AA862826BE82005C276B /* Frameworks */, + F6BF9BE52E390216002E6AF0 /* Makefile */, + F608AB692827F3BB005C276B /* Makefile.def */, + F608AB6A2827F3BC005C276B /* Makefile.project */, + F608A9C02826BC54005C276B /* Products */, + F608AA802826BE2A005C276B /* tests */, + F61D7C422E38168F002A1AED /* tjp */, + ); + sourceTree = ""; + }; + F608A9C02826BC54005C276B /* Products */ = { + isa = PBXGroup; + children = ( + F608A9BF2826BC54005C276B /* libCore_Future.a */, + F608AA7F2826BE2A005C276B /* Core_Future_Tests */, + F6971F3C282B119C008FBD17 /* libCore_Future_iOS.a */, + ); + name = Products; + sourceTree = ""; + }; + F608A9C62826BCB6005C276B /* core */ = { + isa = PBXGroup; + children = ( + F608A9C72826BCB6005C276B /* future */, + ); + path = core; + sourceTree = ""; + }; + F608A9C72826BCB6005C276B /* future */ = { + isa = PBXGroup; + children = ( + F61F9BF22C6E4E1600F79137 /* _tests */, + F633E93C2915B72B007A4C26 /* after.hpp */, + F6DDE7012DAABA93005F94FC /* after_using.hpp */, + F608A9D12826BCB6005C276B /* boost */, + F608A9D92826BCB6005C276B /* custom */, + F608A9E72826BCB6005C276B /* folly */, + F62757BA2B307D7C00655557 /* future_handle_exception.hpp */, + F66A9DEA290C641600AA74BD /* future_on_exception.hpp */, + F635F7C82E3B950B00E3D1D6 /* future_is_exception.hpp */, + F63DCC5C2EDA451D003BEE7C /* future_on_exception_what.hpp */, + F63DCC5D2EDA5CE9003BEE7C /* future_on_exception_value.hpp */, + F6984F512EF34B6800718723 /* future_discard_exception.hpp */, + F676CAC12E9211A700BE5ACC /* future_success.hpp */, + F608A9CD2826BCB6005C276B /* Future.h */, + F608A9D02826BCB6005C276B /* Future.hpp */, + F60582782EC24B14008FE966 /* weak_future_consume.hpp */, + F608A9C82826BCB6005C276B /* FutureChain.h */, + F608A9CB2826BCB6005C276B /* FutureChain.hpp */, + F6CC6A2B2D076B5D00D533B7 /* FutureErase.hpp */, + F608A9D32826BCB6005C276B /* FutureEvent.hpp */, + F6865CAF289C0C6700A46111 /* FutureResult.h */, + F6865CAE289C0B5F00A46111 /* FutureResult_v1.hpp */, + F6CC6A2E2D076BEB00D533B7 /* FutureResult_v2.hpp */, + F6CC6A2F2D076C1500D533B7 /* FutureResult.hpp */, + F608A9CF2826BCB6005C276B /* Futures.cpp */, + F608A9D72826BCB6005C276B /* Futures.h */, + F608A9E92826BCB6005C276B /* Futures.hpp */, + F6F53DD528F5A9F000E878EF /* FutureStrong.hpp */, + F608A9E42826BCB6005C276B /* liblw */, + F608A9D82826BCB6005C276B /* PromiseLocked.h */, + F608A9D52826BCB6005C276B /* PromiseLocked.hpp */, + F608A9C92826BCB6005C276B /* PromiseOfFutures.h */, + F608A9CA2826BCB6005C276B /* PromiseOfFutures.hpp */, + F6B4CFC12A6D7303004B9AB5 /* WeakFuture.hpp */, + F608A9CE2826BCB6005C276B /* WorkPromise.h */, + F608A9D42826BCB6005C276B /* WorkPromise.hpp */, + ); + path = future; + sourceTree = ""; + }; + F608A9D12826BCB6005C276B /* boost */ = { + isa = PBXGroup; + children = ( + F608A9D22826BCB6005C276B /* Future.h */, + ); + path = boost; + sourceTree = ""; + }; + F608A9D92826BCB6005C276B /* custom */ = { + isa = PBXGroup; + children = ( + F61F9BF32C6E4E3800F79137 /* _tests */, + F608A9DA2826BCB6005C276B /* Future.h */, + F608A9DB2826BCB6005C276B /* Future.hpp */, + F608A9DD2826BCB6005C276B /* Future_.h */, + F608A9DE2826BCB6005C276B /* Future_.hpp */, + F608A9DF2826BCB6005C276B /* Future_void.hpp */, + F608A9E02826BCB6005C276B /* Future_Requirements.hpp */, + F608A9E22826BCB6005C276B /* Future_void.h */, + F608A9E32826BCB6005C276B /* Future.cpp */, + ); + path = custom; + sourceTree = ""; + }; + F608A9E42826BCB6005C276B /* liblw */ = { + isa = PBXGroup; + children = ( + F608A9E52826BCB6005C276B /* Future.h */, + ); + path = liblw; + sourceTree = ""; + }; + F608A9E72826BCB6005C276B /* folly */ = { + isa = PBXGroup; + children = ( + F608A9E82826BCB6005C276B /* Future.h */, + ); + path = folly; + sourceTree = ""; + }; + F608AA802826BE2A005C276B /* tests */ = { + isa = PBXGroup; + children = ( + F61F9BF12C6E4DFC00F79137 /* Makefile.project */, + F608AA812826BE2A005C276B /* main.cpp */, + ); + path = tests; + sourceTree = ""; + }; + F608AA862826BE82005C276B /* Frameworks */ = { + isa = PBXGroup; + children = ( + F608AA872826BE82005C276B /* libCore_Zero.a */, + ); + name = Frameworks; + sourceTree = ""; + }; + F61D7C422E38168F002A1AED /* tjp */ = { + isa = PBXGroup; + children = ( + F608A9C62826BCB6005C276B /* core */, + ); + path = tjp; + sourceTree = ""; + }; + F61F9BF22C6E4E1600F79137 /* _tests */ = { + isa = PBXGroup; + children = ( + F6CC6A2C2D076B7300D533B7 /* FutureErase.cpp */, + F6CC6A302D07771200D533B7 /* FutureResult.cpp */, + F633E93D2915B970007A4C26 /* after.cpp */, + F608A9CC2826BCB6005C276B /* PromiseLocked.cpp */, + F608A9E62826BCB6005C276B /* PromiseOfFutures.cpp */, + F608A9D62826BCB6005C276B /* FutureChain.cpp */, + ); + path = _tests; + sourceTree = ""; + }; + F61F9BF32C6E4E3800F79137 /* _tests */ = { + isa = PBXGroup; + children = ( + F608A9DC2826BCB6005C276B /* Future.cpp */, + ); + path = _tests; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + F608A9BB2826BC54005C276B /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F6971F35282B119C008FBD17 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + F608A9BE2826BC54005C276B /* Core_Future */ = { + isa = PBXNativeTarget; + buildConfigurationList = F608A9C32826BC54005C276B /* Build configuration list for PBXNativeTarget "Core_Future" */; + buildPhases = ( + F608A9BB2826BC54005C276B /* Headers */, + F608A9BC2826BC54005C276B /* Sources */, + F608A9BD2826BC54005C276B /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Core_Future; + productName = Core_Future; + productReference = F608A9BF2826BC54005C276B /* libCore_Future.a */; + productType = "com.apple.product-type.library.static"; + }; + F608AA7E2826BE2A005C276B /* Core_Future_Tests */ = { + isa = PBXNativeTarget; + buildConfigurationList = F608AA832826BE2A005C276B /* Build configuration list for PBXNativeTarget "Core_Future_Tests" */; + buildPhases = ( + F608AA7B2826BE2A005C276B /* Sources */, + F608AA7C2826BE2A005C276B /* Frameworks */, + F608AA7D2826BE2A005C276B /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + F608AA8B2826BE98005C276B /* PBXTargetDependency */, + ); + name = Core_Future_Tests; + productName = Core_Future_Tests; + productReference = F608AA7F2826BE2A005C276B /* Core_Future_Tests */; + productType = "com.apple.product-type.tool"; + }; + F6971F34282B119C008FBD17 /* Core_Future_iOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = F6971F39282B119C008FBD17 /* Build configuration list for PBXNativeTarget "Core_Future_iOS" */; + buildPhases = ( + F6971F35282B119C008FBD17 /* Headers */, + F6971F36282B119C008FBD17 /* Sources */, + F6971F38282B119C008FBD17 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Core_Future_iOS; + productName = Core_Future; + productReference = F6971F3C282B119C008FBD17 /* libCore_Future_iOS.a */; + productType = "com.apple.product-type.library.static"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + F608A9B72826BC54005C276B /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + DefaultBuildSystemTypeForWorkspace = Original; + LastUpgradeCheck = 1330; + TargetAttributes = { + F608A9BE2826BC54005C276B = { + CreatedOnToolsVersion = 13.3; + }; + F608AA7E2826BE2A005C276B = { + CreatedOnToolsVersion = 13.3; + }; + }; + }; + buildConfigurationList = F608A9BA2826BC54005C276B /* Build configuration list for PBXProject "Core_Future" */; + compatibilityVersion = "Xcode 13.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = F608A9B62826BC54005C276B; + productRefGroup = F608A9C02826BC54005C276B /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + F608A9BE2826BC54005C276B /* Core_Future */, + F6971F34282B119C008FBD17 /* Core_Future_iOS */, + F608AA7E2826BE2A005C276B /* Core_Future_Tests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + F608A9BC2826BC54005C276B /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + F608AA8C2826BEAD005C276B /* Futures.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F608AA7B2826BE2A005C276B /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + F6A8B2B52A64227F00E4FDC7 /* Future.cpp in Sources */, + F6CC6A2D2D076B7300D533B7 /* FutureErase.cpp in Sources */, + F608AA822826BE2A005C276B /* main.cpp in Sources */, + F6CC6A312D07771200D533B7 /* FutureResult.cpp in Sources */, + F608AA8E2826BF2C005C276B /* FutureChain.cpp in Sources */, + F633E93E2915BF58007A4C26 /* after.cpp in Sources */, + F608AA8D2826BF2A005C276B /* PromiseLocked.cpp in Sources */, + F60A19B22845794A0040CD24 /* PromiseOfFutures.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F6971F36282B119C008FBD17 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + F6971F37282B119C008FBD17 /* Futures.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + F608AA8B2826BE98005C276B /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = F608A9BE2826BC54005C276B /* Core_Future */; + targetProxy = F608AA8A2826BE98005C276B /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + F608A9C12826BC54005C276B /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + ../Core_Zero, + ../Core_Misc, + ); + IPHONEOS_DEPLOYMENT_TARGET = 13.6; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + }; + name = Debug; + }; + F608A9C22826BC54005C276B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + ../Core_Zero, + ../Core_Misc, + ); + IPHONEOS_DEPLOYMENT_TARGET = 13.6; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = macosx; + }; + name = Release; + }; + F608A9C42826BC54005C276B /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = T2M28D3T75; + EXECUTABLE_PREFIX = lib; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + F608A9C52826BC54005C276B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = T2M28D3T75; + EXECUTABLE_PREFIX = lib; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + }; + name = Release; + }; + F608AA842826BE2A005C276B /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = T2M28D3T75; + ENABLE_HARDENED_RUNTIME = YES; + HEADER_SEARCH_PATHS = ( + "${inherited}", + ../Core_Future, + ); + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + F608AA852826BE2A005C276B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = T2M28D3T75; + ENABLE_HARDENED_RUNTIME = YES; + HEADER_SEARCH_PATHS = ( + "${inherited}", + ../Core_Future, + ); + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; + F6971F3A282B119C008FBD17 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = T2M28D3T75; + EXECUTABLE_PREFIX = lib; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + F6971F3B282B119C008FBD17 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = T2M28D3T75; + EXECUTABLE_PREFIX = lib; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + F608A9BA2826BC54005C276B /* Build configuration list for PBXProject "Core_Future" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + F608A9C12826BC54005C276B /* Debug */, + F608A9C22826BC54005C276B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + F608A9C32826BC54005C276B /* Build configuration list for PBXNativeTarget "Core_Future" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + F608A9C42826BC54005C276B /* Debug */, + F608A9C52826BC54005C276B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + F608AA832826BE2A005C276B /* Build configuration list for PBXNativeTarget "Core_Future_Tests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + F608AA842826BE2A005C276B /* Debug */, + F608AA852826BE2A005C276B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + F6971F39282B119C008FBD17 /* Build configuration list for PBXNativeTarget "Core_Future_iOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + F6971F3A282B119C008FBD17 /* Debug */, + F6971F3B282B119C008FBD17 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = F608A9B72826BC54005C276B /* Project object */; +} diff --git a/Core_Future.xcodeproj/xcshareddata/xcschemes/Core_Future_Tests.xcscheme b/Core_Future.xcodeproj/xcshareddata/xcschemes/Core_Future_Tests.xcscheme new file mode 100644 index 0000000..aef0113 --- /dev/null +++ b/Core_Future.xcodeproj/xcshareddata/xcschemes/Core_Future_Tests.xcscheme @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..f61a565 --- /dev/null +++ b/Makefile @@ -0,0 +1,2 @@ +ROOTDIR := $(realpath $(dir $(lastword $(MAKEFILE_LIST)))..) +include $(ROOTDIR)/Core_Make/tjp/Make/Makefile diff --git a/Makefile.def b/Makefile.def new file mode 100755 index 0000000..3d05612 --- /dev/null +++ b/Makefile.def @@ -0,0 +1,6 @@ +timprepscius.core.include := $(timprepscius.core.include) -I $(dir $(realpath $(lastword $(MAKEFILE_LIST)))) +timprepscius.core.link := $(timprepscius.core.link) -L $(dir $(realpath $(lastword $(MAKEFILE_LIST))))/.bin/$(OBJDIR) + +timprepscius.core_future.include := -I $(dir $(realpath $(lastword $(MAKEFILE_LIST)))) +timprepscius.core_future.link := -L $(dir $(realpath $(lastword $(MAKEFILE_LIST))))/.bin/$(OBJDIR) + diff --git a/Makefile.project b/Makefile.project new file mode 100755 index 0000000..c836ad1 --- /dev/null +++ b/Makefile.project @@ -0,0 +1,19 @@ +include $(MAKEDIR)/Makefile.base + +# use: ls -d tjp/core/*/ tjp/core/*/*/ | rev | cut -c 2- | rev | sed 's/$/ \\/' + +PROJECTS := \ + tjp/core/future \ + tjp/core/future/custom + +#SRC_PCH := tjp/core/Precompile.pch + +INCPATH := \ + $(timprepscius.libraries.cpp.include) \ + $(timprepscius.core.include) + +LIBFILE := libCore_Future.a + +COPYTO := $(LIBRARIES_PROJECT) + +include $(MAKEDIR)/Makefile.lib diff --git a/tests/Core_Future_Tests.txt b/tests/Core_Future_Tests.txt new file mode 100644 index 0000000..6df7029 --- /dev/null +++ b/tests/Core_Future_Tests.txt @@ -0,0 +1,2 @@ +20240815_23:58:27.748962 1eefafac0 | [testing] ius::core::log::Logs::activate logging activated +20240815_23:58:27.749167 1eefafac0 | [debug] ius::core::log::Logs::activate logging activated diff --git a/tests/Makefile b/tests/Makefile new file mode 120000 index 0000000..b8f87c1 --- /dev/null +++ b/tests/Makefile @@ -0,0 +1 @@ +../../Make/Makefile \ No newline at end of file diff --git a/tests/Makefile.project b/tests/Makefile.project new file mode 100755 index 0000000..26e3c8f --- /dev/null +++ b/tests/Makefile.project @@ -0,0 +1,31 @@ +include $(MAKEDIR)/Makefile.base + +# use: ls -d core/*/ core/*/*/ | rev | cut -c 2- | rev | sed 's/$/ \\/' + +PROJECTS := \ + . \ + ../core/future/_tests \ + ../core/future/custom/_tests \ + +INCPATH := \ + $(timprepscius.libraries.cpp.include) \ + $(timprepscius.core.include) + +LDPATH := $(timprepscius.libraries.cpp.link) + +LIBS := \ + -lCore_Zero \ + -lCore_Future \ + -lCore_Misc \ + -lz_ + +EXEFILE := Core_Future_Tests.exe + +#COPYTO := $(ROOTDIR)/.bin + +ifeq (Darwin,$(SYS_NAME)) + LIBS += -lc++ +endif + + +include $(MAKEDIR)/Makefile.bin diff --git a/tests/main.cpp b/tests/main.cpp new file mode 100644 index 0000000..2de48a2 --- /dev/null +++ b/tests/main.cpp @@ -0,0 +1,19 @@ +// TJP COPYRIGHT HEADER + +#define CATCH_CONFIG_RUNNER +#include + +#include + +using namespace tjp; +using namespace core; + +int main( int argc, char* argv[] ) +{ + xLogInitialize("Core_Future_Tests.txt"); + xLogActivateStory("testing"); + xLogActivateStory("debug"); + + int result = Catch::Session().run( argc, argv ); + return result; +} diff --git a/tjp/core/future/Future.h b/tjp/core/future/Future.h new file mode 100755 index 0000000..bbd53f4 --- /dev/null +++ b/tjp/core/future/Future.h @@ -0,0 +1,17 @@ +// TJP COPYRIGHT HEADER + +#pragma once + +#include "./custom/Future.h" +#include +#include + +namespace tjp { +namespace core { + +template struct is_future : std::false_type {}; +template struct is_future> : std::true_type {}; +template<> struct is_future> : std::true_type {}; + +} // namespace +} // namespace diff --git a/tjp/core/future/Future.hpp b/tjp/core/future/Future.hpp new file mode 100755 index 0000000..3b649ca --- /dev/null +++ b/tjp/core/future/Future.hpp @@ -0,0 +1,205 @@ +// TJP COPYRIGHT HEADER + +#pragma once + +#include "Future.h" +#include "./custom/Future.hpp" +#include + +namespace tjp { +namespace core { + +template +Promise &promise_of(Promise &p, F &&f) +{ + p.consume(f); + return p; +} + +template +auto future_of(F &&f) +{ + using R_Ref = decltype(f()); + using R = std::remove_reference_t; + + Promise promise; + promise.consume(f); + return promise.get_future(); +} + +template +auto future_of(F &&f, Args && ... args) +{ + using R_Ref = decltype(f(std::forward(args)...)); + using R = std::remove_reference_t; + + Promise promise; + promise.consume(f, std::forward(args)...); + return promise.get_future(); +} + +template +auto future_of_value(T &&t) +{ + using T_ = std::remove_reference_t; + Promise promise; + + promise.set_value(std::forward(t)); + return promise.get_future(); +} + +template +Future future_of_value(const T &t) +{ + Promise promise; + promise.set_value(t); + return promise.get_future(); +} + +inline +Future future_of_value() +{ + Promise promise; + promise.set_value(); + return promise.get_future(); +} + +template +Future future_of_exception(E &&e) +{ + Promise promise; + promise.set_exception(std::forward(e)); + return promise.get_future(); +} + +template +Future future_of_exception(const E &e) +{ + return future_of_exception(E(e)); +} + +template +auto future_with(F &&f) +{ + using R_Ref = decltype(f()); + using R = std::remove_reference_t; + + if constexpr (is_future::value) + { + using RV = typename R::value_type; + + try + { + return f(); + } + CORE_FUTURE_CATCH_BEGIN(e) + { + return future_of_exception(e); + } + CORE_FUTURE_CATCH_END + } + else + { + return future_of(f); + } +} + +template +auto future_with(F &&f, Args && ...args) +{ + using R_Ref = decltype(f(std::forward(args)...)); + using R = std::remove_reference_t; + + if constexpr (is_future::value) + { + using RV = typename R::value_type; + + try + { + return f(std::forward(args)...); + } + CORE_FUTURE_CATCH_BEGIN(e) + { + return future_of_exception(e); + } + CORE_FUTURE_CATCH_END + } + else + { + return future_of(f, std::forward(args)...); + } +} + +template +struct AsFuture_ +{ + T v; + + template + operator Future() + { + return future_of_value(std::move(v)); + } +}; + +template<> +struct AsFuture_ +{ + template + operator Future() + { + return future_of_value(); + } +} ; + +template +AsFuture_ as_future(T &&t) +{ + return AsFuture_> { std::forward(t) }; +} + +inline +AsFuture_ as_future() +{ + return AsFuture_ { }; +} + +template +struct AsFutureException_ +{ + T v; + + template + operator Future() + { + return future_of_exception(std::move(v)); + } +}; + +template +AsFutureException_ as_future_exception(T &&t) +{ + return AsFutureException_> { std::forward(t) }; +} + + +//template +//auto future_with(F f) -> decltype(f()) { +// using R = typename decltype(f())::value_type; +// try { +// return f(); +// } +// catch (Exception &e) { +// return future_of_exception(copy_of(e)); +// } +//} + + +//template::value, R>::type*> +//auto with(std::function &&f) { +// return f; +//} +// + +} // namespace +} // namespace diff --git a/tjp/core/future/FutureChain.h b/tjp/core/future/FutureChain.h new file mode 100755 index 0000000..fd2f408 --- /dev/null +++ b/tjp/core/future/FutureChain.h @@ -0,0 +1,4 @@ +// TJP COPYRIGHT HEADER + +#pragma once + diff --git a/tjp/core/future/FutureChain.hpp b/tjp/core/future/FutureChain.hpp new file mode 100755 index 0000000..3d5156e --- /dev/null +++ b/tjp/core/future/FutureChain.hpp @@ -0,0 +1,177 @@ +// TJP COPYRIGHT HEADER + +#pragma once + +#include "FutureChain.h" +#include "Futures.hpp" +#include +#include +#include +#include +#include + +namespace tjp { +namespace core { +namespace future_chain_detail { + +struct FutureParent +{ + virtual ~FutureParent() {} +} ; + +template +struct FutureExecutor : FutureParent +{ + virtual void execute(const FutureGeneratorParameter ¶meter) = 0; +} ; + +template +struct FutureNode : FutureExecutor +{ + FutureGenerator futureGenerator; + + typedef decltype(futureGenerator(FutureGeneratorParameter())) FutureType; + typedef Promise PromiseType; + + typedef FutureExecutor Child; + + WeakPtr self; + StrongPtr parent; + Future next; + + PromiseType promise; + FutureType future; + + WeakPtr link; + + FutureNode(FutureGenerator &&futureGenerator_, const StrongPtr &parent_) : + futureGenerator(std::move(futureGenerator_)), + parent(parent_) + { + future = promise.get_future(); + } + + ~FutureNode() + { + xDebugLine(); + } + + static auto generate(FutureGenerator &&futureGenerator_, const StrongPtr &parent_) + { + auto v = strong>(std::move(futureGenerator_), parent_); + v->self = weak(v); + return v; + } + + template::value, F>::type* = nullptr + > + auto add(F &&nextFutureGenerator) + { + auto child = FutureNode::generate(std::move(nextFutureGenerator), strong(self)); + + if (future.is_set()) + { + child->execute(future); + return child; + } + + link = weak(child); + return child; + } + + template::value, F>::type* = nullptr + > + auto add(F &&nextFutureGenerator) + { + return add( + [nextFutureGenerator=std::move(nextFutureGenerator)](auto &&f) { + f.get(); + return nextFutureGenerator(); + } + ); + } + + void execute(const FutureGeneratorParameter ¶meter) override + { + parent = nullptr; + + try + { + next = futureGenerator(copy_of(parameter)).then( + [self_=this->self, this](auto &&f) { + if (auto self = strong(self_)) + { + promise.consume([](auto &&f){ return f.get(); }, std::move(f)); + executeChildren(future); + } + } + ); + } + catch (Exception &e) + { + promise.set_exception(copy_of(e)); + executeChildren(future); + } + } + + void executeChildren(const FutureType &f) + { + if (auto child = strong(this->link)) + { + executeChild(child, f); + } + } + + void executeChild(const StrongPtr &child, const FutureType &f) + { + child->execute(f); + } + + FutureType get_future() + { + return future.then([self = strong(this->self)](auto &&f) { + return f.get(); + }); + } +}; + +inline +auto FutureChain() +{ + auto empty = [](Future &&) { + return future_of_value(); + }; + auto chain = + FutureNode, decltype(empty)>::generate( + std::move(empty), + nullptr + ); + chain->execute(Future()); + + return chain; +} + +} // namespace future_chain_detail + +template +auto future_chain_(A &&a, B &&b) +{ + return a->add(std::forward(b)); +} ; + +template +auto future_chain_(A &&a, B &&b, T &&...t) +{ + return future_chain_(a->add(std::forward(b)), std::forward(t)...); +} ; + +template +auto future_chain(T &&...t) +{ + return future_chain_(future_chain_detail::FutureChain(), std::forward(t)...)->get_future(); +} ; + +} // namespace +} // namespace diff --git a/tjp/core/future/FutureErase.hpp b/tjp/core/future/FutureErase.hpp new file mode 100644 index 0000000..e40df04 --- /dev/null +++ b/tjp/core/future/FutureErase.hpp @@ -0,0 +1,79 @@ +// TJP COPYRIGHT HEADER + +#pragma once + +#include +#include +#include +#include + +namespace tjp::core { +namespace futures::v2 { + +struct FutureErase +{ + StrongPtr> future; + + FutureErase() + {} + + template + FutureErase(Future &&future_) + { + set(std::move(future_)); + } + + ~FutureErase() + { + clear(); + } + + template + void set(Future &&future_) + { + strong_emplace(future); + + *future = future_.then([future_ = weak(future)](auto &&f){ + if (auto future = strong(future_)) + (*future) = {}; + }); + + if (future->is_set()) + future = {}; + } + + template + void operator =(Future &&future_) + { + return set(std::move(future_)); + } + + void clear() + { + future.reset(); + } + + bool has_value () const + { + return future && future->valid(); + } + + bool empty() const + { + return !has_value(); + } + + Future get_future() + { + auto future_ = future; + return future_ ? + *future_ : future_of_value(); + } +} ; + +} // namespace + +using FutureErase = futures::v2::FutureErase; + +} // namespace + diff --git a/tjp/core/future/FutureEvent.hpp b/tjp/core/future/FutureEvent.hpp new file mode 100755 index 0000000..91e01c0 --- /dev/null +++ b/tjp/core/future/FutureEvent.hpp @@ -0,0 +1,58 @@ +// TJP COPYRIGHT HEADER + +#pragma once + +#include +#include + +namespace tjp { +namespace core { + +template +struct FutureEvent +{ + typedef Future F; + + bool waiting_ = false; + Future dependency; + + std::function on; + + void set(Future &&future_) { + waiting_ = true; + + dependency = future_.then([this](F &&f) { + reset(); + + if (on) + on(std::forward(f)); + }); + } + + bool waiting() const + { + return waiting_; + } + + void reset () + { + dependency = {}; + waiting_ = false; + } + + FutureEvent(const FutureEvent &) = delete; + + FutureEvent() + { + sLogDebug("core::future::FutureEvent", this); + } + + ~FutureEvent () + { + sLogDebug("core::future::FutureEvent", this); + dependency = {}; + } +} ; + +} // namespace +} // namespace diff --git a/tjp/core/future/FutureResult.h b/tjp/core/future/FutureResult.h new file mode 100755 index 0000000..e38451e --- /dev/null +++ b/tjp/core/future/FutureResult.h @@ -0,0 +1,10 @@ +// TJP COPYRIGHT HEADER + +#pragma once + +namespace tjp::core { + +template +struct FutureResult; + +} // namespace diff --git a/tjp/core/future/FutureResult.hpp b/tjp/core/future/FutureResult.hpp new file mode 100755 index 0000000..e3335b2 --- /dev/null +++ b/tjp/core/future/FutureResult.hpp @@ -0,0 +1,5 @@ +// TJP COPYRIGHT HEADER + +#pragma once + +#include "FutureResult_v1.hpp" diff --git a/tjp/core/future/FutureResult_v1.hpp b/tjp/core/future/FutureResult_v1.hpp new file mode 100755 index 0000000..d222052 --- /dev/null +++ b/tjp/core/future/FutureResult_v1.hpp @@ -0,0 +1,157 @@ +// TJP COPYRIGHT HEADER + +#pragma once + +#include "Future.hpp" +#include + +namespace tjp::core { +namespace futures::v1 { + +template +struct FutureResult_ +{ + enum Mode { + None, + Running, + Finished + }; + + Mode mode = None; + Future future; + Optional exception; + + void reset () + { + mode = None; + future = {}; + exception.reset(); + } + + operator bool() + { + return isFinished (); + } + + bool isInitiated () + { + return mode != None; + } + + void update () + { + if (mode != Running) + return ; + + if (future.valid() && future.is_set()) + { + mode = Finished; + + try + { + future.get(); + } + catch (Exception &e) + { + exception = e; + } + } + } + + bool isFinished () + { + update(); + + return mode == Finished; + } + + bool isRunning () + { + update(); + + return mode == Running; + } + + Future &set(Future &&future_) + { + mode = Running; + exception = {}; + future = std::move(future_); + + return future; + } + + Future &operator =(Future &&future_) + { + return set(future_); + } + + bool finished () + { + return isFinished(); + } + + bool succeeded () + { + return isFinished() && !exception.has_value(); + } + + bool failed () + { + return isFinished() && exception.has_value(); + } + + bool has_value () + { + return succeeded(); + } + + bool has_exception() + { + return exception.has_value(); + } + + const Exception &get_exception() + { + return *exception; + } + + bool empty() + { + return !isFinished(); + } +} ; + +template +struct FutureResult : FutureResult_ +{ + using Super = FutureResult_; + + Future &operator =(Future &&future_) + { + return this->set(std::move(future_)); + } + + const T &get() + { + return this->future.get(); + } +} ; + +template<> +struct FutureResult : FutureResult_ +{ + using Super = FutureResult_; + + Future &operator =(Future &&future_) + { + return this->set(std::move(future_)); + } + +} ; + +} // namespace + +using futures::v1::FutureResult; + +} // namespace diff --git a/tjp/core/future/FutureResult_v2.hpp b/tjp/core/future/FutureResult_v2.hpp new file mode 100755 index 0000000..bdb2303 --- /dev/null +++ b/tjp/core/future/FutureResult_v2.hpp @@ -0,0 +1,183 @@ +// TJP COPYRIGHT HEADER + +#pragma once + +#include "Future.hpp" +#include "FutureErase.hpp" +#include + +namespace tjp::core { +namespace futures::v2 { + +template +struct ExpectedValue +{ + Optional value; + Optional exception; + + ExpectedValue(Future &&f) + { + try + { + value.emplace(std::move(f.get())); + } + catch (const Exception &e) + { + exception.emplace(e); + } + } + + const T &get() + { + if (exception) + throw *exception; + + return *value; + } + + T &&move() + { + if (exception) + throw *exception; + + return std::move(*value); + } +} ; + +template<> +struct ExpectedValue +{ + Optional exception; + + ExpectedValue(Future &&f) { + try + { + f.get(); + } + catch (const Exception &e) + { + exception.emplace(e); + } + } + + void get() + { + if (exception) + throw *exception; + } +} ; + +template +struct FutureResult_ +{ + FutureErase future; + Optional> expected; + + void reset () + { + future.clear(); + expected.reset(); + } + + operator bool() + { + return has_value(); + } + + bool isInitiated () + { + return isRunning() || isFinished(); + } + + bool isFinished () + { + return finished(); + } + + bool isRunning () + { + return future.has_value(); + } + + void operator =(Future &&future_) + { + set(std::move(future_)); + } + + void set(Future &&future_) + { + expected.reset(); + future = future_.then([this](auto &&f) { + expected.emplace(std::move(f)); + }); + } + + bool finished () + { + return expected; + } + + bool succeeded () + { + return expected && !expected->exception; + } + + bool failed () + { + return expected && expected->exception; + } + + bool has_exception () + { + return expected && expected->exception; + } + + bool has_value () + { + return succeeded(); + } + + const Exception &get_exception() + { + return *expected->exception; + } + + bool empty() + { + return !expected; + } +} ; + +template +struct FutureResult : FutureResult_ +{ + using Super = FutureResult_; + + void operator =(Future &&future_) + { + set(std::move(future_)); + } + + const T &get() + { + return this->expected->get(); + } +} ; + +template<> +struct FutureResult : FutureResult_ +{ + using Super = FutureResult_; + + void operator =(Future &&future_) + { + set(std::move(future_)); + } + +} ; + +} // namespace + +using futures::v2::FutureResult; + +} // namespace diff --git a/tjp/core/future/FutureStrong.hpp b/tjp/core/future/FutureStrong.hpp new file mode 100755 index 0000000..5b1f763 --- /dev/null +++ b/tjp/core/future/FutureStrong.hpp @@ -0,0 +1,49 @@ +// TJP COPYRIGHT HEADER + +#pragma once + +#include + +namespace tjp { +namespace core { + +template +auto future_strong(U &&f) +{ + return f.then([](auto &&g) { + using T = typename std::remove_reference::type; + + return strong(std::move(g.get())); + }); +} + +template +auto future_strong(U &&f) +{ + return f.then([](auto &&g) { + return strong(std::move(g.get())); + }); +} + +template +auto future_strong_value(U &&f) +{ + return f.then([](auto &&g) { + if (auto ptr = g.get()) + return *ptr; + + throw exceptions::NullPointer(); + }); +} + +template +auto future_strong_with(U &&ptr) +{ + if (ptr) + return *ptr; + + throw exceptions::NullPointer(); +} + +} // namespace +} // namespace diff --git a/tjp/core/future/Futures.cpp b/tjp/core/future/Futures.cpp new file mode 100755 index 0000000..0cc8576 --- /dev/null +++ b/tjp/core/future/Futures.cpp @@ -0,0 +1,312 @@ +// TJP COPYRIGHT HEADER + +#include +#ifdef TJP_CORE_HEADER_ONLY + #pragma once +#endif + +#include "Futures.hpp" +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +//#define DEBUG_FUTURE_LEAKS_BUT_PROBLEMS_WITH_THIS +#ifdef DEBUG_FUTURE_LEAKS_BUT_PROBLEMS_WITH_THIS +#include +#include +#endif + +namespace tjp { +namespace core { + +#ifdef DEBUG_FUTURE_LEAKS_BUT_PROBLEMS_WITH_THIS + +static Atomic totalOutstandingFutures = 0; + +struct StackFrames { + void* trace[64]; + int size; +} ; + +String toString(StackFrames &f) +{ + char** messages = NULL; + + std::ostringstream out; + + messages = backtrace_symbols( f.trace, f.size ); + for( int i = 2; i < f.size; ++i ) { + out << "\t" << messages[i] << std::endl; + } + + free (messages); + + return out.str(); +} + +struct Leak { + time::Time then; + StackFrames stack; + WeakPtr future; +} ; + +Map outstandingFutures; +time::Time lastLeaker = 0; + +static void debug_log(); + +static void debug_futureCreated(const StrongPtr &future) +{ + totalOutstandingFutures++; + + auto &leak = outstandingFutures[ptr_of(future)]; + leak.then = time::now(); + leak.stack.size = backtrace( leak.stack.trace, 16 ); + leak.future = weak(future); + + sLogRelease("core::futures", logVar(totalOutstandingFutures)); + debug_log(); +} + +static void debug_futureFinished(void *fp) +{ + totalOutstandingFutures--; + auto erased_leak = map_erase(outstandingFutures, fp); + debug_assert(erased_leak); + + sLogDebug("core::futures", logVar(totalOutstandingFutures)); + debug_log(); +} + +void debug_log() +{ + auto now = time::now(); + if (now - lastLeaker > 5.0) + { + lastLeaker = now; + for (auto &[p, leak]: outstandingFutures) + { + auto diff = now - leak.then; + if (diff > 10.0) + { + sLogRelease("core::futures::leak", logVar(leak.future.use_count()) << logVar(diff) << logVar(p) << logVar(toString(leak.stack))); + } + } + } +} + +#else + +#define debug_futureCreated(x) +#define debug_futureFinished(x) + +#endif + +struct Futures::Internal { + mutable Mutex mutex; + List> futures; + + virtual void add(StrongPtr &self, const StrongPtr &future) + { + StrongPtr r; + { + auto lock = lock_of(mutex); + r = futures.emplace_back(future); + + debug_futureCreated(future); + } + + r->inject([weak=weak(self)](auto *fp) { + if (auto self = strong(weak)) + self->onFuture(fp); + }); + } + + void onFuture_noLock(void *fp) + { + auto erased = vector_erase_if_value( + futures, + [fp](auto &v) { + return ptr_of(v) == fp; + } + ); + + debug_assert(erased); + + debug_futureFinished(fp); + } + + virtual void onFuture(void *fp) + { + auto lock = lock_of(mutex); + onFuture_noLock(fp); + } + + virtual void clear () + { + auto l = lock_of(mutex); + futures.clear(); + } + + bool empty() const + { + auto l = lock_of(mutex); + return futures.empty(); + } +} ; + +struct FuturesEvent_Internal : Futures::Internal { + using Super = Futures::Internal; + Event event; + + void onFuture(void *fp) override + { + Super::onFuture(fp); + event.notify_all(); + } + + void clear () override + { + auto l = lock_of(mutex); + futures.clear(); + event.notify_all(); + } + + void wait() + { + while (!empty()) + { + Event::Mutex m; + auto l = lock_of(m); + event.wait(l); + } + } +} ; + +struct FuturesFuture_Internal : Futures::Internal +{ + using Super = Futures::Internal; + + bool shouldSetFinished = false; + Promise finished; + + void onFuture(void *fp) override + { + Optional> finished_; + + { + auto lock = lock_of(mutex); + Super::onFuture_noLock(fp); + + if (shouldSetFinished && futures.empty()) + { + // TODO: promises should have a move constructor + finished_.emplace(std::move(finished)); + finished = {}; + } + } + + if (finished_) + finished_->set_value(); + } + + Future get_future(StrongPtr &self) + { + auto l = lock_of(mutex); + if (futures.empty()) + return future_of_value(); + + shouldSetFinished = true; + + return finished.get_future() + .then([self](auto &&f) { + return f.get(); + }); + } + +} ; + +// ---------- + +struct Futures::NoConstructInternal {}; + +TJP_CORE_HEADER_ONLY_INLINE +Futures::Futures (NoConstructInternal) +{ +} + +TJP_CORE_HEADER_ONLY_INLINE +Futures::Futures () +{ + internal = strong(); +} + +TJP_CORE_HEADER_ONLY_INLINE +Futures::~Futures () +{ +} + +TJP_CORE_HEADER_ONLY_INLINE +void Futures::add(const StrongPtr &future) +{ + internal->add(internal, future); +} + +TJP_CORE_HEADER_ONLY_INLINE +bool Futures::empty() const +{ + return internal->empty(); +} + +TJP_CORE_HEADER_ONLY_INLINE +void Futures::clear() +{ + internal->clear(); +} + +// ------------------ + +TJP_CORE_HEADER_ONLY_INLINE +FuturesEvent::FuturesEvent() : + Super(Super::NoConstructInternal{}) +{ + internal = strong(); +} + +TJP_CORE_HEADER_ONLY_INLINE +void FuturesEvent::wait () +{ + strong_ptr_cast(internal)->wait(); +} + +// ------------------ + +TJP_CORE_HEADER_ONLY_INLINE +FuturesFuture::FuturesFuture() : + Super(Super::NoConstructInternal{}) +{ + internal = strong(); +} + +TJP_CORE_HEADER_ONLY_INLINE +Future FuturesFuture::get_future() +{ + return strong_ptr_cast(internal)->get_future(internal); +} + +} // namespace +} // namespace diff --git a/tjp/core/future/Futures.h b/tjp/core/future/Futures.h new file mode 100755 index 0000000..93cdd57 --- /dev/null +++ b/tjp/core/future/Futures.h @@ -0,0 +1,16 @@ +// TJP COPYRIGHT HEADER + +#pragma once + +namespace tjp { +namespace core { + +struct FuturePersist; + +template +struct FuturePersistTyped; + +struct Futures; + +} // namespace +} // namespace diff --git a/tjp/core/future/Futures.hpp b/tjp/core/future/Futures.hpp new file mode 100755 index 0000000..01740c0 --- /dev/null +++ b/tjp/core/future/Futures.hpp @@ -0,0 +1,87 @@ +// TJP COPYRIGHT HEADER + +#pragma once + +#include "Futures.h" +#include "Future.hpp" +#include + +namespace tjp::core { + +struct FuturePersist +{ + virtual ~FuturePersist () {} + + virtual void inject(std::function &&t) = 0; +} ; + +template +struct FuturePersistTyped : FuturePersist +{ + Future f; + + FuturePersistTyped(const Future &f_) : + f(f_) + {} + + void inject(std::function &&t) override + { + f = f.then([t=std::move(t), this](auto &&f_) { + f_.wait(); + + t(this); + return f_.get(); + }); + } +} ; + +struct Futures +{ + struct Internal; + StrongPtr internal; + + struct NoConstructInternal; + + Futures (NoConstructInternal); + + Futures (); + ~Futures (); + + void add(const StrongPtr &future); + + template + Future add(const Future &future) + { + auto persisted = strong>(future); + add(persisted); + + return persisted->f; + } + + bool empty() const; + void clear(); +} ; + +struct FuturesEvent : Futures +{ + using Super = Futures; + + FuturesEvent (); + + void wait (); +} ; + +struct FuturesFuture : Futures +{ + using Super = Futures; + + FuturesFuture (); + + Future get_future(); +} ; + +} // namespace + +#ifdef TJP_CORE_HEADER_ONLY + #include "Futures.cpp" +#endif diff --git a/tjp/core/future/PromiseLocked.h b/tjp/core/future/PromiseLocked.h new file mode 100755 index 0000000..7d0f785 --- /dev/null +++ b/tjp/core/future/PromiseLocked.h @@ -0,0 +1,15 @@ +// TJP COPYRIGHT HEADER + +#pragma once + +namespace tjp { +namespace core { + +template +struct PromiseLocked; + +template +PromiseLocked &promise_of_and_reset(PromiseLocked &p, F &&f); + +} // namespace +} // namespace diff --git a/tjp/core/future/PromiseLocked.hpp b/tjp/core/future/PromiseLocked.hpp new file mode 100755 index 0000000..f50c4c1 --- /dev/null +++ b/tjp/core/future/PromiseLocked.hpp @@ -0,0 +1,168 @@ +// TJP COPYRIGHT HEADER + +#pragma once + +#include "PromiseLocked.h" +#include "Future.hpp" +#include + +namespace tjp { +namespace core { + +template +struct PromiseLocked +{ + Mutex m; + bool owned = false; + Promise promise; + + std::tuple> own_future() + { + auto l = lock_of(m); + + if (promise.is_set() || owned) + return { false, promise.get_future() }; + + owned = true; + return { true, promise.get_future() }; + } + + template ::value, U>::type* = nullptr + > + void set_value (U &&t) + { + auto l = lock_of(m); + debug_assert(owned); + + promise.set_value(t); + owned = false; + } + + template ::value, U>::type* = nullptr + > + void set_value (const U &t) + { + auto l = lock_of(m); + debug_assert(owned); + + promise.set_value(t); + owned = false; + } + + template ::value, U>::type* = nullptr + > + void set_value () + { + auto l = lock_of(m); + debug_assert(owned); + promise.set_value(); + + owned = false; + } + + void set_exception (Exception &&e) + { + auto l = lock_of(m); + debug_assert(owned); + promise.set_exception(std::move(e)); + + owned = false; + } + + template::value>::type* = nullptr + > + void consume (F &&f) + { + auto l = lock_of(m); + + debug_assert(owned); + promise.consume(std::forward(f)); + + owned = false; + } + + template::value>::type* = nullptr + > + void reset_consume (F &&f) + { + debug_assert(owned); + Promise o = reset(); + + o.consume(std::forward(f)); + } + + template::value>::type* = nullptr + > + void consume (F &&f) + { + consume([&f]() { return f.get(); }); + } + + template::value>::type* = nullptr + > + void reset_consume (F &&f) + { + reset_consume([&f]() { return f.get(); }); + } + + template + void consume_value (const V &v) + { + auto l = lock_of(m); + debug_assert(owned); + set_value(v); + + owned = false; + } + + template + void reset_consume_value (const V &v) + { + debug_assert(owned); + + Promise o = reset(); + o.set_value(v); + } + + void release () + { + auto l = lock_of(m); + debug_assert(owned); + + owned = false; + } + + Promise reset () + { + auto l = lock_of(m); + + owned = false; + auto r = std::move(promise); + promise = {}; + + return r; + } +} ; + +template +PromiseLocked &promise_of_and_reset(PromiseLocked &p, F &&f) +{ + p.reset_consume(std::forward(f)); + return p; +} + +template +PromiseLocked &promise_of_and_reset_value(PromiseLocked &p, const V &v) +{ + p.reset_consume_value(v); + return p; +} +} // namespace +} // namespace diff --git a/tjp/core/future/PromiseOfFutures.h b/tjp/core/future/PromiseOfFutures.h new file mode 100755 index 0000000..a14a60e --- /dev/null +++ b/tjp/core/future/PromiseOfFutures.h @@ -0,0 +1,21 @@ +// TJP COPYRIGHT HEADER + +#pragma once + +#include + +namespace tjp { +namespace core { + +template +struct PromiseOfFutures; + +template<> +struct PromiseOfFutures; + +template +using PromiseOfFuturesPtr = StrongPtr>; + + +} // namespace +} // namespace diff --git a/tjp/core/future/PromiseOfFutures.hpp b/tjp/core/future/PromiseOfFutures.hpp new file mode 100755 index 0000000..b7efeaf --- /dev/null +++ b/tjp/core/future/PromiseOfFutures.hpp @@ -0,0 +1,228 @@ +// TJP COPYRIGHT HEADER + +#pragma once + +#include "PromiseOfFutures.h" +#include "Futures.hpp" +#include +#include +#include + +#include + +namespace tjp { +namespace core { + +// TODO: PromiseOfFutures should go away and instead just have FuturesFuture +// TODO: this class can cause a memory leak, if the underlying future is not triggered + +template +struct PromiseOfFutures +{ + typedef PromiseOfFutures Self; + typedef StrongPtr Instance; + WeakPtr self; + + T value; + StrongPtr exception; + Futures futures; + + Promise promise; + std::atomic outstanding = 1; + + void onCompletion() + { + auto outstanding_ = --outstanding; + fLogDebug(logOfThis(this) << "onCompletion " << outstanding_); + + if (outstanding_ == 0) + { + if (exception) + { + xLogDebug(logOfThis(this) << "exception"); + promise.set_exception(Exception(*exception)); + } + else + { + xLogDebug(logOfThis(this) << "value"); + promise.set_value(value); + } + } + } + + template + auto add(FT &&f) + { + auto outstanding_ = ++outstanding; + fLogDebug(logOfThis(this) << "add " << outstanding_); + + return futures.add(f.template then<>([self_=this->self, this](auto &&f_) + { + if (auto self = strong(self_)) + { + try + { + f_.get(); + } + catch (Exception &e) + { + exception = strong(e); + } + + onCompletion(); + } + })); + } + + auto get_promise () + { + return promise; + } + + auto get_future () + { + onCompletion(); + + return promise.get_future() + .then([self=strong(this->self)](auto &&f) { + return f.get(); + }) + .then([](auto &&f) { return f.get(); }); + } + + template + void consume(F &&f) + { + try + { + value = f.get(); + } + catch (Exception &e) + { + exception = strong(e); + } + } + + template + void consume_throw_exception(F &&f) + { + value = f.get(); + } + + void set(const T &t) + { + value = t; + } + + static StrongPtr generate() + { + auto v = strong(); + v->self = weak(v); + + return v; + } + +public: + PromiseOfFutures() {} +} ; + +template<> +struct PromiseOfFutures +{ + typedef PromiseOfFutures Self; + typedef StrongPtr Instance; + WeakPtr self; + + StrongPtr exception; + Futures futures; + + Promise promise; + size_t outstanding = 1; + + void onCompletion() + { + auto outstanding_ = --outstanding; + fLogDebug(logOfThis(this) << "onCompletion " << outstanding_); + + if (outstanding_ == 0) + { + if (exception) + { + xLogDebug(logOfThis(this) << "exception"); + promise.set_exception(Exception(*exception)); + } + else + { + xLogDebug(logOfThis(this) << "value"); + promise.set_value(); + } + } + } + + template + auto add(FT &&f) + { + auto outstanding_ = ++outstanding; + (void)outstanding_; + fLogDebug(logOfThis(this) << "add " << outstanding_); + + return futures.add(f.template then<>([self_=this->self, this](auto &&f_) + { + if (auto self = strong(self_)) + { + try + { + f_.get(); + } + catch (Exception &e) + { + exception = strong(e); + } + + onCompletion(); + } + })); + } + + auto get_future () + { + onCompletion(); + return promise.get_future().then([self=strong(this->self)](auto &&f) { + return f.get(); + }); + } + + template + void consume(F &&f) + { + try + { + f.get(); + } + catch (Exception &e) + { + exception = strong(e); + } + } + + template + void consume_throw_exception(F &&f) + { + f.get(); + } + + static StrongPtr generate() + { + auto v = strong(); + v->self = weak(v); + + return v; + } + +public: + PromiseOfFutures() {} + +} ; + +} // namespace +} // namespace diff --git a/tjp/core/future/WeakFuture.hpp b/tjp/core/future/WeakFuture.hpp new file mode 100755 index 0000000..2d8591d --- /dev/null +++ b/tjp/core/future/WeakFuture.hpp @@ -0,0 +1,37 @@ +// TJP COPYRIGHT HEADER + +#pragma once + +#include "Future.hpp" + +namespace tjp { +namespace core { + +// this may need to be strong this +template +struct WeakFuture +{ + typedef Future F; + + F f; + u8 number = 0; + + void set(Future &&f_) + { + auto number_ = ++number; + + f = f_.then([this, number_](auto &&) { + if (number_ == number) + f = {}; + }); + }; + + auto &operator =(Future &&f_) + { + set(std::move(f_)); + return *this; + } +} ; + +} // namespace +} // namespace diff --git a/tjp/core/future/WorkPromise.h b/tjp/core/future/WorkPromise.h new file mode 100755 index 0000000..5fb8f03 --- /dev/null +++ b/tjp/core/future/WorkPromise.h @@ -0,0 +1,12 @@ +// TJP COPYRIGHT HEADER + +#pragma once + +namespace tjp { +namespace core { + +template +struct WorkPromise; + +} // namespace +} // namespace diff --git a/tjp/core/future/WorkPromise.hpp b/tjp/core/future/WorkPromise.hpp new file mode 100755 index 0000000..c3f540c --- /dev/null +++ b/tjp/core/future/WorkPromise.hpp @@ -0,0 +1,27 @@ +// TJP COPYRIGHT HEADER + +#pragma once + +#include "PromiseOfFutures.hpp" + +namespace tjp { +namespace core { + +template +struct WorkPromise : PromiseOfFutures +{ + typedef PromiseOfFutures Super; + + W work; + + static StrongPtr generate() + { + auto v = strong(); + v->self = weak(strong_ptr_cast(v)); + + return v; + } +} ; + +} // namespace +} // namespace diff --git a/tjp/core/future/_tests/FutureChain.cpp b/tjp/core/future/_tests/FutureChain.cpp new file mode 100755 index 0000000..32376fa --- /dev/null +++ b/tjp/core/future/_tests/FutureChain.cpp @@ -0,0 +1,257 @@ +// TJP COPYRIGHT HEADER + +#include +#include + +#include +#include + +namespace tjp { +namespace core { +namespace futures { +namespace promise_of_futures_test { + +SCENARIO("core::future::future_chain" ) +{ + GIVEN("a void promise") + { + WHEN("two different futures using functional auto no_f and exception") + { + Promise a; + Promise b; + Promise c; + Promise d; + int i = 32; + int x = 0; + + auto future = future_chain( + [&a, i]() { + return a.get_future(); + }, + [&b, &x, i]() { + x++; + return b.get_future(); + }, + [&c, &x, i]() { + x++; + return c.get_future(); + }, + [&d, &x, i]() { + x++; + return d.get_future(); + } + ); + + THEN("waits for sub futures") + { + Timer timer; + + x = 0; + + std::thread threadA([&]() { + std::this_thread::sleep_for(std::chrono::milliseconds(250)); + a.set_exception(Exception { "Failed"}); + b.set_value("hello"); +// c.set_value(1); +// d.set_value(2); + }); + + future.wait(); + threadA.join(); + + REQUIRE(x == 0); + REQUIRE_THROWS(future.get()); + } + } + + WHEN("no futures") + { + auto future = future_chain_detail::FutureChain()->get_future(); + future.wait(); + + REQUIRE(true); + } + + WHEN("one future") + { + Promise a; + + auto chain = + future_chain_detail::FutureChain()->add([&]() { + return a.get_future(); + }) + ; + + THEN("waits for result") + { + auto future = chain->get_future(); + chain = nullptr; + + Timer timer; + + std::thread threadA([&]() { + std::this_thread::sleep_for(std::chrono::milliseconds(250)); + a.set_value(); + }); + + future.wait(); + auto elapsed = timer.elapsed(); + threadA.join(); + + REQUIRE(elapsed > 0.1); + } + + THEN("if future is discarded chain deletes") + { + auto future = chain->get_future(); + auto p = weak(chain); + chain = nullptr; + + future = {}; + + REQUIRE(strong(p) == nullptr); + } + } + + WHEN("two futures") + { + Promise a, b; + + auto chain = future_chain_detail::FutureChain() + ->add([&]() { + return a.get_future(); + }) + ->add([&](auto &&f) { + return b.get_future(); + }) + ; + + THEN("waits for sub futures") + { + auto future = chain->get_future(); + chain = nullptr; + + Timer timer; + + std::thread threadA([&]() { + std::this_thread::sleep_for(std::chrono::milliseconds(250)); + a.set_value(); + b.set_value(); + }); + + future.wait(); + auto elapsed = timer.elapsed(); + threadA.join(); + + REQUIRE(elapsed > 0.1); + } + } + + + WHEN("two different futures") + { + Promise a; + Promise b; + + auto chain = future_chain_detail::FutureChain() + ->add([&]() { + return a.get_future(); + }) + ->add([&](Future &&f) { + return b.get_future(); + }) + ; + + THEN("waits for sub futures") + { + auto future = chain->get_future(); + chain = nullptr; + + Timer timer; + + std::thread threadA([&]() { + std::this_thread::sleep_for(std::chrono::milliseconds(250)); + a.set_value(1); + b.set_value("hello"); + }); + + future.wait(); + auto elapsed = timer.elapsed(); + threadA.join(); + + REQUIRE(elapsed > 0.1); + } + } + + WHEN("two different futures using functional") + { + Promise a; + Promise b; + auto i = 32; + + auto future = future_chain( + [&a, i]() { + return a.get_future(); + }, + [&b, i](Future &&f) { + return b.get_future(); + } + ); + + THEN("waits for sub futures") + { + Timer timer; + + std::thread threadA([&]() { + std::this_thread::sleep_for(std::chrono::milliseconds(250)); + a.set_value(1); + b.set_value("hello"); + }); + + future.wait(); + auto elapsed = timer.elapsed(); + threadA.join(); + + REQUIRE(elapsed > 0.1); + } + } + + WHEN("two different futures using functional auto") + { + Promise a; + Promise b; + int i = 32; + + auto future = future_chain( + [&a, i]() { + return a.get_future(); + }, + [&b, i](auto &&f) { + return b.get_future(); + } + ); + + THEN("waits for sub futures") + { + Timer timer; + + std::thread threadA([&]() { + std::this_thread::sleep_for(std::chrono::milliseconds(250)); + a.set_value(1); + b.set_value("hello"); + }); + + future.wait(); + auto elapsed = timer.elapsed(); + threadA.join(); + + REQUIRE(elapsed > 0.1); + } + } + } +} + +} // namespace +} // namespace +} // namespace +} // namespace diff --git a/tjp/core/future/_tests/FutureErase.cpp b/tjp/core/future/_tests/FutureErase.cpp new file mode 100644 index 0000000..90075dc --- /dev/null +++ b/tjp/core/future/_tests/FutureErase.cpp @@ -0,0 +1,39 @@ +// TJP COPYRIGHT HEADER + +#include "../FutureErase.hpp" +#include + +namespace tjp::core::futures { +namespace { + +SCENARIO("core::futures::FutureErase") +{ + GIVEN("a Futures") + { + FutureErase futures; + + WHEN("adding a future that resolves afterwards") + { + Promise promise; + futures.set(promise.get_future()); + REQUIRE(!futures.empty()); + + promise.set_value(); + + REQUIRE(futures.empty()); + } + + WHEN("adding a future that's already resolved") + { + Promise promise; + promise.set_value(); + futures.set(promise.get_future()); + + REQUIRE(futures.empty()); + } + } +} + +} // namespace +} // namespace + diff --git a/tjp/core/future/_tests/FutureResult.cpp b/tjp/core/future/_tests/FutureResult.cpp new file mode 100644 index 0000000..3a37e34 --- /dev/null +++ b/tjp/core/future/_tests/FutureResult.cpp @@ -0,0 +1,97 @@ +// TJP COPYRIGHT HEADER + +#include "../FutureResult.hpp" +#include + +namespace tjp::core::futures { +namespace { + +SCENARIO("core::futures::FutureResult") +{ + GIVEN("a FutureResult") + { + FutureResult futures; + + WHEN("adding a future that resolves afterwards") + { + Promise promise; + futures.set(promise.get_future()); + REQUIRE(futures.empty()); + + promise.set_value(); + + REQUIRE(!futures.empty()); + } + + WHEN("adding a future that's already resolved") + { + Promise promise; + promise.set_value(); + futures.set(promise.get_future()); + + REQUIRE(!futures.empty()); + } + } + GIVEN("a FutureResult") + { + FutureResult futures; + + WHEN("adding a future that resolves afterwards") + { + Promise promise; + futures.set(promise.get_future()); + REQUIRE(futures.empty()); + + promise.set_value(42); + + REQUIRE(!futures.empty()); + REQUIRE(futures.get() == 42); + } + + WHEN("adding a future that's already resolved") + { + Promise promise; + promise.set_value(42); + futures.set(promise.get_future()); + + REQUIRE(!futures.empty()); + REQUIRE(futures.get() == 42); + } + } + + GIVEN("a FutureResult") + { + FutureResult futures; + + WHEN("adding a future that resolves afterwards") + { + Promise promise; + futures.set(promise.get_future()); + REQUIRE(futures.empty()); + REQUIRE(!futures.has_exception()); + + promise.set_exception(Exception { "abcd" }); + + REQUIRE(!futures.empty()); + REQUIRE(!futures.has_value()); + REQUIRE(futures.has_exception()); + REQUIRE(futures.get_exception().what() == "abcd"); + } + + WHEN("adding a future that's already resolved") + { + Promise promise; + promise.set_exception(Exception { "abcd" }); + futures.set(promise.get_future()); + + REQUIRE(!futures.empty()); + REQUIRE(!futures.has_value()); + REQUIRE(futures.has_exception()); + REQUIRE(futures.get_exception().what() == "abcd"); + } + } +} + +} // namespace +} // namespace + diff --git a/tjp/core/future/_tests/PromiseLocked.cpp b/tjp/core/future/_tests/PromiseLocked.cpp new file mode 100755 index 0000000..dfe3ff1 --- /dev/null +++ b/tjp/core/future/_tests/PromiseLocked.cpp @@ -0,0 +1,23 @@ +// TJP COPYRIGHT HEADER + +#include + +namespace tjp { +namespace core { +namespace { + +static void futures_promise_locked_test () +{ + PromiseLocked pi; + pi.consume(future_of_value((int)1)); + pi.consume([]() { return (int)1; }); + + PromiseLocked pv; + pv.consume(future_of_value()); + pv.consume([]() {}); + +} + +} +} // namespace +} // namespace diff --git a/tjp/core/future/_tests/PromiseOfFutures.cpp b/tjp/core/future/_tests/PromiseOfFutures.cpp new file mode 100755 index 0000000..1f7e318 --- /dev/null +++ b/tjp/core/future/_tests/PromiseOfFutures.cpp @@ -0,0 +1,124 @@ +// TJP COPYRIGHT HEADER + +#include +#include + +#include +#include + +namespace tjp { +namespace core { +namespace futures { +namespace promise_of_futures_test { + +SCENARIO("promise of future" ) +{ + GIVEN("a void promise") + { + auto promise = PromiseOfFutures::generate(); + + WHEN("no futures") + { + auto future = promise->get_future(); + future.wait(); + + REQUIRE(true); + } + + WHEN("one future") + { + Promise a; + promise->add(a.get_future()); + + THEN("waits for result") + { + auto future = promise->get_future(); + promise = nullptr; + + Timer timer; + + std::thread threadA([&]() { + std::this_thread::sleep_for(std::chrono::milliseconds(250)); + a.set_value(); + }); + + future.wait(); + auto elapsed = timer.elapsed(); + threadA.join(); + + REQUIRE(elapsed > 0.1); + } + + THEN("if future is discarded promise deletes") + { + auto future = promise->get_future(); + auto p = weak(promise); + promise = nullptr; + + future = {}; + + REQUIRE(strong(p) == nullptr); + } + } + + WHEN("two futures") + { + Promise a, b; + promise->add(a.get_future()); + promise->add(b.get_future()); + + THEN("waits for sub futures") + { + auto future = promise->get_future(); + promise = nullptr; + + Timer timer; + + std::thread threadA([&]() { + std::this_thread::sleep_for(std::chrono::milliseconds(250)); + a.set_value(); + b.set_value(); + }); + + future.wait(); + auto elapsed = timer.elapsed(); + threadA.join(); + + REQUIRE(elapsed > 0.1); + } + } + + WHEN("two different futures") + { + Promise a; + Promise b; + promise->add(a.get_future()); + promise->add(b.get_future()); + + THEN("waits for sub futures") + { + auto future = promise->get_future(); + promise = nullptr; + + Timer timer; + + std::thread threadA([&]() { + std::this_thread::sleep_for(std::chrono::milliseconds(250)); + a.set_value(1); + b.set_value("hello"); + }); + + future.wait(); + auto elapsed = timer.elapsed(); + threadA.join(); + + REQUIRE(elapsed > 0.1); + } + } + } +} + +} // namespace +} // namespace +} // namespace +} // namespace diff --git a/tjp/core/future/_tests/after.cpp b/tjp/core/future/_tests/after.cpp new file mode 100755 index 0000000..dff8540 --- /dev/null +++ b/tjp/core/future/_tests/after.cpp @@ -0,0 +1,48 @@ +// TJP COPYRIGHT HEADER + +#include + +#include + +namespace tjp { +namespace core { + +SCENARIO("after a future") +{ + GIVEN("two promises") + { + Promise p0, p1; + + WHEN("a future from one promise") + { + auto f0 = p0.get_future(); + + WHEN("get a different future after") + { + auto added = after( + f0, + [&](auto &&f) + { + auto r = f.get(); + return p1.get_future().then([r](auto &&f) { + return r + f.get(); + }); + } + ); + + THEN("values are correct passed through") + { + p0.set_value(1); + REQUIRE(f0.get() == 1); + REQUIRE(added.is_set() == false); + + p1.set_value(2); + REQUIRE(added.get() == 3); + } + } + } + } +} + +} // namespace +} // namespace diff --git a/tjp/core/future/after.hpp b/tjp/core/future/after.hpp new file mode 100755 index 0000000..4f20ef2 --- /dev/null +++ b/tjp/core/future/after.hpp @@ -0,0 +1,43 @@ +// TJP COPYRIGHT HEADER + +#pragma once + +#include "Future.hpp" +#include "weak_future_consume.hpp" +#include + +namespace tjp { +namespace core { + +template +auto after(F0 &&f0, FutureGenerator &&next) +{ + typedef decltype(f0.get()) R0; + typedef decltype(next(f0)) F1_Ref; + typedef typename std::remove_reference::type F1; + typedef decltype(std::declval().get()) R1_Ref; + typedef typename std::remove_reference::type R1; + + Promise p; + auto p_ = weak(p.shared); + + auto swizzle = f0.then([p_, next](auto &&f0) { + return + future_with([&]() { return next(f0); }) + .then([p_](auto &&f1) { + weak_future_consume( + p_, + [](auto &&f1) { return f1.get(); }, + f1 + ); + }); + + }); + + return p.get_future().then([swizzle](auto &&f1) { + return f1.get(); + }); +} + +} // namespace +} // namespace diff --git a/tjp/core/future/after_using.hpp b/tjp/core/future/after_using.hpp new file mode 100755 index 0000000..d908a25 --- /dev/null +++ b/tjp/core/future/after_using.hpp @@ -0,0 +1,17 @@ +// TJP COPYRIGHT HEADER + +#pragma once + +#include "after.hpp" + +namespace tjp::core { + +template +auto after_using(F0 &&f0, FutureGenerator &&next) +{ + return after(f0, [next = std::move(next)](auto &&f) { + return next(f.get()); + }); +} + +} // namespace diff --git a/tjp/core/future/boost/Future.h b/tjp/core/future/boost/Future.h new file mode 100755 index 0000000..c6a8773 --- /dev/null +++ b/tjp/core/future/boost/Future.h @@ -0,0 +1,23 @@ +// TJP COPYRIGHT HEADER + +#pragma once + +#define BOOST_THREAD_PROVIDES_FUTURE +#define BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION +#include +#include +#include + +namespace tjp { +namespace core { + +template +using Future = boost::future; + +template +using Promise = boost::promise; + +} // namespace +} // namespace + + diff --git a/tjp/core/future/custom/Future.cpp b/tjp/core/future/custom/Future.cpp new file mode 100755 index 0000000..ea7c069 --- /dev/null +++ b/tjp/core/future/custom/Future.cpp @@ -0,0 +1,28 @@ +// TJP COPYRIGHT HEADER + +#include "Future.hpp" + +namespace tjp { +namespace core { +namespace futures { + +namespace detail { + +//typedef std::list Stack; +//ThreadSpecificSingleton stack; + +//CancelFrame::CancelFrame(Cancelable *c) +//{ +// stack->push_back(c); +//} + +//CancelFrame::~CancelFrame() +//{ +// stack->pop_back(); +//} + +} // namespace + +} // namespace +} // namespace +} // namespace diff --git a/tjp/core/future/custom/Future.h b/tjp/core/future/custom/Future.h new file mode 100755 index 0000000..a4adbc5 --- /dev/null +++ b/tjp/core/future/custom/Future.h @@ -0,0 +1,6 @@ +// TJP COPYRIGHT HEADER + +#pragma once + +#include "Future_.h" +#include "Future_void.h" diff --git a/tjp/core/future/custom/Future.hpp b/tjp/core/future/custom/Future.hpp new file mode 100755 index 0000000..0d65916 --- /dev/null +++ b/tjp/core/future/custom/Future.hpp @@ -0,0 +1,14 @@ +// TJP COPYRIGHT HEADER + +#pragma once + +//#define FUTURES_ENABLE_LOG +//#define FUTURES_THEN_ON_CONSTRUCT +#define FUTURES_THEN_ON_SET +//#define FUTURES_THEN_ON_WAIT + +//#define CORE_FUTURE_USE_STRONG_EXCEPTION_PTR +#define CORE_FUTURE_USE_STD_EXCEPTION_PTR + +#include "Future_.hpp" +#include "Future_void.hpp" diff --git a/tjp/core/future/custom/Future_.h b/tjp/core/future/custom/Future_.h new file mode 100755 index 0000000..0955000 --- /dev/null +++ b/tjp/core/future/custom/Future_.h @@ -0,0 +1,69 @@ +// TJP COPYRIGHT HEADER + +#pragma once + +namespace tjp { +namespace core { + +namespace futures { +namespace detail { + +template +struct Shared; + +template +struct Shared_; + +template +struct Promise; + +template +struct Future; + +struct Dependency; + +struct Cancelable; + +struct CancelFrame; + +template +struct Then; + +template +struct Shared_; + +template +struct Shared; + +template +struct Promise_; + +template +struct Promise; + +template +struct Future_; + +template +struct Future; + +} // namespace + +template +using Promise = detail::Promise; + +template +using Future = detail::Future; + +} // namespace + +template +using Promise = futures::Promise; + +template +using Future = futures::Future; + +} // namespace +} // namespace + + diff --git a/tjp/core/future/custom/Future_.hpp b/tjp/core/future/custom/Future_.hpp new file mode 100755 index 0000000..2a20dd0 --- /dev/null +++ b/tjp/core/future/custom/Future_.hpp @@ -0,0 +1,513 @@ +// TJP COPYRIGHT HEADER + +#pragma once + +#include "Future_Requirements.hpp" + +namespace tjp { +namespace core { + +namespace futures { +namespace detail { + +template +struct Shared; + +template +struct Shared_; + +template +struct Promise; + +template +struct Future; + +struct Dependency { + virtual ~Dependency() {} +} ; + + +#if defined(CORE_FUTURE_USE_STRONG_EXCEPTION_PTR) + +using ExceptionPtr = StrongPtr; + +inline +void future_rethrow_exception(const ExceptionPtr &exception) +{ + throw *exception; +} + +template +ExceptionPtr make_exception(T &&t) +{ + return strong>(std::forward(t)); +} + +#define CORE_FUTURE_CATCH_BEGIN(e) \ + catch (Exception &e) + +#define CORE_FUTURE_CATCH_END + + +#elif defined(CORE_FUTURE_USE_STD_EXCEPTION_PTR) + +using ExceptionPtr = std::exception_ptr; + +inline +void future_rethrow_exception(const ExceptionPtr &exception) +{ + std::rethrow_exception(exception); +} + +template +ExceptionPtr make_exception(T &&t) +{ + try + { + throw t; + } + catch (...) + { + return std::current_exception(); + } +} + +inline +ExceptionPtr make_exception(ExceptionPtr exception) +{ + return exception; +} + +#define CORE_FUTURE_CATCH_BEGIN(e) \ + catch (...) \ + { \ + auto e = std::current_exception(); \ + + +#define CORE_FUTURE_CATCH_END \ + } + +#endif + +template +struct Then : Dependency +{ + StrongPtr> dependency; + + typedef std::function> &)> F; + F f; + + Then(const StrongPtr> &dependency_, F &&f_) : + dependency(dependency_), + f(std::move(f_)) + { + FuturesLogDebug(tjp::core::futures::Then, logOfThis(this) << "constructor " << type_id().name()); + } + + ~Then () + { + FuturesLogDebug(tjp::core::futures::Then, logOfThis(this) << "destructor " << type_id().name()); + } + + void execute() + { + auto f_ = std::move(f); + f_(dependency); + } +} ; + +template +struct Shared_ +{ + typedef Shared_ Self; + StrongPtr dependency; + ExceptionPtr exception; + + bool isSet; + mutable Event::Mutex mutex; + mutable Event event; + + Shared_(const Shared_ &) = delete; + Shared_(Shared_ &&) = delete; + + Shared_ () : + isSet(false) + { + FuturesLogDebug(tjp::core::futures::Shared_, logOfThis(this) << "constructor " << type_id().name()); + } + + ~Shared_ () + { + FuturesLogDebug(tjp::core::futures::Shared_, logOfThis(this) << "destructor " << type_id().name()); + } + + template + void except_hasLock(E &&e) + { + debug_assert(mutex.locked_by_caller()); + exception = make_exception(std::forward(e)); + set_notify(); + } + + void set_notify () + { + FuturesLogDebug(tjp::core::futures::Shared_::set_notify, logOfThis(this) << type_id().name()); + + debug_assert(!isSet); + isSet = true; + dependency = {}; + event.notify_all(); + } + + void wait () const + { + // first time before lock, fast + auto l = lock_of(mutex); + while (!isSet) + event.wait(l); + + #ifdef FUTURES_THEN_ON_WAIT + if (!thens.empty()) + const_cast(this)->execute(l); + #endif + } + + void raise () const + { + wait(); + + if (exception) + future_rethrow_exception(exception); + } + + bool is_set () const + { + return isSet; + } + + typedef std::list>> Thens; + Thens thens; + + template + auto generate_then( + const StrongPtr> &self, + const WeakPtr> &value, + F &&f + ) + { + auto then = strong>( + self, + [value, f=std::move(f)](const StrongPtr> &t) { + if (auto value_ = strong(value)) + { + Promise promise(value_); + promise.consume(f, Future(t)); + } + } + ); + + return then; + } + + template + auto then(const StrongPtr> &self, F &&f) + { + auto value = strong>(); + Future future(value); + + auto then__ = generate_then(self, weak(value), std::forward(f)); + + value->dependency = then__; + thens.push_back(weak(then__)); + + return future; + } + + #ifdef FUTURES_THEN_ON_WAIT + virtual void execute (Event::Mutex::Lock &l) = 0; + #endif +} ; + +template +struct Shared : Shared_ +{ + typedef Shared_ Super; + + Optional value; + + template + void set(R && ... value_) + { + Event::Mutex::Lock l(Super::mutex); + value.emplace(std::forward(value_)...); + Super::set_notify(); + execute(l); + } + +// void set(const T &value_) +// { +// Event::Mutex::Lock l(Super::mutex); +// value = value_; +// Super::set_notify(); +// execute(l); +// } + + template + void except(E &&e) + { + Event::Mutex::Lock l(Super::mutex); + Super::except_hasLock(std::forward(e)); + execute(l); + } + +// const T &get () const +// { +// Super::raise(); +// return value; +// } + + T &get () + { + Super::raise(); + return *value; + } + + #ifdef FUTURES_THEN_ON_CONSTRUCT + template + auto then(const StrongPtr> &self, F &&f) + { + using R = decltype(f(Future(this))); + + Super::wait(); + + Promise promise; + promise.consume(f, Future(self)); + return promise.get_future(); + } + #else + template + auto then(const StrongPtr> &self, F &&f) + { + Event::Mutex::Lock l(Super::mutex); + using R = decltype(f(Future(self))); + + auto future = Super::template then(self, std::forward(f)); + + if (Super::is_set()) + execute(l); + + return future; + } + #endif + + void execute (Event::Mutex::Lock &l) + #ifdef FUTURES_THEN_ON_WAIT + override + #endif + { + FuturesLogDebug(tjp::core::futures::Shared_::execute, logOfThis(this) << type_id().name()); + + auto thens_ = std::move(Super::thens); + l.unlock(); + + while (!thens_.empty()) + { + auto &then = thens_.front(); + if (auto then_ = strong(then)) + then_->execute(); + + thens_.pop_front(); + } + } +} ; + + +template +struct Promise_ +{ + using shared_ptr = StrongPtr>; + shared_ptr shared; + + Promise_() : + shared(strong>()) + { + } + + Promise_(const StrongPtr> &shared_) : shared(shared_) {} + + template + static void set_exception(shared_ptr &shared, E &&exception) + { + shared->except(std::forward(exception)); + } + + template + void set_exception(E &&exception) + { + set_exception(shared, std::forward(exception)); + } + + Future get_future () + { + return Future(shared); + } + + bool is_set () + { + return shared->is_set(); + } +} ; + +template +struct Promise : public Promise_ +{ + typedef Promise_ Super; + using shared_ptr = typename Super::shared_ptr; + + Promise() {} + Promise(const StrongPtr> &value_) : Super(value_) {} + ~Promise () {} + + template + static void set_value(shared_ptr &shared, R && ...t) + { + shared->set(std::forward(t)...); + } + +// static void set_value(shared_ptr &shared, const T &t) +// { +// shared->set(t); +// } + + template + void set_value(R && ...t) + { + set_value(Super::shared, std::forward(t)...); + } + +// void set_value(const T &t) +// { +// set_value(Super::shared, t); +// } + + template + void consume(const F &f, V && ...v) + { + auto shared_ = weak(Super::shared); + + try + { + auto result = f(std::forward(v)...); + if (auto shared = strong(shared_)) + set_value(shared, std::forward(result)); + } + CORE_FUTURE_CATCH_BEGIN(e) + { + if (auto shared = strong(shared_)) + Super::set_exception(shared, e); + } + CORE_FUTURE_CATCH_END + } + + template + void consume(const F &f) + { + auto shared_ = weak(Super::shared); + + try + { + auto result = f(); + if (auto shared = strong(shared_)) + this->set_value(shared, std::forward(result)); + } + CORE_FUTURE_CATCH_BEGIN(e) + { + if (auto shared = strong(shared_)) + Super::set_exception(shared, e); + } + CORE_FUTURE_CATCH_END + } +} ; + +template +struct Future_ +{ + typedef T value_type; + + StrongPtr> shared; + + Future_(const StrongPtr> &shared_) : shared(shared_) {} + Future_() {} + + ~Future_ () + { + FuturesLogDebug(tjp::core::futures::Future_, logOfThis(this) << " destructing " << type_id().name() << ": " << SmartPtrBase::getInfoFor(ptr_of(shared))); + } + + void wait () const + { + shared->wait(); + } + + bool valid () const + { + return (bool)shared; + } + + bool is_set () const + { + return shared->is_set(); + } + + void cancel () + { + shared->cancel(); + } +} ; + +template +struct Future : public Future_ +{ + typedef Future_ Super; + typedef T value_type; + + Future(const StrongPtr> &promise_) : Super(promise_) {} + Future() {} + + T &get () + { + return Super::shared->get(); + } + + void raise() const + { + return Super::shared->raise(); + } + + template + auto then(F &&f) + { + return Super::shared->then(Super::shared, std::forward(f)); + } +} ; + +} // namespace + +template +using Promise = detail::Promise; + +template +using Future = detail::Future; + +} // namespace + +template +using Promise = futures::Promise; + +template +using Future = futures::Future; + +} // namespace +} // namespace + + diff --git a/tjp/core/future/custom/Future_Requirements.hpp b/tjp/core/future/custom/Future_Requirements.hpp new file mode 100755 index 0000000..e912400 --- /dev/null +++ b/tjp/core/future/custom/Future_Requirements.hpp @@ -0,0 +1,24 @@ +// TJP COPYRIGHT HEADER + +#pragma once + +#ifdef TIMPREPSCIUS_CORE_STANDALONE + #include "StandaloneCore.ipp" +#else + #include + #include + #include + #include + #include +#endif + +#include +#include +#include + +#ifdef FUTURES_ENABLE_LOG +#include "../../log/Log.h" +#define FuturesLogDebug(x,y) xLogDebug(x,y) +#else +#define FuturesLogDebug(x,y) +#endif diff --git a/tjp/core/future/custom/Future_void.h b/tjp/core/future/custom/Future_void.h new file mode 100755 index 0000000..4a0ade4 --- /dev/null +++ b/tjp/core/future/custom/Future_void.h @@ -0,0 +1,31 @@ +// TJP COPYRIGHT HEADER + +#pragma once + +#include "Future_.h" + +namespace tjp { +namespace core { +namespace futures { +namespace detail { + +template<> +struct Future; + +template<> +struct Promise; + +template<> +struct Shared; + +template<> +struct Future; + + +} // namespace +} // namespace + +} // namespace +} // namespace + + diff --git a/tjp/core/future/custom/Future_void.hpp b/tjp/core/future/custom/Future_void.hpp new file mode 100755 index 0000000..6ce0a64 --- /dev/null +++ b/tjp/core/future/custom/Future_void.hpp @@ -0,0 +1,195 @@ +// TJP COPYRIGHT HEADER + +#pragma once + +#include "Future_void.h" +#include "Future_.hpp" + +namespace tjp { +namespace core { +namespace futures { +namespace detail { + +template<> +struct Future; + +template<> +struct Promise; + +template<> +struct Shared : Shared_ +{ + typedef Shared_ Super; + + void set() + { + Event::Mutex::Lock l(Super::mutex); + Super::set_notify(); + execute(l); + } + + template + void except(E &&e) + { + Event::Mutex::Lock l(Super::mutex); + Super::except_hasLock(std::forward(e)); + execute(l); + } + + void get () + { + Super::raise(); + } + + using Super::raise; + + template + auto then(const StrongPtr> &self, F &&f); + + void execute (Event::Mutex::Lock &l) + #ifdef FUTURES_THEN_ON_WAIT + override + #endif + { + auto thens_ = std::move(Super::thens); + l.unlock(); + + while (!thens_.empty()) + { + auto &then = thens_.front(); + if (auto then_ = strong(then)) + then_->execute(); + + thens_.pop_front(); + } + } +} ; + + +template<> +struct Promise : Promise_ +{ + typedef Promise_ Super; + + Promise() {} + Promise(const StrongPtr> &shared_) : Super(shared_) {} + ~Promise() {} + + static void set_value(shared_ptr &shared) + { + shared->set(); + } + + void set_value() + { + set_value(Super::shared); + } + + void get () + { + Super::shared->get(); + } + + template + void consume(const F &f, V && ... v) + { + auto shared_ = weak(Super::shared); + + try + { + f(std::forward(v)...); + if (auto shared = strong(shared_)) + set_value(shared); + } + CORE_FUTURE_CATCH_BEGIN(e) + { + if (auto shared = strong(shared_)) + Super::set_exception(shared, e); + } + CORE_FUTURE_CATCH_END + } + + template + void consume(const F &f) + { + auto shared_ = weak(Super::shared); + + try + { + f(); + if (auto shared = strong(shared_)) + set_value(shared); + } + CORE_FUTURE_CATCH_BEGIN(e) + { + if (auto shared = strong(shared_)) + Super::set_exception(shared, e); + } + CORE_FUTURE_CATCH_END + } + +} ; + +template<> +struct Future : Future_ +{ + typedef Future_ Super; + + Future(const StrongPtr> &shared_) : Super(shared_) {} + Future() {} + + void get () + { + shared->get(); + } + + void raise() const + { + shared->raise(); + } + + template + auto then(F &&f) + { + return Super::shared->then(Super::shared, std::forward(f)); + } +} ; + +//------------ + +#ifdef FUTURES_THEN_ON_CONSTRUCT +template +auto Shared::then(const StrongPtr> &self, F &&f) +{ + using R = decltype(f(Future(this))); + + Super::wait(); + + Promise promise; + promise.consume(f, Future(self)); + return promise.get_future(); +} +#else +template +auto Shared::then(const StrongPtr> &self, F &&f) +{ + Event::Mutex::Lock l(Super::mutex); + using R = decltype(f(Future(StrongPtr>()))); + + auto future = Super::template then(self, std::forward(f)); + if (Super::is_set()) + execute(l); + + return future; +} + +#endif + + +} // namespace +} // namespace + +} // namespace +} // namespace + + diff --git a/tjp/core/future/custom/_tests/Future.cpp b/tjp/core/future/custom/_tests/Future.cpp new file mode 100755 index 0000000..77340b0 --- /dev/null +++ b/tjp/core/future/custom/_tests/Future.cpp @@ -0,0 +1,394 @@ +// TJP COPYRIGHT HEADER + +#include +#include + +#include +#include +#include + +namespace tjp { +namespace core { +namespace futures { + +struct StructX { + char bytes[32]; +} ; + +struct CustomExceptionNotHandled {}; + +struct CustomExceptionHandled: Exception { + int x; + + CustomExceptionHandled(const String &s, int x_) : + Exception(s), + x(x_) + { + } +} ; + +SCENARIO("futures with thens", "[core::future]" ) +{ + GIVEN("sizeof") + { + Promise ap; + Promise bp; + Promise cp; + Promise dp; + Promise ep; + + sLogTest("testing", logVar(sizeof(ap)) << logVar(sizeof(bp)) << logVar(sizeof(cp)) << logVar(sizeof(dp)) << logVar(sizeof(ep))); + + Future af; + Future bf; + Future cf; + Future df; + Future ef; + + sLogTest("testing", logVar(sizeof(af)) << logVar(sizeof(bf)) << logVar(sizeof(cf)) << logVar(sizeof(df)) << logVar(sizeof(ef))); + + af = ap.get_future(); + bf = bp.get_future(); + cf = cp.get_future(); + df = dp.get_future(); + ef = ep.get_future(); + + sLogTest("testing", logVar(sizeof(ap)) << logVar(sizeof(bp)) << logVar(sizeof(cp)) << logVar(sizeof(dp)) << logVar(sizeof(ep))); + sLogTest("testing", logVar(sizeof(af)) << logVar(sizeof(bf)) << logVar(sizeof(cf)) << logVar(sizeof(df)) << logVar(sizeof(ef))); + + ap.set_value(); + bp.set_value(0); + cp.set_value(0); + dp.set_value(0); + ep.set_value(StructX{}); + + sLogTest("testing", logVar(sizeof(ap)) << logVar(sizeof(bp)) << logVar(sizeof(cp)) << logVar(sizeof(dp)) << logVar(sizeof(ep))); + sLogTest("testing", logVar(sizeof(af)) << logVar(sizeof(bf)) << logVar(sizeof(cf)) << logVar(sizeof(df)) << logVar(sizeof(ef))); + } + + GIVEN("a void promise") + { + Promise p; + + WHEN("setting a value directly") + { + auto future = p.get_future(); + p.set_value(); + + future.wait(); + REQUIRE(true); + } + + WHEN ("manifesting an exception") + { + auto future = p.get_future() + .then([](auto &&f) { + throw Exception("made exception"); + }); + + p.set_value(); + + try + { + future.get(); + REQUIRE(false); + } + catch (Exception &e) + { + REQUIRE(e.what() == "made exception"); + } + } + + WHEN("manifesting a custom handled exception in then") + { + auto future = p.get_future() + .then([](auto &&f) { + throw CustomExceptionHandled("made exception", 42); + }); + + p.set_value(); + + try + { + future.get(); + REQUIRE(false); + } + catch (CustomExceptionHandled &e) + { + REQUIRE(e.what() == "made exception"); + REQUIRE(e.x == 42); + } + catch (Exception &e) + { + REQUIRE(false); + } + catch (...) + { + REQUIRE(false); + } + } + + WHEN("manifesting a custom handled exception") + { + p.consume([]() { + throw CustomExceptionHandled("made exception", 42); + }); + + auto future = p.get_future(); + + try + { + future.get(); + REQUIRE(false); + } + catch (CustomExceptionHandled &e) + { + REQUIRE(e.what() == "made exception"); + REQUIRE(e.x == 42); + } + catch (Exception &e) + { + REQUIRE(false); + } + } + + WHEN ("manifesting an exception through a chain") + { + auto future = p.get_future() + .then([](auto &&f) { + throw Exception("made exception"); + return 1; + }) + .then([](const auto &f) { + return -1.0; + }); + + p.set_value(); + + auto value = future.get(); + REQUIRE(value == -1); + } + } + + GIVEN("a void promise ptr") + { + Promise *p; + p = new Promise(); + + WHEN("setting a consume") + { + auto future = p->get_future(); + + p->consume([&](){ delete p; p = nullptr; }); + + future.wait(); + REQUIRE(true); + } + } + + GIVEN("an integer promise") + { + Promise p; + + WHEN("setting a value directly") + { + auto future = p.get_future(); + p.set_value(1); + + future.wait(); + auto value = future.get(); + REQUIRE(value == 1); + } + + WHEN ("settings a value with a then") + { + auto future = p.get_future(); + auto next = future.then([](auto f) { + return f.get() + 1; + }); + + p.set_value(1); + + auto value = next.get(); + REQUIRE(value == 2); + } + + WHEN ("settings a value with a then chain") + { + auto future = p.get_future() + .then([](auto &&f) { + return f.get() + 1; + }) + .then([](auto &&f) { + return f.get() + 1; + }); + + p.set_value(1); + + auto value = future.get(); + REQUIRE(value == 3); + } + + WHEN ("settings a value with a then chain changing type") + { + auto future = p.get_future() + .then([](auto &&f) { + return f.get() + 1; + }) + .then([](auto &&f) { + return f.get() + 1.5; + }); + + p.set_value(1); + + auto value = future.get(); + REQUIRE(value == 3.5); + } + + WHEN ("manifesting an exception") + { + auto future = p.get_future() + .then([](auto &&f) { + throw Exception("made exception"); + return f.get()+1; + }) + .then([](auto &&f) { + return f.get() + 1.5; + }); + + p.set_value(1); + + try + { + future.get(); + REQUIRE(false); + } + catch (Exception &e) + { + REQUIRE(e.what() == "made exception"); + } + } + + WHEN ("manifesting an exception but ignoring") + { + auto future = p.get_future() + .then([](auto &&f) { + throw Exception("made exception"); + return f.get()+1; + }) + .then([](auto &&f) { + try + { + return f.get() + 1.5; + } + catch (Exception &e) + { + return -1.0; + } + }); + + p.set_value(1); + + auto value = future.get(); + REQUIRE(value == -1); + } + + WHEN ("manifesting an exception but not even checking") + { + auto future = p.get_future() + .then([](auto &&f) { + throw Exception("made exception"); + return f.get()+1; + }) + .then([](auto &&f) { + return -1.0; + }); + + p.set_value(1); + + auto value = future.get(); + REQUIRE(value == -1); + } + } + + GIVEN("an strongptr promise") + { + Promise> p; + + WHEN ("settings a value with a then chain changing type") + { + auto future = p.get_future() + .then([](auto &&f) { + return *f.get() + 1; + }) + .then([](auto &&f) { + return f.get() + 1; + }); + + p.set_value(strong(1)); + + auto value = future.get(); + REQUIRE(value == 3); + } + } + + GIVEN("a promise") + { + Promise p; + + WHEN ("a future with multiple thens") + { + auto future = p.get_future(); + auto then1 = future.then([](auto &&f) { + return f.get() + 1; + }); + + auto then2 = future.then([](auto &&f) { + return f.get() + 2; + }); + + p.set_value(1); + + auto value1 = then1.get(); + auto value2 = then2.get(); + auto value = value1 + value2; + REQUIRE(value == 5); + } + + WHEN ("a future with multiple thens") + { + auto future = p.get_future(); + + Future thena, thenb; + + { + auto then1 = future.then([](auto &&f) { + return f.get() + 1; + }); + + auto then2 = future.then([](auto &&f) { + return f.get() + 2; + }); + + thena = then1.then([](auto &&f) { + return f.get() + 1; + }); + + thenb = then2.then([](auto &&f) { + return f.get() + 1; + }); + } + + p.set_value(1); + + auto value1 = thena.get(); + auto value2 = thenb.get(); + auto value = value1 + value2; + REQUIRE(value == 7); + } + } +} + +} // namespace +} // namespace +} // namespace diff --git a/tjp/core/future/folly/Future.h b/tjp/core/future/folly/Future.h new file mode 100755 index 0000000..0264bf9 --- /dev/null +++ b/tjp/core/future/folly/Future.h @@ -0,0 +1,19 @@ +// TJP COPYRIGHT HEADER + +#pragma once + +#include + +namespace tjp { +namespace core { + +template +using Promise = folly:Promise; + +template +using Future = folly::Future; + +} // namespace +} // namespace + + diff --git a/tjp/core/future/future_discard_exception.hpp b/tjp/core/future/future_discard_exception.hpp new file mode 100755 index 0000000..8bac5db --- /dev/null +++ b/tjp/core/future/future_discard_exception.hpp @@ -0,0 +1,30 @@ +// TJP COPYRIGHT HEADER + +#pragma once + +#include "Future.hpp" + +#include + +namespace tjp::core { + +// Non-void version +template().get())> +// typename = std::enable_if_t> +> +Optional future_discard_exception(T &&f) +{ + try + { + return f.get(); + } + CORE_FUTURE_CATCH_BEGIN(e) + { + } + CORE_FUTURE_CATCH_END + + return {}; +} + +} // namespace diff --git a/tjp/core/future/future_handle_exception.hpp b/tjp/core/future/future_handle_exception.hpp new file mode 100755 index 0000000..83231f9 --- /dev/null +++ b/tjp/core/future/future_handle_exception.hpp @@ -0,0 +1,27 @@ +// TJP COPYRIGHT HEADER + +#pragma once + +#include "Future.hpp" + +namespace tjp { +namespace core { + +template +Future future_handle_exception(Future &&f, U &&u) +{ + return f.then([u_ = std::move(u)](auto &&f) { + try + { + return f.get(); + } + catch (Exception &e) + { + u_(e); + throw e; + } + }); +} + +} // namespace +} // namespace diff --git a/tjp/core/future/future_is_exception.hpp b/tjp/core/future/future_is_exception.hpp new file mode 100755 index 0000000..ec78c68 --- /dev/null +++ b/tjp/core/future/future_is_exception.hpp @@ -0,0 +1,25 @@ +// TJP COPYRIGHT HEADER + +#pragma once + +#include "Future.hpp" + +namespace tjp { +namespace core { + +template +bool future_is_exception(Future &f) +{ + try + { + f.get(); + return false; + } + catch (...) + { + return true; + } +} + +} // namespace +} // namespace diff --git a/tjp/core/future/future_on_exception.hpp b/tjp/core/future/future_on_exception.hpp new file mode 100755 index 0000000..96306be --- /dev/null +++ b/tjp/core/future/future_on_exception.hpp @@ -0,0 +1,29 @@ +// TJP COPYRIGHT HEADER + +#pragma once + +#include "Future.hpp" + +#include + +namespace tjp::core { + +template().get()) +// typename = std::enable_if_t> +> +R future_on_exception(T &&f, U &&u) +{ + try + { + return f.get(); + } + CORE_FUTURE_CATCH_BEGIN(e) + { + u(e); + throw; + } + CORE_FUTURE_CATCH_END +} + +} // namespace diff --git a/tjp/core/future/future_on_exception_value.hpp b/tjp/core/future/future_on_exception_value.hpp new file mode 100755 index 0000000..9d22411 --- /dev/null +++ b/tjp/core/future/future_on_exception_value.hpp @@ -0,0 +1,39 @@ +// TJP COPYRIGHT HEADER + +#pragma once + +#include "Future.hpp" + +#include + +namespace tjp::core { + +template().get()) +// typename = std::enable_if_t> +> +R future_on_exception_value(T &&f, U &&u) +{ + try + { + return f.get(); + } + catch(std::exception &e) + { + u(Exception(e.what())); + throw; + } + catch(Exception &e) + { + u(e); + throw; + } + CORE_FUTURE_CATCH_BEGIN(e) + { + u(Exception("Unknown")); + throw; + } + CORE_FUTURE_CATCH_END +} + +} // namespace diff --git a/tjp/core/future/future_on_exception_what.hpp b/tjp/core/future/future_on_exception_what.hpp new file mode 100755 index 0000000..f858ddb --- /dev/null +++ b/tjp/core/future/future_on_exception_what.hpp @@ -0,0 +1,39 @@ +// TJP COPYRIGHT HEADER + +#pragma once + +#include "Future.hpp" + +#include + +namespace tjp::core { + +template().get()) +// typename = std::enable_if_t> +> +R future_on_exception_what(T &&f, U &&u) +{ + try + { + return f.get(); + } + catch(std::exception &e) + { + u(String(e.what())); + throw; + } + catch(Exception &e) + { + u(e.what()); + throw; + } + CORE_FUTURE_CATCH_BEGIN(e) + { + u(String("Unknown")); + throw; + } + CORE_FUTURE_CATCH_END +} + +} // namespace diff --git a/tjp/core/future/future_success.hpp b/tjp/core/future/future_success.hpp new file mode 100755 index 0000000..c440bc6 --- /dev/null +++ b/tjp/core/future/future_success.hpp @@ -0,0 +1,29 @@ +// TJP COPYRIGHT HEADER + +#pragma once + +#include "Future.hpp" +#include + +namespace tjp { +namespace core { + +template +auto future_success(F &&f) +{ + typedef typename std::remove_reference::type R; + + try + { + if (f.valid()) + return Optional { f.get() }; + } + catch(...) + { + } + + return Optional{}; +} + +} // namespace +} // namespace diff --git a/tjp/core/future/liblw/Future.h b/tjp/core/future/liblw/Future.h new file mode 100755 index 0000000..4d2e218 --- /dev/null +++ b/tjp/core/future/liblw/Future.h @@ -0,0 +1,19 @@ +// TJP COPYRIGHT HEADER + +#pragma once + +#include + +namespace tjp { +namespace core { + +template +using Promise = lw::event::Promise; + +template +using Future = lw::event::Future; + +} // namespace +} // namespace + + diff --git a/tjp/core/future/weak_future_consume.hpp b/tjp/core/future/weak_future_consume.hpp new file mode 100755 index 0000000..ee43e64 --- /dev/null +++ b/tjp/core/future/weak_future_consume.hpp @@ -0,0 +1,57 @@ +// TJP COPYRIGHT HEADER + +#pragma once + +#include + +namespace tjp::core { + +template +void weak_future_consume_value(T &&shared_, F &&f, V && ... v) +{ + + try + { + auto result = std::forward(f)(std::forward(v)...); + if (auto shared = strong(shared_)) + shared->set(std::move(result)); + } + CORE_FUTURE_CATCH_BEGIN(e) + { + if (auto shared = strong(shared_)) + shared->except(std::move(e)); + } + CORE_FUTURE_CATCH_END +} + +template +void weak_future_consume_void(T &&shared_, F &&f, V && ... v) +{ + + try + { + std::forward(f)(std::forward(v)...); + if (auto shared = strong(shared_)) + shared->set(); + } + CORE_FUTURE_CATCH_BEGIN(e) + { + if (auto shared = strong(shared_)) + shared->except(std::move(e)); + } + CORE_FUTURE_CATCH_END +} + +template +void weak_future_consume(T &&shared_, F &&f, V && ... v) +{ + using R_Ref = decltype(std::forward(f)(std::forward(v)...)); + using R = std::remove_reference_t(); + + if constexpr(std::is_void_v) + return weak_future_consume_void(std::forward(shared_), std::forward(f), std::forward(v)...); + else + return weak_future_consume_value(std::forward(shared_), std::forward(f), std::forward(v)...); +} + +} // namespace