flatten 20260225

This commit is contained in:
Timothy Prepscius
2026-02-25 12:28:38 -05:00
commit b9c17f9506
59 changed files with 4984 additions and 0 deletions

4
.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
.DS_Store
*.pyc
xcuserdata
.bin

View File

@@ -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 = "<group>"; };
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 = "<group>"; };
F608A9C92826BCB6005C276B /* PromiseOfFutures.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PromiseOfFutures.h; sourceTree = "<group>"; };
F608A9CA2826BCB6005C276B /* PromiseOfFutures.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = PromiseOfFutures.hpp; sourceTree = "<group>"; };
F608A9CB2826BCB6005C276B /* FutureChain.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = FutureChain.hpp; sourceTree = "<group>"; };
F608A9CC2826BCB6005C276B /* PromiseLocked.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = PromiseLocked.cpp; sourceTree = "<group>"; };
F608A9CD2826BCB6005C276B /* Future.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Future.h; sourceTree = "<group>"; };
F608A9CE2826BCB6005C276B /* WorkPromise.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WorkPromise.h; sourceTree = "<group>"; };
F608A9CF2826BCB6005C276B /* Futures.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Futures.cpp; sourceTree = "<group>"; };
F608A9D02826BCB6005C276B /* Future.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Future.hpp; sourceTree = "<group>"; };
F608A9D22826BCB6005C276B /* Future.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Future.h; sourceTree = "<group>"; };
F608A9D32826BCB6005C276B /* FutureEvent.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = FutureEvent.hpp; sourceTree = "<group>"; };
F608A9D42826BCB6005C276B /* WorkPromise.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = WorkPromise.hpp; sourceTree = "<group>"; };
F608A9D52826BCB6005C276B /* PromiseLocked.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = PromiseLocked.hpp; sourceTree = "<group>"; };
F608A9D62826BCB6005C276B /* FutureChain.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = FutureChain.cpp; sourceTree = "<group>"; };
F608A9D72826BCB6005C276B /* Futures.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Futures.h; sourceTree = "<group>"; };
F608A9D82826BCB6005C276B /* PromiseLocked.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PromiseLocked.h; sourceTree = "<group>"; };
F608A9DA2826BCB6005C276B /* Future.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Future.h; sourceTree = "<group>"; };
F608A9DB2826BCB6005C276B /* Future.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Future.hpp; sourceTree = "<group>"; };
F608A9DC2826BCB6005C276B /* Future.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Future.cpp; sourceTree = "<group>"; };
F608A9DD2826BCB6005C276B /* Future_.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Future_.h; sourceTree = "<group>"; };
F608A9DE2826BCB6005C276B /* Future_.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Future_.hpp; sourceTree = "<group>"; };
F608A9DF2826BCB6005C276B /* Future_void.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Future_void.hpp; sourceTree = "<group>"; };
F608A9E02826BCB6005C276B /* Future_Requirements.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Future_Requirements.hpp; sourceTree = "<group>"; };
F608A9E22826BCB6005C276B /* Future_void.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Future_void.h; sourceTree = "<group>"; };
F608A9E32826BCB6005C276B /* Future.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Future.cpp; sourceTree = "<group>"; };
F608A9E52826BCB6005C276B /* Future.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Future.h; sourceTree = "<group>"; };
F608A9E62826BCB6005C276B /* PromiseOfFutures.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = PromiseOfFutures.cpp; sourceTree = "<group>"; };
F608A9E82826BCB6005C276B /* Future.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Future.h; sourceTree = "<group>"; };
F608A9E92826BCB6005C276B /* Futures.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Futures.hpp; sourceTree = "<group>"; };
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 = "<group>"; };
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 = "<group>"; };
F608AB6A2827F3BC005C276B /* Makefile.project */ = {isa = PBXFileReference; lastKnownFileType = text; path = Makefile.project; sourceTree = "<group>"; };
F61F9BF12C6E4DFC00F79137 /* Makefile.project */ = {isa = PBXFileReference; lastKnownFileType = text; path = Makefile.project; sourceTree = "<group>"; };
F62757BA2B307D7C00655557 /* future_handle_exception.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = future_handle_exception.hpp; sourceTree = "<group>"; };
F633E93C2915B72B007A4C26 /* after.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = after.hpp; sourceTree = "<group>"; };
F633E93D2915B970007A4C26 /* after.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = after.cpp; sourceTree = "<group>"; };
F635F7C82E3B950B00E3D1D6 /* future_is_exception.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = future_is_exception.hpp; sourceTree = "<group>"; };
F63DCC5C2EDA451D003BEE7C /* future_on_exception_what.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = future_on_exception_what.hpp; sourceTree = "<group>"; };
F63DCC5D2EDA5CE9003BEE7C /* future_on_exception_value.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = future_on_exception_value.hpp; sourceTree = "<group>"; };
F66A9DEA290C641600AA74BD /* future_on_exception.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = future_on_exception.hpp; sourceTree = "<group>"; };
F676CAC12E9211A700BE5ACC /* future_success.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = future_success.hpp; sourceTree = "<group>"; };
F6865CAE289C0B5F00A46111 /* FutureResult_v1.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = FutureResult_v1.hpp; sourceTree = "<group>"; };
F6865CAF289C0C6700A46111 /* FutureResult.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FutureResult.h; sourceTree = "<group>"; };
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 = "<group>"; };
F6B4CFC12A6D7303004B9AB5 /* WeakFuture.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = WeakFuture.hpp; sourceTree = "<group>"; };
F6BF9BE52E390216002E6AF0 /* Makefile */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = "<group>"; };
F6CC6A2B2D076B5D00D533B7 /* FutureErase.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = FutureErase.hpp; sourceTree = "<group>"; };
F6CC6A2C2D076B7300D533B7 /* FutureErase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FutureErase.cpp; sourceTree = "<group>"; };
F6CC6A2E2D076BEB00D533B7 /* FutureResult_v2.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = FutureResult_v2.hpp; sourceTree = "<group>"; };
F6CC6A2F2D076C1500D533B7 /* FutureResult.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = FutureResult.hpp; sourceTree = "<group>"; };
F6CC6A302D07771200D533B7 /* FutureResult.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = FutureResult.cpp; sourceTree = "<group>"; };
F6DDE7012DAABA93005F94FC /* after_using.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = after_using.hpp; sourceTree = "<group>"; };
F6F53DD528F5A9F000E878EF /* FutureStrong.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = FutureStrong.hpp; sourceTree = "<group>"; };
/* 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 = "<group>";
};
F608A9C02826BC54005C276B /* Products */ = {
isa = PBXGroup;
children = (
F608A9BF2826BC54005C276B /* libCore_Future.a */,
F608AA7F2826BE2A005C276B /* Core_Future_Tests */,
F6971F3C282B119C008FBD17 /* libCore_Future_iOS.a */,
);
name = Products;
sourceTree = "<group>";
};
F608A9C62826BCB6005C276B /* core */ = {
isa = PBXGroup;
children = (
F608A9C72826BCB6005C276B /* future */,
);
path = core;
sourceTree = "<group>";
};
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 = "<group>";
};
F608A9D12826BCB6005C276B /* boost */ = {
isa = PBXGroup;
children = (
F608A9D22826BCB6005C276B /* Future.h */,
);
path = boost;
sourceTree = "<group>";
};
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 = "<group>";
};
F608A9E42826BCB6005C276B /* liblw */ = {
isa = PBXGroup;
children = (
F608A9E52826BCB6005C276B /* Future.h */,
);
path = liblw;
sourceTree = "<group>";
};
F608A9E72826BCB6005C276B /* folly */ = {
isa = PBXGroup;
children = (
F608A9E82826BCB6005C276B /* Future.h */,
);
path = folly;
sourceTree = "<group>";
};
F608AA802826BE2A005C276B /* tests */ = {
isa = PBXGroup;
children = (
F61F9BF12C6E4DFC00F79137 /* Makefile.project */,
F608AA812826BE2A005C276B /* main.cpp */,
);
path = tests;
sourceTree = "<group>";
};
F608AA862826BE82005C276B /* Frameworks */ = {
isa = PBXGroup;
children = (
F608AA872826BE82005C276B /* libCore_Zero.a */,
);
name = Frameworks;
sourceTree = "<group>";
};
F61D7C422E38168F002A1AED /* tjp */ = {
isa = PBXGroup;
children = (
F608A9C62826BCB6005C276B /* core */,
);
path = tjp;
sourceTree = "<group>";
};
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 = "<group>";
};
F61F9BF32C6E4E3800F79137 /* _tests */ = {
isa = PBXGroup;
children = (
F608A9DC2826BCB6005C276B /* Future.cpp */,
);
path = _tests;
sourceTree = "<group>";
};
/* 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 */;
}

