flatten 20260225
This commit is contained in:
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
.DS_Store
|
||||
*.pyc
|
||||
xcuserdata
|
||||
.bin
|
||||
683
Core_Future.xcodeproj/project.pbxproj
Normal file
683
Core_Future.xcodeproj/project.pbxproj
Normal 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 */;
|
||||
}
|
||||
@@ -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 = ""Scenario: core::future::future_chain""
|
||||
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
2
Makefile
Normal file
@@ -0,0 +1,2 @@
|
||||
ROOTDIR := $(realpath $(dir $(lastword $(MAKEFILE_LIST)))..)
|
||||
include $(ROOTDIR)/Core_Make/tjp/Make/Makefile
|
||||
6
Makefile.def
Executable file
6
Makefile.def
Executable 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
19
Makefile.project
Executable 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
|
||||
2
tests/Core_Future_Tests.txt
Normal file
2
tests/Core_Future_Tests.txt
Normal 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
1
tests/Makefile
Symbolic link
@@ -0,0 +1 @@
|
||||
../../Make/Makefile
|
||||
31
tests/Makefile.project
Executable file
31
tests/Makefile.project
Executable 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
19
tests/main.cpp
Normal 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
17
tjp/core/future/Future.h
Executable 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
205
tjp/core/future/Future.hpp
Executable 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
4
tjp/core/future/FutureChain.h
Executable file
@@ -0,0 +1,4 @@
|
||||
// TJP COPYRIGHT HEADER
|
||||
|
||||
#pragma once
|
||||
|
||||
177
tjp/core/future/FutureChain.hpp
Executable file
177
tjp/core/future/FutureChain.hpp
Executable 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 ¶meter) = 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 ¶meter) override
|
||||
{
|
||||
parent = nullptr;
|
||||
|
||||
try
|
||||
{
|
||||
next = futureGenerator(copy_of(parameter)).then(
|
||||
[self_=this->self, this](auto &&f) {
|
||||
if (auto self = strong(self_))
|
||||
{
|
||||
promise.consume([](auto &&f){ return f.get(); }, std::move(f));
|
||||
executeChildren(future);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
catch (Exception &e)
|
||||
{
|
||||
promise.set_exception(copy_of(e));
|
||||
executeChildren(future);
|
||||
}
|
||||
}
|
||||
|
||||
void executeChildren(const FutureType &f)
|
||||
{
|
||||
if (auto child = strong(this->link))
|
||||
{
|
||||
executeChild(child, f);
|
||||
}
|
||||
}
|
||||
|
||||
void executeChild(const StrongPtr<Child> &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
|
||||
79
tjp/core/future/FutureErase.hpp
Normal file
79
tjp/core/future/FutureErase.hpp
Normal 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
58
tjp/core/future/FutureEvent.hpp
Executable 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
10
tjp/core/future/FutureResult.h
Executable file
@@ -0,0 +1,10 @@
|
||||
// TJP COPYRIGHT HEADER
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace tjp::core {
|
||||
|
||||
template<typename T>
|
||||
struct FutureResult;
|
||||
|
||||
} // namespace
|
||||
5
tjp/core/future/FutureResult.hpp
Executable file
5
tjp/core/future/FutureResult.hpp
Executable file
@@ -0,0 +1,5 @@
|
||||
// TJP COPYRIGHT HEADER
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "FutureResult_v1.hpp"
|
||||
157
tjp/core/future/FutureResult_v1.hpp
Executable file
157
tjp/core/future/FutureResult_v1.hpp
Executable 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
|
||||
183
tjp/core/future/FutureResult_v2.hpp
Executable file
183
tjp/core/future/FutureResult_v2.hpp
Executable 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
|
||||
49
tjp/core/future/FutureStrong.hpp
Executable file
49
tjp/core/future/FutureStrong.hpp
Executable 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
312
tjp/core/future/Futures.cpp
Executable 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
16
tjp/core/future/Futures.h
Executable 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
87
tjp/core/future/Futures.hpp
Executable 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
15
tjp/core/future/PromiseLocked.h
Executable 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
168
tjp/core/future/PromiseLocked.hpp
Executable 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
|
||||
21
tjp/core/future/PromiseOfFutures.h
Executable file
21
tjp/core/future/PromiseOfFutures.h
Executable 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
|
||||
228
tjp/core/future/PromiseOfFutures.hpp
Executable file
228
tjp/core/future/PromiseOfFutures.hpp
Executable 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
37
tjp/core/future/WeakFuture.hpp
Executable 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
12
tjp/core/future/WorkPromise.h
Executable 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
27
tjp/core/future/WorkPromise.hpp
Executable 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
|
||||
257
tjp/core/future/_tests/FutureChain.cpp
Executable file
257
tjp/core/future/_tests/FutureChain.cpp
Executable 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
|
||||
39
tjp/core/future/_tests/FutureErase.cpp
Normal file
39
tjp/core/future/_tests/FutureErase.cpp
Normal 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
|
||||
|
||||
97
tjp/core/future/_tests/FutureResult.cpp
Normal file
97
tjp/core/future/_tests/FutureResult.cpp
Normal 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
|
||||
|
||||
23
tjp/core/future/_tests/PromiseLocked.cpp
Executable file
23
tjp/core/future/_tests/PromiseLocked.cpp
Executable 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
|
||||
124
tjp/core/future/_tests/PromiseOfFutures.cpp
Executable file
124
tjp/core/future/_tests/PromiseOfFutures.cpp
Executable 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
|
||||
48
tjp/core/future/_tests/after.cpp
Executable file
48
tjp/core/future/_tests/after.cpp
Executable 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
43
tjp/core/future/after.hpp
Executable 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
17
tjp/core/future/after_using.hpp
Executable 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
23
tjp/core/future/boost/Future.h
Executable 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
|
||||
|
||||
|
||||
28
tjp/core/future/custom/Future.cpp
Executable file
28
tjp/core/future/custom/Future.cpp
Executable 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
|
||||
6
tjp/core/future/custom/Future.h
Executable file
6
tjp/core/future/custom/Future.h
Executable file
@@ -0,0 +1,6 @@
|
||||
// TJP COPYRIGHT HEADER
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Future_.h"
|
||||
#include "Future_void.h"
|
||||
14
tjp/core/future/custom/Future.hpp
Executable file
14
tjp/core/future/custom/Future.hpp
Executable 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"
|
||||
69
tjp/core/future/custom/Future_.h
Executable file
69
tjp/core/future/custom/Future_.h
Executable 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
|
||||
|
||||
|
||||
513
tjp/core/future/custom/Future_.hpp
Executable file
513
tjp/core/future/custom/Future_.hpp
Executable 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
|
||||
|
||||
|
||||
24
tjp/core/future/custom/Future_Requirements.hpp
Executable file
24
tjp/core/future/custom/Future_Requirements.hpp
Executable 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
|
||||
31
tjp/core/future/custom/Future_void.h
Executable file
31
tjp/core/future/custom/Future_void.h
Executable 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
|
||||
|
||||
|
||||
195
tjp/core/future/custom/Future_void.hpp
Executable file
195
tjp/core/future/custom/Future_void.hpp
Executable 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
|
||||
|
||||
|
||||
394
tjp/core/future/custom/_tests/Future.cpp
Executable file
394
tjp/core/future/custom/_tests/Future.cpp
Executable 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
19
tjp/core/future/folly/Future.h
Executable 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
|
||||
|
||||
|
||||
30
tjp/core/future/future_discard_exception.hpp
Executable file
30
tjp/core/future/future_discard_exception.hpp
Executable 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
|
||||
27
tjp/core/future/future_handle_exception.hpp
Executable file
27
tjp/core/future/future_handle_exception.hpp
Executable 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
|
||||
25
tjp/core/future/future_is_exception.hpp
Executable file
25
tjp/core/future/future_is_exception.hpp
Executable 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
|
||||
29
tjp/core/future/future_on_exception.hpp
Executable file
29
tjp/core/future/future_on_exception.hpp
Executable 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
|
||||
39
tjp/core/future/future_on_exception_value.hpp
Executable file
39
tjp/core/future/future_on_exception_value.hpp
Executable 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
|
||||
39
tjp/core/future/future_on_exception_what.hpp
Executable file
39
tjp/core/future/future_on_exception_what.hpp
Executable 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
|
||||
29
tjp/core/future/future_success.hpp
Executable file
29
tjp/core/future/future_success.hpp
Executable 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
19
tjp/core/future/liblw/Future.h
Executable 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
|
||||
|
||||
|
||||
57
tjp/core/future/weak_future_consume.hpp
Executable file
57
tjp/core/future/weak_future_consume.hpp
Executable 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
|
||||
Reference in New Issue
Block a user