View File

@@ -0,0 +1,92 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1330"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "F608AA7E2826BE2A005C276B"
BuildableName = "Core_Future_Tests"
BlueprintName = "Core_Future_Tests"
ReferencedContainer = "container:Core_Future.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "F608AA7E2826BE2A005C276B"
BuildableName = "Core_Future_Tests"
BlueprintName = "Core_Future_Tests"
ReferencedContainer = "container:Core_Future.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<CommandLineArguments>
<CommandLineArgument
argument = "-s"
isEnabled = "YES">
</CommandLineArgument>
<CommandLineArgument
argument = "&quot;Scenario: core::future::future_chain&quot;"
isEnabled = "NO">
</CommandLineArgument>
<CommandLineArgument
argument = "-b"
isEnabled = "YES">
</CommandLineArgument>
</CommandLineArguments>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "F608AA7E2826BE2A005C276B"
BuildableName = "Core_Future_Tests"
BlueprintName = "Core_Future_Tests"
ReferencedContainer = "container:Core_Future.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

2
Makefile Normal file
View File

@@ -0,0 +1,2 @@
ROOTDIR := $(realpath $(dir $(lastword $(MAKEFILE_LIST)))..)
include $(ROOTDIR)/Core_Make/tjp/Make/Makefile

6
Makefile.def Executable file
View File

@@ -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)

19
Makefile.project Executable file
View File

@@ -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

View File

@@ -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

1
tests/Makefile Symbolic link
View File

@@ -0,0 +1 @@
../../Make/Makefile

31
tests/Makefile.project Executable file
View File

@@ -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

19
tests/main.cpp Normal file
View File

@@ -0,0 +1,19 @@
// TJP COPYRIGHT HEADER
#define CATCH_CONFIG_RUNNER
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/log/Log.h>
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;
}

17
tjp/core/future/Future.h Executable file
View File

@@ -0,0 +1,17 @@
// TJP COPYRIGHT HEADER
#pragma once
#include "./custom/Future.h"
#include <type_traits>
#include <functional>
namespace tjp {
namespace core {
template<typename T> struct is_future : std::false_type {};
template<typename T> struct is_future<Future<T>> : std::true_type {};
template<> struct is_future<Future<void>> : std::true_type {};
} // namespace
} // namespace

205
tjp/core/future/Future.hpp Executable file
View File

@@ -0,0 +1,205 @@
// TJP COPYRIGHT HEADER
#pragma once
#include "Future.h"
#include "./custom/Future.hpp"
#include <tjp/core/algorithm/copy_of.hpp>
namespace tjp {
namespace core {
template<typename R, typename F>
Promise<R> &promise_of(Promise<R> &p, F &&f)
{
p.consume(f);
return p;
}
template<typename F>
auto future_of(F &&f)
{
using R_Ref = decltype(f());
using R = std::remove_reference_t<R_Ref>;
Promise<R> promise;
promise.consume(f);
return promise.get_future();
}
template<typename F, typename ... Args>
auto future_of(F &&f, Args && ... args)
{
using R_Ref = decltype(f(std::forward<Args>(args)...));
using R = std::remove_reference_t<R_Ref>;
Promise<R> promise;
promise.consume(f, std::forward<Args>(args)...);
return promise.get_future();
}
template<typename T>
auto future_of_value(T &&t)
{
using T_ = std::remove_reference_t<T>;
Promise<T_> promise;
promise.set_value(std::forward<T>(t));
return promise.get_future();
}
template<typename T>
Future<T> future_of_value(const T &t)
{
Promise<T> promise;
promise.set_value(t);
return promise.get_future();
}
inline
Future<void> future_of_value()
{
Promise<void> promise;
promise.set_value();
return promise.get_future();
}
template<typename T, typename E>
Future<T> future_of_exception(E &&e)
{
Promise<T> promise;
promise.set_exception(std::forward<E>(e));
return promise.get_future();
}
template<typename T, typename E>
Future<T> future_of_exception(const E &e)
{
return future_of_exception<T, E>(E(e));
}
template<typename F>
auto future_with(F &&f)
{
using R_Ref = decltype(f());
using R = std::remove_reference_t<R_Ref>;
if constexpr (is_future<R>::value)
{
using RV = typename R::value_type;
try
{
return f();
}
CORE_FUTURE_CATCH_BEGIN(e)
{
return future_of_exception<RV>(e);
}
CORE_FUTURE_CATCH_END
}
else
{
return future_of(f);
}
}
template<typename F, typename ... Args>
auto future_with(F &&f, Args && ...args)
{
using R_Ref = decltype(f(std::forward<Args>(args)...));
using R = std::remove_reference_t<R_Ref>;
if constexpr (is_future<R>::value)
{
using RV = typename R::value_type;
try
{
return f(std::forward<Args>(args)...);
}
CORE_FUTURE_CATCH_BEGIN(e)
{
return future_of_exception<RV>(e);
}
CORE_FUTURE_CATCH_END
}
else
{
return future_of(f, std::forward<Args>(args)...);
}
}
template<typename T>
struct AsFuture_
{
T v;
template<typename U>
operator Future<U>()
{
return future_of_value<U>(std::move(v));
}
};
template<>
struct AsFuture_<void>
{
template<typename U>
operator Future<U>()
{
return future_of_value();
}
} ;
template<typename T>
AsFuture_<T> as_future(T &&t)
{
return AsFuture_<std::remove_reference_t<T>> { std::forward<T>(t) };
}
inline
AsFuture_<void> as_future()
{
return AsFuture_<void> { };
}
template<typename T>
struct AsFutureException_
{
T v;
template<typename U>
operator Future<U>()
{
return future_of_exception<U>(std::move(v));
}
};
template<typename T>
AsFutureException_<T> as_future_exception(T &&t)
{
return AsFutureException_<std::remove_reference_t<T>> { std::forward<T>(t) };
}
//template<typename F>
//auto future_with(F f) -> decltype(f()) {
// using R = typename decltype(f())::value_type;
// try {
// return f();
// }
// catch (Exception &e) {
// return future_of_exception<R>(copy_of(e));
// }
//}
//template<typename R, typename ...T, typename std::enable_if<!is_future<R>::value, R>::type*>
//auto with(std::function<R(T&&...)> &&f) {
// return f;
//}
//
} // namespace
} // namespace

4
tjp/core/future/FutureChain.h Executable file
View File

@@ -0,0 +1,4 @@
// TJP COPYRIGHT HEADER
#pragma once

177
tjp/core/future/FutureChain.hpp Executable file
View File

@@ -0,0 +1,177 @@
// TJP COPYRIGHT HEADER
#pragma once
#include "FutureChain.h"
#include "Futures.hpp"
#include <tjp/core/ptr/Ptr.hpp>
#include <type_traits>
#include <tjp/core/algorithm/copy_of.hpp>
#include <tjp/core/threads/Lock.hpp>
#include <tjp/core/debug/Debug.h>
namespace tjp {
namespace core {
namespace future_chain_detail {
struct FutureParent
{
virtual ~FutureParent() {}
} ;
template<typename FutureGeneratorParameter>
struct FutureExecutor : FutureParent
{
virtual void execute(const FutureGeneratorParameter &parameter) = 0;
} ;
template<typename FutureGeneratorParameter, typename FutureGenerator>
struct FutureNode : FutureExecutor<FutureGeneratorParameter>
{
FutureGenerator futureGenerator;
typedef decltype(futureGenerator(FutureGeneratorParameter())) FutureType;
typedef Promise<typename FutureType::value_type> PromiseType;
typedef FutureExecutor<FutureType> Child;
WeakPtr<FutureNode> self;
StrongPtr<FutureParent> parent;
Future<void> next;
PromiseType promise;
FutureType future;
WeakPtr<Child> link;
FutureNode(FutureGenerator &&futureGenerator_, const StrongPtr<FutureParent> &parent_) :
futureGenerator(std::move(futureGenerator_)),
parent(parent_)
{
future = promise.get_future();
}
~FutureNode()
{
xDebugLine();
}
static auto generate(FutureGenerator &&futureGenerator_, const StrongPtr<FutureParent> &parent_)
{
auto v = strong<FutureNode<FutureGeneratorParameter, FutureGenerator>>(std::move(futureGenerator_), parent_);
v->self = weak(v);
return v;
}
template<typename F,
typename std::enable_if<std::is_invocable<F, FutureType>::value, F>::type* = nullptr
>
auto add(F &&nextFutureGenerator)
{
auto child = FutureNode<FutureType, F>::generate(std::move(nextFutureGenerator), strong(self));
if (future.is_set())
{
child->execute(future);
return child;
}
link = weak(child);
return child;
}
template<typename F,
typename std::enable_if<std::is_invocable<F>::value, F>::type* = nullptr
>
auto add(F &&nextFutureGenerator)
{
return add(
[nextFutureGenerator=std::move(nextFutureGenerator)](auto &&f) {
f.get();
return nextFutureGenerator();
}
);
}
void execute(const FutureGeneratorParameter &parameter) 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> &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<void> &&) {
return future_of_value();
};
auto chain =
FutureNode<Future<void>, decltype(empty)>::generate(
std::move(empty),
nullptr
);
chain->execute(Future<void>());
return chain;
}
} // namespace future_chain_detail
template<typename A, typename B>
auto future_chain_(A &&a, B &&b)
{
return a->add(std::forward<B>(b));
} ;
template<typename A, typename B, typename ...T>
auto future_chain_(A &&a, B &&b, T &&...t)
{
return future_chain_(a->add(std::forward<B>(b)), std::forward<T>(t)...);
} ;
template<typename ...T>
auto future_chain(T &&...t)
{
return future_chain_(future_chain_detail::FutureChain(), std::forward<T>(t)...)->get_future();
} ;
} // namespace
} // namespace

View File

@@ -0,0 +1,79 @@
// TJP COPYRIGHT HEADER
#pragma once
#include <tjp/core/future/Future.hpp>
#include <tjp/core/ptr/Ptr.hpp>
#include <tjp/core/ptr/strong_of.hpp>
#include <tjp/core/ptr/strong_emplace.hpp>
namespace tjp::core {
namespace futures::v2 {
struct FutureErase
{
StrongPtr<Future<void>> future;
FutureErase()
{}
template<typename T>
FutureErase(Future<T> &&future_)
{
set(std::move(future_));
}
~FutureErase()
{
clear();
}
template<typename T>
void set(Future<T> &&future_)
{
strong_emplace(future);
*future = future_.then([future_ = weak(future)](auto &&f){
if (auto future = strong(future_))
(*future) = {};
});
if (future->is_set())
future = {};
}
template<typename T>
void operator =(Future<T> &&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<void> get_future()
{
auto future_ = future;
return future_ ?
*future_ : future_of_value();
}
} ;
} // namespace
using FutureErase = futures::v2::FutureErase;
} // namespace

58
tjp/core/future/FutureEvent.hpp Executable file
View File

@@ -0,0 +1,58 @@
// TJP COPYRIGHT HEADER
#pragma once
#include <functional>
#include <tjp/core/log/Log.h>
namespace tjp {
namespace core {
template<typename T>
struct FutureEvent
{
typedef Future<T> F;
bool waiting_ = false;
Future<void> dependency;
std::function<void(F &&f)> on;
void set(Future<T> &&future_) {
waiting_ = true;
dependency = future_.then([this](F &&f) {
reset();
if (on)
on(std::forward<F>(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

10
tjp/core/future/FutureResult.h Executable file
View File

@@ -0,0 +1,10 @@
// TJP COPYRIGHT HEADER
#pragma once
namespace tjp::core {
template<typename T>
struct FutureResult;
} // namespace

View File

@@ -0,0 +1,5 @@
// TJP COPYRIGHT HEADER
#pragma once
#include "FutureResult_v1.hpp"

View File

@@ -0,0 +1,157 @@
// TJP COPYRIGHT HEADER
#pragma once
#include "Future.hpp"
#include <tjp/core/containers/Optional.hpp>
namespace tjp::core {
namespace futures::v1 {
template<typename T>
struct FutureResult_
{
enum Mode {
None,
Running,
Finished
};
Mode mode = None;
Future<T> future;
Optional<Exception> 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<T> &set(Future<T> &&future_)
{
mode = Running;
exception = {};
future = std::move(future_);
return future;
}
Future<T> &operator =(Future<T> &&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<typename T>
struct FutureResult : FutureResult_<T>
{
using Super = FutureResult_<T>;
Future<T> &operator =(Future<T> &&future_)
{
return this->set(std::move(future_));
}
const T &get()
{
return this->future.get();
}
} ;
template<>
struct FutureResult<void> : FutureResult_<void>
{
using Super = FutureResult_<void>;
Future<void> &operator =(Future<void> &&future_)
{
return this->set(std::move(future_));
}
} ;
} // namespace
using futures::v1::FutureResult;
} // namespace

View File

@@ -0,0 +1,183 @@
// TJP COPYRIGHT HEADER
#pragma once
#include "Future.hpp"
#include "FutureErase.hpp"
#include <tjp/core/containers/Optional.hpp>
namespace tjp::core {
namespace futures::v2 {
template<typename T>
struct ExpectedValue
{
Optional<T> value;
Optional<Exception> exception;
ExpectedValue(Future<T> &&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<void>
{
Optional<Exception> exception;
ExpectedValue(Future<void> &&f) {
try
{
f.get();
}
catch (const Exception &e)
{
exception.emplace(e);
}
}
void get()
{
if (exception)
throw *exception;
}
} ;
template<typename T>
struct FutureResult_
{
FutureErase future;
Optional<ExpectedValue<T>> 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<T> &&future_)
{
set(std::move(future_));
}
void set(Future<T> &&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<typename T>
struct FutureResult : FutureResult_<T>
{
using Super = FutureResult_<T>;
void operator =(Future<T> &&future_)
{
set(std::move(future_));
}
const T &get()
{
return this->expected->get();
}
} ;
template<>
struct FutureResult<void> : FutureResult_<void>
{
using Super = FutureResult_<void>;
void operator =(Future<void> &&future_)
{
set(std::move(future_));
}
} ;
} // namespace
using futures::v2::FutureResult;
} // namespace

View File

@@ -0,0 +1,49 @@
// TJP COPYRIGHT HEADER
#pragma once
#include <tjp/core/exception/NullPointer.hpp>
namespace tjp {
namespace core {
template<typename U>
auto future_strong(U &&f)
{
return f.then([](auto &&g) {
using T = typename std::remove_reference<decltype(g.get())>::type;
return strong<T>(std::move(g.get()));
});
}
template<typename T, typename U>
auto future_strong(U &&f)
{
return f.then([](auto &&g) {
return strong<T>(std::move(g.get()));
});
}
template<typename U>
auto future_strong_value(U &&f)
{
return f.then([](auto &&g) {
if (auto ptr = g.get())
return *ptr;
throw exceptions::NullPointer();
});
}
template<typename U>
auto future_strong_with(U &&ptr)
{
if (ptr)
return *ptr;
throw exceptions::NullPointer();
}
} // namespace
} // namespace

312
tjp/core/future/Futures.cpp Executable file
View File

@@ -0,0 +1,312 @@
// TJP COPYRIGHT HEADER
#include <tjp/core/header_only/compile.h>
#ifdef TJP_CORE_HEADER_ONLY
#pragma once
#endif
#include "Futures.hpp"
#include <tjp/core/threads/Lock.hpp>
#include <tjp/core/containers/List.hpp>
#include <tjp/core/containers/Vector.hpp>
#include <tjp/core/containers/Optional.hpp>
#include <tjp/core/threads/Atomic.h>
#include <tjp/core/algorithm/vector_erase_if_value.hpp>
#include <tjp/core/assert/debug_assert.h>
#include <tjp/core/containers/Map.hpp>
#include <tjp/core/containers/List.hpp>
#include <tjp/core/debug/Stack.h>
#include <tjp/core/string/String.h>
#include <tjp/core/algorithm/map_erase.hpp>
#include <tjp/core/time/Time.h>
#include <tjp/core/log/Log.h>
#include <tjp/core/log/LogOf.h>
//#define DEBUG_FUTURE_LEAKS_BUT_PROBLEMS_WITH_THIS
#ifdef DEBUG_FUTURE_LEAKS_BUT_PROBLEMS_WITH_THIS
#include <execinfo.h>
#include <sstream>
#endif
namespace tjp {
namespace core {
#ifdef DEBUG_FUTURE_LEAKS_BUT_PROBLEMS_WITH_THIS
static Atomic<size_t> 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<FuturePersist> future;
} ;
Map<void *, Leak> outstandingFutures;
time::Time lastLeaker = 0;
static void debug_log();
static void debug_futureCreated(const StrongPtr<FuturePersist> &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<StrongPtr<FuturePersist>> futures;
virtual void add(StrongPtr<Futures::Internal> &self, const StrongPtr<FuturePersist> &future)
{
StrongPtr<FuturePersist> 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<void> finished;
void onFuture(void *fp) override
{
Optional<Promise<void>> 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<void> get_future(StrongPtr<Futures::Internal> &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<Internal>();
}
TJP_CORE_HEADER_ONLY_INLINE
Futures::~Futures ()
{
}
TJP_CORE_HEADER_ONLY_INLINE
void Futures::add(const StrongPtr<FuturePersist> &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<FuturesEvent_Internal>();
}
TJP_CORE_HEADER_ONLY_INLINE
void FuturesEvent::wait ()
{
strong_ptr_cast<FuturesEvent_Internal>(internal)->wait();
}
// ------------------
TJP_CORE_HEADER_ONLY_INLINE
FuturesFuture::FuturesFuture() :
Super(Super::NoConstructInternal{})
{
internal = strong<FuturesFuture_Internal>();
}
TJP_CORE_HEADER_ONLY_INLINE
Future<void> FuturesFuture::get_future()
{
return strong_ptr_cast<FuturesFuture_Internal>(internal)->get_future(internal);
}
} // namespace
} // namespace

16
tjp/core/future/Futures.h Executable file
View File

@@ -0,0 +1,16 @@
// TJP COPYRIGHT HEADER
#pragma once
namespace tjp {
namespace core {
struct FuturePersist;
template<typename T>
struct FuturePersistTyped;
struct Futures;
} // namespace
} // namespace

87
tjp/core/future/Futures.hpp Executable file
View File

@@ -0,0 +1,87 @@
// TJP COPYRIGHT HEADER
#pragma once
#include "Futures.h"
#include "Future.hpp"
#include <tjp/core/ptr/Ptr.hpp>
namespace tjp::core {
struct FuturePersist
{
virtual ~FuturePersist () {}
virtual void inject(std::function<void(FuturePersist *)> &&t) = 0;
} ;
template<typename T>
struct FuturePersistTyped : FuturePersist
{
Future<T> f;
FuturePersistTyped(const Future<T> &f_) :
f(f_)
{}
void inject(std::function<void(FuturePersist *)> &&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> internal;
struct NoConstructInternal;
Futures (NoConstructInternal);
Futures ();
~Futures ();
void add(const StrongPtr<FuturePersist> &future);
template<typename T>
Future<T> add(const Future<T> &future)
{
auto persisted = strong<FuturePersistTyped<T>>(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<void> get_future();
} ;
} // namespace
#ifdef TJP_CORE_HEADER_ONLY
#include "Futures.cpp"
#endif

15
tjp/core/future/PromiseLocked.h Executable file
View File

@@ -0,0 +1,15 @@
// TJP COPYRIGHT HEADER
#pragma once
namespace tjp {
namespace core {
template<typename T>
struct PromiseLocked;
template<typename R, typename F>
PromiseLocked<R> &promise_of_and_reset(PromiseLocked<R> &p, F &&f);
} // namespace
} // namespace

168
tjp/core/future/PromiseLocked.hpp Executable file
View File

@@ -0,0 +1,168 @@
// TJP COPYRIGHT HEADER
#pragma once
#include "PromiseLocked.h"
#include "Future.hpp"
#include <tjp/core/type_traits/is_callable.hpp>
namespace tjp {
namespace core {
template<typename T>
struct PromiseLocked
{
Mutex m;
bool owned = false;
Promise<T> promise;
std::tuple<bool, Future<T>> 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 <typename U=T,
typename std::enable_if<!std::is_void<U>::value, U>::type* = nullptr
>
void set_value (U &&t)
{
auto l = lock_of(m);
debug_assert(owned);
promise.set_value(t);
owned = false;
}
template <typename U=T,
typename std::enable_if<!std::is_void<U>::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 <typename U=void,
typename std::enable_if<std::is_void<U>::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<typename F,
typename std::enable_if<std::is_invocable<F>::value>::type* = nullptr
>
void consume (F &&f)
{
auto l = lock_of(m);
debug_assert(owned);
promise.consume(std::forward<F>(f));
owned = false;
}
template<typename F,
typename std::enable_if<std::is_invocable<F>::value>::type* = nullptr
>
void reset_consume (F &&f)
{
debug_assert(owned);
Promise<T> o = reset();
o.consume(std::forward<F>(f));
}
template<typename F,
typename std::enable_if<!std::is_invocable<F>::value>::type* = nullptr
>
void consume (F &&f)
{
consume([&f]() { return f.get(); });
}
template<typename F,
typename std::enable_if<!std::is_invocable<F>::value>::type* = nullptr
>
void reset_consume (F &&f)
{
reset_consume([&f]() { return f.get(); });
}
template<typename V>
void consume_value (const V &v)
{
auto l = lock_of(m);
debug_assert(owned);
set_value(v);
owned = false;
}
template<typename V>
void reset_consume_value (const V &v)
{
debug_assert(owned);
Promise<T> o = reset();
o.set_value(v);
}
void release ()
{
auto l = lock_of(m);
debug_assert(owned);
owned = false;
}
Promise<T> reset ()
{
auto l = lock_of(m);
owned = false;
auto r = std::move(promise);
promise = {};
return r;
}
} ;
template<typename R, typename F>
PromiseLocked<R> &promise_of_and_reset(PromiseLocked<R> &p, F &&f)
{
p.reset_consume(std::forward<F>(f));
return p;
}
template<typename R, typename V>
PromiseLocked<R> &promise_of_and_reset_value(PromiseLocked<R> &p, const V &v)
{
p.reset_consume_value(v);
return p;
}
} // namespace
} // namespace

View File

@@ -0,0 +1,21 @@
// TJP COPYRIGHT HEADER
#pragma once
#include <tjp/core/ptr/Ptr.h>
namespace tjp {
namespace core {
template<typename T>
struct PromiseOfFutures;
template<>
struct PromiseOfFutures<void>;
template<typename T>
using PromiseOfFuturesPtr = StrongPtr<PromiseOfFutures<T>>;
} // namespace
} // namespace

View File

@@ -0,0 +1,228 @@
// TJP COPYRIGHT HEADER
#pragma once
#include "PromiseOfFutures.h"
#include "Futures.hpp"
#include <tjp/core/ptr/Ptr.hpp>
#include <tjp/core/log/Log.h>
#include <tjp/core/log/LogOf.h>
#include <atomic>
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<typename T>
struct PromiseOfFutures
{
typedef PromiseOfFutures<T> Self;
typedef StrongPtr<Self> Instance;
WeakPtr<Self> self;
T value;
StrongPtr<Exception> exception;
Futures futures;
Promise<T> promise;
std::atomic<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(value);
}
}
}
template<typename FT>
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<Exception>(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<typename F>
void consume(F &&f)
{
try
{
value = f.get();
}
catch (Exception &e)
{
exception = strong<Exception>(e);
}
}
template<typename F>
void consume_throw_exception(F &&f)
{
value = f.get();
}
void set(const T &t)
{
value = t;
}
static StrongPtr<PromiseOfFutures> generate()
{
auto v = strong<PromiseOfFutures>();
v->self = weak(v);
return v;
}
public:
PromiseOfFutures() {}
} ;
template<>
struct PromiseOfFutures<void>
{
typedef PromiseOfFutures<void> Self;
typedef StrongPtr<Self> Instance;
WeakPtr<Self> self;
StrongPtr<Exception> exception;
Futures futures;
Promise<void> 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<typename FT>
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<Exception>(e);
}
onCompletion();
}
}));
}
auto get_future ()
{
onCompletion();
return promise.get_future().then([self=strong(this->self)](auto &&f) {
return f.get();
});
}
template<typename F>
void consume(F &&f)
{
try
{
f.get();
}
catch (Exception &e)
{
exception = strong<Exception>(e);
}
}
template<typename F>
void consume_throw_exception(F &&f)
{
f.get();
}
static StrongPtr<PromiseOfFutures> generate()
{
auto v = strong<PromiseOfFutures>();
v->self = weak(v);
return v;
}
public:
PromiseOfFutures() {}
} ;
} // namespace
} // namespace

37
tjp/core/future/WeakFuture.hpp Executable file
View File

@@ -0,0 +1,37 @@
// TJP COPYRIGHT HEADER
#pragma once
#include "Future.hpp"
namespace tjp {
namespace core {
// this may need to be strong this
template<typename T>
struct WeakFuture
{
typedef Future<T> F;
F f;
u8 number = 0;
void set(Future<T> &&f_)
{
auto number_ = ++number;
f = f_.then([this, number_](auto &&) {
if (number_ == number)
f = {};
});
};
auto &operator =(Future<T> &&f_)
{
set(std::move(f_));
return *this;
}
} ;
} // namespace
} // namespace

12
tjp/core/future/WorkPromise.h Executable file
View File

@@ -0,0 +1,12 @@
// TJP COPYRIGHT HEADER
#pragma once
namespace tjp {
namespace core {
template<typename W, typename T>
struct WorkPromise;
} // namespace
} // namespace

27
tjp/core/future/WorkPromise.hpp Executable file
View File

@@ -0,0 +1,27 @@
// TJP COPYRIGHT HEADER
#pragma once
#include "PromiseOfFutures.hpp"
namespace tjp {
namespace core {
template<typename W, typename T>
struct WorkPromise : PromiseOfFutures<T>
{
typedef PromiseOfFutures<T> Super;
W work;
static StrongPtr<WorkPromise> generate()
{
auto v = strong<WorkPromise>();
v->self = weak(strong_ptr_cast<Super>(v));
return v;
}
} ;
} // namespace
} // namespace

View File

@@ -0,0 +1,257 @@
// TJP COPYRIGHT HEADER
#include <tjp/core/future/FutureChain.hpp>
#include <tjp/core/iterators/range.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/timer/Timer.hpp>
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<int> a;
Promise<std::string> b;
Promise<int> c;
Promise<int> 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<void> 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<void> 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<int> a;
Promise<std::string> b;
auto chain = future_chain_detail::FutureChain()
->add([&]() {
return a.get_future();
})
->add([&](Future<int> &&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<int> a;
Promise<std::string> b;
auto i = 32;
auto future = future_chain(
[&a, i]() {
return a.get_future();
},
[&b, i](Future<int> &&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<int> a;
Promise<std::string> 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

View File

@@ -0,0 +1,39 @@
// TJP COPYRIGHT HEADER
#include "../FutureErase.hpp"
#include <tjp/core/testing/catch.hpp>
namespace tjp::core::futures {
namespace {
SCENARIO("core::futures::FutureErase")
{
GIVEN("a Futures")
{
FutureErase futures;
WHEN("adding a future that resolves afterwards")
{
Promise<void> promise;
futures.set(promise.get_future());
REQUIRE(!futures.empty());
promise.set_value();
REQUIRE(futures.empty());
}
WHEN("adding a future that's already resolved")
{
Promise<void> promise;
promise.set_value();
futures.set(promise.get_future());
REQUIRE(futures.empty());
}
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,97 @@
// TJP COPYRIGHT HEADER
#include "../FutureResult.hpp"
#include <tjp/core/testing/catch.hpp>
namespace tjp::core::futures {
namespace {
SCENARIO("core::futures::FutureResult")
{
GIVEN("a FutureResult")
{
FutureResult<void> futures;
WHEN("adding a future that resolves afterwards")
{
Promise<void> promise;
futures.set(promise.get_future());
REQUIRE(futures.empty());
promise.set_value();
REQUIRE(!futures.empty());
}
WHEN("adding a future that's already resolved")
{
Promise<void> promise;
promise.set_value();
futures.set(promise.get_future());
REQUIRE(!futures.empty());
}
}
GIVEN("a FutureResult")
{
FutureResult<int> futures;
WHEN("adding a future that resolves afterwards")
{
Promise<int> 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<int> promise;
promise.set_value(42);
futures.set(promise.get_future());
REQUIRE(!futures.empty());
REQUIRE(futures.get() == 42);
}
}
GIVEN("a FutureResult")
{
FutureResult<void> futures;
WHEN("adding a future that resolves afterwards")
{
Promise<void> 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<void> 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

View File

@@ -0,0 +1,23 @@
// TJP COPYRIGHT HEADER
#include <tjp/core/future/PromiseLocked.hpp>
namespace tjp {
namespace core {
namespace {
static void futures_promise_locked_test ()
{
PromiseLocked<int> pi;
pi.consume(future_of_value((int)1));
pi.consume([]() { return (int)1; });
PromiseLocked<void> pv;
pv.consume(future_of_value());
pv.consume([]() {});
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,124 @@
// TJP COPYRIGHT HEADER
#include <tjp/core/future/PromiseOfFutures.hpp>
#include <tjp/core/iterators/range.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/timer/Timer.hpp>
namespace tjp {
namespace core {
namespace futures {
namespace promise_of_futures_test {
SCENARIO("promise of future" )
{
GIVEN("a void promise")
{
auto promise = PromiseOfFutures<void>::generate();
WHEN("no futures")
{
auto future = promise->get_future();
future.wait();
REQUIRE(true);
}
WHEN("one future")
{
Promise<void> 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<void> 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<int> a;
Promise<std::string> 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

View File

@@ -0,0 +1,48 @@
// TJP COPYRIGHT HEADER
#include <tjp/core/future/after.hpp>
#include <tjp/core/testing/catch.hpp>
namespace tjp {
namespace core {
SCENARIO("after a future")
{
GIVEN("two promises")
{
Promise<int> 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

43
tjp/core/future/after.hpp Executable file
View File

@@ -0,0 +1,43 @@
// TJP COPYRIGHT HEADER
#pragma once
#include "Future.hpp"
#include "weak_future_consume.hpp"
#include <utility>
namespace tjp {
namespace core {
template<typename F0, typename FutureGenerator>
auto after(F0 &&f0, FutureGenerator &&next)
{
typedef decltype(f0.get()) R0;
typedef decltype(next(f0)) F1_Ref;
typedef typename std::remove_reference<F1_Ref>::type F1;
typedef decltype(std::declval<F1>().get()) R1_Ref;
typedef typename std::remove_reference<R1_Ref>::type R1;
Promise<R1> 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

17
tjp/core/future/after_using.hpp Executable file
View File

@@ -0,0 +1,17 @@
// TJP COPYRIGHT HEADER
#pragma once
#include "after.hpp"
namespace tjp::core {
template<typename F0, typename FutureGenerator>
auto after_using(F0 &&f0, FutureGenerator &&next)
{
return after(f0, [next = std::move(next)](auto &&f) {
return next(f.get());
});
}
} // namespace

23
tjp/core/future/boost/Future.h Executable file
View File

@@ -0,0 +1,23 @@
// TJP COPYRIGHT HEADER
#pragma once
#define BOOST_THREAD_PROVIDES_FUTURE
#define BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION
#include <boost/thread.hpp>
#include <boost/thread/future.hpp>
#include <functional>
namespace tjp {
namespace core {
template<typename T>
using Future = boost::future<T>;
template<typename T>
using Promise = boost::promise<T>;
} // namespace
} // namespace

View File

@@ -0,0 +1,28 @@
// TJP COPYRIGHT HEADER
#include "Future.hpp"
namespace tjp {
namespace core {
namespace futures {
namespace detail {
//typedef std::list<Cancelable *> Stack;
//ThreadSpecificSingleton<Stack> stack;
//CancelFrame::CancelFrame(Cancelable *c)
//{
// stack->push_back(c);
//}
//CancelFrame::~CancelFrame()
//{
// stack->pop_back();
//}
} // namespace
} // namespace
} // namespace
} // namespace

View File

@@ -0,0 +1,6 @@
// TJP COPYRIGHT HEADER
#pragma once
#include "Future_.h"
#include "Future_void.h"

View File

@@ -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"

View File

@@ -0,0 +1,69 @@
// TJP COPYRIGHT HEADER
#pragma once
namespace tjp {
namespace core {
namespace futures {
namespace detail {
template<typename T>
struct Shared;
template<typename T>
struct Shared_;
template<typename T>
struct Promise;
template<typename T>
struct Future;
struct Dependency;
struct Cancelable;
struct CancelFrame;
template<typename T>
struct Then;
template<typename T>
struct Shared_;
template<typename T>
struct Shared;
template<typename T>
struct Promise_;
template<typename T>
struct Promise;
template<typename T>
struct Future_;
template<typename T>
struct Future;
} // namespace
template<typename T>
using Promise = detail::Promise<T>;
template<typename T>
using Future = detail::Future<T>;
} // namespace
template<typename T>
using Promise = futures::Promise<T>;
template<typename T>
using Future = futures::Future<T>;
} // namespace
} // namespace

View File

@@ -0,0 +1,513 @@
// TJP COPYRIGHT HEADER
#pragma once
#include "Future_Requirements.hpp"
namespace tjp {
namespace core {
namespace futures {
namespace detail {
template<typename T>
struct Shared;
template<typename T>
struct Shared_;
template<typename T>
struct Promise;
template<typename T>
struct Future;
struct Dependency {
virtual ~Dependency() {}
} ;
#if defined(CORE_FUTURE_USE_STRONG_EXCEPTION_PTR)
using ExceptionPtr = StrongPtr<Exception>;
inline
void future_rethrow_exception(const ExceptionPtr &exception)
{
throw *exception;
}
template<typename T>
ExceptionPtr make_exception(T &&t)
{
return strong<std::decay_t<T>>(std::forward<T>(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<typename T>
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<typename T>
struct Then : Dependency
{
StrongPtr<Shared<T>> dependency;
typedef std::function<void(const StrongPtr<Shared<T>> &)> F;
F f;
Then(const StrongPtr<Shared<T>> &dependency_, F &&f_) :
dependency(dependency_),
f(std::move(f_))
{
FuturesLogDebug(tjp::core::futures::Then, logOfThis(this) << "constructor " << type_id<T>().name());
}
~Then ()
{
FuturesLogDebug(tjp::core::futures::Then, logOfThis(this) << "destructor " << type_id<T>().name());
}
void execute()
{
auto f_ = std::move(f);
f_(dependency);
}
} ;
template<typename T>
struct Shared_
{
typedef Shared_<T> Self;
StrongPtr<Dependency> 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<T>().name());
}
~Shared_ ()
{
FuturesLogDebug(tjp::core::futures::Shared_, logOfThis(this) << "destructor " << type_id<T>().name());
}
template<typename E>
void except_hasLock(E &&e)
{
debug_assert(mutex.locked_by_caller());
exception = make_exception(std::forward<E>(e));
set_notify();
}
void set_notify ()
{
FuturesLogDebug(tjp::core::futures::Shared_::set_notify, logOfThis(this) << type_id<T>().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<Self *>(this)->execute(l);
#endif
}
void raise () const
{
wait();
if (exception)
future_rethrow_exception(exception);
}
bool is_set () const
{
return isSet;
}
typedef std::list<WeakPtr<Then<T>>> Thens;
Thens thens;
template<typename R, typename F>
auto generate_then(
const StrongPtr<Shared<T>> &self,
const WeakPtr<Shared<R>> &value,
F &&f
)
{
auto then = strong<Then<T>>(
self,
[value, f=std::move(f)](const StrongPtr<Shared<T>> &t) {
if (auto value_ = strong(value))
{
Promise<R> promise(value_);
promise.consume(f, Future<T>(t));
}
}
);
return then;
}
template<typename R, typename F>
auto then(const StrongPtr<Shared<T>> &self, F &&f)
{
auto value = strong<Shared<R>>();
Future<R> future(value);
auto then__ = generate_then(self, weak(value), std::forward<F>(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<typename T>
struct Shared : Shared_<T>
{
typedef Shared_<T> Super;
Optional<T> value;
template<typename ... R>
void set(R && ... value_)
{
Event::Mutex::Lock l(Super::mutex);
value.emplace(std::forward<R>(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<typename E>
void except(E &&e)
{
Event::Mutex::Lock l(Super::mutex);
Super::except_hasLock(std::forward<E>(e));
execute(l);
}
// const T &get () const
// {
// Super::raise();
// return value;
// }
T &get ()
{
Super::raise();
return *value;
}
#ifdef FUTURES_THEN_ON_CONSTRUCT
template<typename F>
auto then(const StrongPtr<Shared<T>> &self, F &&f)
{
using R = decltype(f(Future<T>(this)));
Super::wait();
Promise<R> promise;
promise.consume(f, Future<T>(self));
return promise.get_future();
}
#else
template<typename F>
auto then(const StrongPtr<Shared<T>> &self, F &&f)
{
Event::Mutex::Lock l(Super::mutex);
using R = decltype(f(Future<T>(self)));
auto future = Super::template then<R>(self, std::forward<F>(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<T>().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<typename T>
struct Promise_
{
using shared_ptr = StrongPtr<Shared<T>>;
shared_ptr shared;
Promise_() :
shared(strong<Shared<T>>())
{
}
Promise_(const StrongPtr<Shared<T>> &shared_) : shared(shared_) {}
template<typename E>
static void set_exception(shared_ptr &shared, E &&exception)
{
shared->except(std::forward<E>(exception));
}
template<typename E>
void set_exception(E &&exception)
{
set_exception(shared, std::forward<E>(exception));
}
Future<T> get_future ()
{
return Future<T>(shared);
}
bool is_set ()
{
return shared->is_set();
}
} ;
template<typename T>
struct Promise : public Promise_<T>
{
typedef Promise_<T> Super;
using shared_ptr = typename Super::shared_ptr;
Promise() {}
Promise(const StrongPtr<Shared<T>> &value_) : Super(value_) {}
~Promise () {}
template<typename ... R>
static void set_value(shared_ptr &shared, R && ...t)
{
shared->set(std::forward<R>(t)...);
}
// static void set_value(shared_ptr &shared, const T &t)
// {
// shared->set(t);
// }
template<typename ... R>
void set_value(R && ...t)
{
set_value(Super::shared, std::forward<R>(t)...);
}
// void set_value(const T &t)
// {
// set_value(Super::shared, t);
// }
template<typename F, typename ... V>
void consume(const F &f, V && ...v)
{
auto shared_ = weak(Super::shared);
try
{
auto result = f(std::forward<V>(v)...);
if (auto shared = strong(shared_))
set_value(shared, std::forward<decltype(result)>(result));
}
CORE_FUTURE_CATCH_BEGIN(e)
{
if (auto shared = strong(shared_))
Super::set_exception(shared, e);
}
CORE_FUTURE_CATCH_END
}
template<typename F>
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<decltype(result)>(result));
}
CORE_FUTURE_CATCH_BEGIN(e)
{
if (auto shared = strong(shared_))
Super::set_exception(shared, e);
}
CORE_FUTURE_CATCH_END
}
} ;
template<typename T>
struct Future_
{
typedef T value_type;
StrongPtr<Shared<T>> shared;
Future_(const StrongPtr<Shared<T>> &shared_) : shared(shared_) {}
Future_() {}
~Future_ ()
{
FuturesLogDebug(tjp::core::futures::Future_, logOfThis(this) << " destructing " << type_id<T>().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<typename T>
struct Future : public Future_<T>
{
typedef Future_<T> Super;
typedef T value_type;
Future(const StrongPtr<Shared<T>> &promise_) : Super(promise_) {}
Future() {}
T &get ()
{
return Super::shared->get();
}
void raise() const
{
return Super::shared->raise();
}
template<typename F>
auto then(F &&f)
{
return Super::shared->then(Super::shared, std::forward<F>(f));
}
} ;
} // namespace
template<typename T>
using Promise = detail::Promise<T>;
template<typename T>
using Future = detail::Future<T>;
} // namespace
template<typename T>
using Promise = futures::Promise<T>;
template<typename T>
using Future = futures::Future<T>;
} // namespace
} // namespace

View File

@@ -0,0 +1,24 @@
// TJP COPYRIGHT HEADER
#pragma once
#ifdef TIMPREPSCIUS_CORE_STANDALONE
#include "StandaloneCore.ipp"
#else
#include <tjp/core/threads/Lock.hpp>
#include <tjp/core/exception/Exception.hpp>
#include <tjp/core/assert/debug_assert.h>
#include <tjp/core/ptr/Ptr.hpp>
#include <tjp/core/containers/Optional.hpp>
#endif
#include <queue>
#include <functional>
#include <list>
#ifdef FUTURES_ENABLE_LOG
#include "../../log/Log.h"
#define FuturesLogDebug(x,y) xLogDebug(x,y)
#else
#define FuturesLogDebug(x,y)
#endif

View File

@@ -0,0 +1,31 @@
// TJP COPYRIGHT HEADER
#pragma once
#include "Future_.h"
namespace tjp {
namespace core {
namespace futures {
namespace detail {
template<>
struct Future<void>;
template<>
struct Promise<void>;
template<>
struct Shared<void>;
template<>
struct Future<void>;
} // namespace
} // namespace
} // namespace
} // namespace

View File

@@ -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<void>;
template<>
struct Promise<void>;
template<>
struct Shared<void> : Shared_<void>
{
typedef Shared_<void> Super;
void set()
{
Event::Mutex::Lock l(Super::mutex);
Super::set_notify();
execute(l);
}
template<typename E>
void except(E &&e)
{
Event::Mutex::Lock l(Super::mutex);
Super::except_hasLock(std::forward<E>(e));
execute(l);
}
void get ()
{
Super::raise();
}
using Super::raise;
template<typename F>
auto then(const StrongPtr<Shared<void>> &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<void> : Promise_<void>
{
typedef Promise_<void> Super;
Promise() {}
Promise(const StrongPtr<Shared<void>> &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<typename F, typename ... V>
void consume(const F &f, V && ... v)
{
auto shared_ = weak(Super::shared);
try
{
f(std::forward<V>(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<typename F>
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<void> : Future_<void>
{
typedef Future_<void> Super;
Future(const StrongPtr<Shared<void>> &shared_) : Super(shared_) {}
Future() {}
void get ()
{
shared->get();
}
void raise() const
{
shared->raise();
}
template<typename F>
auto then(F &&f)
{
return Super::shared->then(Super::shared, std::forward<F>(f));
}
} ;
//------------
#ifdef FUTURES_THEN_ON_CONSTRUCT
template<typename F>
auto Shared<void>::then(const StrongPtr<Shared<void>> &self, F &&f)
{
using R = decltype(f(Future<void>(this)));
Super::wait();
Promise<R> promise;
promise.consume(f, Future<void>(self));
return promise.get_future();
}
#else
template<typename F>
auto Shared<void>::then(const StrongPtr<Shared<void>> &self, F &&f)
{
Event::Mutex::Lock l(Super::mutex);
using R = decltype(f(Future<void>(StrongPtr<Shared<void>>())));
auto future = Super::template then<R>(self, std::forward<F>(f));
if (Super::is_set())
execute(l);
return future;
}
#endif
} // namespace
} // namespace
} // namespace
} // namespace

View File

@@ -0,0 +1,394 @@
// TJP COPYRIGHT HEADER
#include <tjp/core/future/custom/Future.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/types/Types.h>
#include <tjp/core/log/Log.h>
#include <tjp/core/log/LogOf.h>
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<void> ap;
Promise<u8> bp;
Promise<u32> cp;
Promise<u64> dp;
Promise<StructX> ep;
sLogTest("testing", logVar(sizeof(ap)) << logVar(sizeof(bp)) << logVar(sizeof(cp)) << logVar(sizeof(dp)) << logVar(sizeof(ep)));
Future<void> af;
Future<u8> bf;
Future<u32> cf;
Future<u64> df;
Future<StructX> 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<void> 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<void> *p;
p = new Promise<void>();
WHEN("setting a consume")
{
auto future = p->get_future();
p->consume([&](){ delete p; p = nullptr; });
future.wait();
REQUIRE(true);
}
}
GIVEN("an integer promise")
{
Promise<int> 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<StrongPtr<int>> 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<int>(1));
auto value = future.get();
REQUIRE(value == 3);
}
}
GIVEN("a promise")
{
Promise<int> 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<int> 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

19
tjp/core/future/folly/Future.h Executable file
View File

@@ -0,0 +1,19 @@
// TJP COPYRIGHT HEADER
#pragma once
#include <folly/futures/Future.h>
namespace tjp {
namespace core {
template<typename T>
using Promise = folly:Promise<T>;
template<typename T>
using Future = folly::Future<T>;
} // namespace
} // namespace

View File

@@ -0,0 +1,30 @@
// TJP COPYRIGHT HEADER
#pragma once
#include "Future.hpp"
#include <type_traits>
namespace tjp::core {
// Non-void version
template<typename T,
typename R = std::decay_t<decltype(std::declval<T>().get())>
// typename = std::enable_if_t<!std::is_void_v<R>>
>
Optional<R> future_discard_exception(T &&f)
{
try
{
return f.get();
}
CORE_FUTURE_CATCH_BEGIN(e)
{
}
CORE_FUTURE_CATCH_END
return {};
}
} // namespace

View File

@@ -0,0 +1,27 @@
// TJP COPYRIGHT HEADER
#pragma once
#include "Future.hpp"
namespace tjp {
namespace core {
template<typename T, typename U>
Future<T> future_handle_exception(Future<T> &&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

View File

@@ -0,0 +1,25 @@
// TJP COPYRIGHT HEADER
#pragma once
#include "Future.hpp"
namespace tjp {
namespace core {
template<typename T>
bool future_is_exception(Future<T> &f)
{
try
{
f.get();
return false;
}
catch (...)
{
return true;
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,29 @@
// TJP COPYRIGHT HEADER
#pragma once
#include "Future.hpp"
#include <type_traits>
namespace tjp::core {
template<typename T, typename U,
typename R = decltype(std::declval<T>().get())
// typename = std::enable_if_t<!std::is_void_v<R>>
>
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

View File

@@ -0,0 +1,39 @@
// TJP COPYRIGHT HEADER
#pragma once
#include "Future.hpp"
#include <type_traits>
namespace tjp::core {
template<typename T, typename U,
typename R = decltype(std::declval<T>().get())
// typename = std::enable_if_t<!std::is_void_v<R>>
>
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

View File

@@ -0,0 +1,39 @@
// TJP COPYRIGHT HEADER
#pragma once
#include "Future.hpp"
#include <type_traits>
namespace tjp::core {
template<typename T, typename U,
typename R = decltype(std::declval<T>().get())
// typename = std::enable_if_t<!std::is_void_v<R>>
>
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

View File

@@ -0,0 +1,29 @@
// TJP COPYRIGHT HEADER
#pragma once
#include "Future.hpp"
#include <tjp/core/containers/Optional.hpp>
namespace tjp {
namespace core {
template<typename F>
auto future_success(F &&f)
{
typedef typename std::remove_reference<decltype(f.get())>::type R;
try
{
if (f.valid())
return Optional<R> { f.get() };
}
catch(...)
{
}
return Optional<R>{};
}
} // namespace
} // namespace

19
tjp/core/future/liblw/Future.h Executable file
View File

@@ -0,0 +1,19 @@
// TJP COPYRIGHT HEADER
#pragma once
#include <lw/event/Promise.impl.hpp>
namespace tjp {
namespace core {
template<typename T>
using Promise = lw::event::Promise<T>;
template<typename T>
using Future = lw::event::Future<T>;
} // namespace
} // namespace

View File

@@ -0,0 +1,57 @@
// TJP COPYRIGHT HEADER
#pragma once
#include <type_traits>
namespace tjp::core {
template<typename T, typename F, typename ... V>
void weak_future_consume_value(T &&shared_, F &&f, V && ... v)
{
try
{
auto result = std::forward<F>(f)(std::forward<V>(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<typename T, typename F, typename ... V>
void weak_future_consume_void(T &&shared_, F &&f, V && ... v)
{
try
{
std::forward<F>(f)(std::forward<V>(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<typename T, typename F, typename ... V>
void weak_future_consume(T &&shared_, F &&f, V && ... v)
{
using R_Ref = decltype(std::forward<F>(f)(std::forward<V>(v)...));
using R = std::remove_reference_t<R_Ref>();
if constexpr(std::is_void_v<R_Ref>)
return weak_future_consume_void(std::forward<T>(shared_), std::forward<F>(f), std::forward<V>(v)...);
else
return weak_future_consume_value(std::forward<T>(shared_), std::forward<F>(f), std::forward<V>(v)...);
}
} // namespace