flatten 20260225

This commit is contained in:
Timothy Prepscius
2026-02-25 12:25:20 -05:00
commit fdf8bae515
46 changed files with 2983 additions and 0 deletions

4
.gitignore vendored Normal file
View File

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

View File

@@ -0,0 +1,476 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 56;
objects = {
/* Begin PBXBuildFile section */
F65B59D92C6C53BF00059339 /* Registry.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F65B59AD2C6C511800059339 /* Registry.cpp */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
F61F9C022C6EF32D00F79137 /* Makefile.project */ = {isa = PBXFileReference; lastKnownFileType = text; path = Makefile.project; sourceTree = "<group>"; };
F61F9C032C6EF34A00F79137 /* main.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = "<group>"; };
F65B59A32C6C511800059339 /* Averaging.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Averaging.hpp; sourceTree = "<group>"; };
F65B59A42C6C511800059339 /* None.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = None.hpp; sourceTree = "<group>"; };
F65B59A62C6C511800059339 /* Data.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Data.hpp; sourceTree = "<group>"; };
F65B59A72C6C511800059339 /* Executor.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Executor.hpp; sourceTree = "<group>"; };
F65B59A82C6C511800059339 /* ExecutorManual.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ExecutorManual.hpp; sourceTree = "<group>"; };
F65B59A92C6C511800059339 /* ExecutorThreaded.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ExecutorThreaded.hpp; sourceTree = "<group>"; };
F65B59AA2C6C511800059339 /* Prunable.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Prunable.hpp; sourceTree = "<group>"; };
F65B59AB2C6C511800059339 /* Pruning.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Pruning.hpp; sourceTree = "<group>"; };
F65B59AC2C6C511800059339 /* Pruning.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Pruning.cpp; sourceTree = "<group>"; };
F65B59AD2C6C511800059339 /* Registry.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Registry.cpp; sourceTree = "<group>"; };
F65B59AE2C6C511800059339 /* Registry.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Registry.hpp; sourceTree = "<group>"; };
F65B59B02C6C511800059339 /* SizeAllocatorPool_locking.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = SizeAllocatorPool_locking.hpp; sourceTree = "<group>"; };
F65B59B22C6C511800059339 /* AllocatorBoilerPlateC++11.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "AllocatorBoilerPlateC++11.h"; sourceTree = "<group>"; };
F65B59B32C6C511800059339 /* AllocatorFunctions.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = AllocatorFunctions.hpp; sourceTree = "<group>"; };
F65B59B42C6C511800059339 /* AllocatorPool.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = AllocatorPool.hpp; sourceTree = "<group>"; };
F65B59B52C6C511800059339 /* AllocatorPool.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = AllocatorPool.cpp; sourceTree = "<group>"; };
F65B59B62C6C511800059339 /* ClassAllocatorPool.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ClassAllocatorPool.hpp; sourceTree = "<group>"; };
F65B59B72C6C511800059339 /* ClassAllocatorPool.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ClassAllocatorPool.cpp; sourceTree = "<group>"; };
F65B59B82C6C511800059339 /* IOAllocator.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = IOAllocator.hpp; sourceTree = "<group>"; };
F65B59B92C6C511800059339 /* MapAllocator.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = MapAllocator.hpp; sourceTree = "<group>"; };
F65B59BA2C6C511800059339 /* SFINAE.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = SFINAE.hpp; sourceTree = "<group>"; };
F65B59BB2C6C511800059339 /* Size.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Size.h; sourceTree = "<group>"; };
F65B59BC2C6C511800059339 /* Size.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Size.hpp; sourceTree = "<group>"; };
F65B59BD2C6C511800059339 /* SizeAllocatorPool.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = SizeAllocatorPool.hpp; sourceTree = "<group>"; };
F65B59BE2C6C511800059339 /* SizeAllocatorPool.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = SizeAllocatorPool.cpp; sourceTree = "<group>"; };
F65B59BF2C6C511800059339 /* Stack_lockfree.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Stack_lockfree.hpp; sourceTree = "<group>"; };
F65B59C02C6C511800059339 /* Stack_locking.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Stack_locking.hpp; sourceTree = "<group>"; };
F65B59C12C6C511800059339 /* Stack.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Stack.cpp; sourceTree = "<group>"; };
F65B59C22C6C511800059339 /* StackAllocatorPool.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = StackAllocatorPool.hpp; sourceTree = "<group>"; };
F65B59C32C6C511800059339 /* StackNode.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = StackNode.hpp; sourceTree = "<group>"; };
F65B59C42C6C511800059339 /* StaticAllocator.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = StaticAllocator.hpp; sourceTree = "<group>"; };
F65B59C52C6C511800059339 /* StaticAllocatorPool.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = StaticAllocatorPool.hpp; sourceTree = "<group>"; };
F65B59C62C6C511800059339 /* StaticAllocatorPoolOf.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = StaticAllocatorPoolOf.hpp; sourceTree = "<group>"; };
F65B59C72C6C511800059339 /* StrongAllocator.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = StrongAllocator.hpp; sourceTree = "<group>"; };
F65B59C82C6C511800059339 /* VectorPool.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = VectorPool.hpp; sourceTree = "<group>"; };
F65B59C92C6C511800059339 /* VectorPool.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = VectorPool.cpp; sourceTree = "<group>"; };
F65B59CC2C6C516C00059339 /* Makefile.project */ = {isa = PBXFileReference; lastKnownFileType = text; path = Makefile.project; sourceTree = "<group>"; };
F65B59CD2C6C516C00059339 /* Makefile.def */ = {isa = PBXFileReference; lastKnownFileType = text; path = Makefile.def; sourceTree = "<group>"; };
F65B59CE2C6C51A500059339 /* Precompile.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Precompile.pch; sourceTree = "<group>"; };
F65B59CF2C6C51DF00059339 /* StrongAllocator.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = StrongAllocator.hpp; sourceTree = "<group>"; };
F65B59D42C6C53A400059339 /* libCore_Allocator.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libCore_Allocator.a; sourceTree = BUILT_PRODUCTS_DIR; };
F6BF9BE12E3900B9002E6AF0 /* Makefile */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
F65B59D22C6C53A400059339 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
F61D7C3D2E381620002A1AED /* tjp */ = {
isa = PBXGroup;
children = (
F65B59CB2C6C511800059339 /* core */,
);
path = tjp;
sourceTree = "<group>";
};
F61F9BBD2C6DA69C00F79137 /* _tests */ = {
isa = PBXGroup;
children = (
F65B59C12C6C511800059339 /* Stack.cpp */,
F65B59C92C6C511800059339 /* VectorPool.cpp */,
F65B59CF2C6C51DF00059339 /* StrongAllocator.hpp */,
F65B59BE2C6C511800059339 /* SizeAllocatorPool.cpp */,
F65B59B72C6C511800059339 /* ClassAllocatorPool.cpp */,
F65B59B52C6C511800059339 /* AllocatorPool.cpp */,
);
path = _tests;
sourceTree = "<group>";
};
F61F9BFB2C6EEB4200F79137 /* _tests */ = {
isa = PBXGroup;
children = (
F65B59AC2C6C511800059339 /* Pruning.cpp */,
);
path = _tests;
sourceTree = "<group>";
};
F61F9C012C6EF32700F79137 /* tests */ = {
isa = PBXGroup;
children = (
F61F9C032C6EF34A00F79137 /* main.cpp */,
F61F9C022C6EF32D00F79137 /* Makefile.project */,
);
path = tests;
sourceTree = "<group>";
};
F65B599C2C6C50C300059339 = {
isa = PBXGroup;
children = (
F6BF9BE12E3900B9002E6AF0 /* Makefile */,
F65B59CD2C6C516C00059339 /* Makefile.def */,
F65B59CC2C6C516C00059339 /* Makefile.project */,
F65B59D52C6C53A400059339 /* Products */,
F61F9C012C6EF32700F79137 /* tests */,
F61D7C3D2E381620002A1AED /* tjp */,
);
sourceTree = "<group>";
};
F65B59A52C6C511800059339 /* algorithm */ = {
isa = PBXGroup;
children = (
F65B59A32C6C511800059339 /* Averaging.hpp */,
F65B59A42C6C511800059339 /* None.hpp */,
);
path = algorithm;
sourceTree = "<group>";
};
F65B59AF2C6C511800059339 /* prune */ = {
isa = PBXGroup;
children = (
F61F9BFB2C6EEB4200F79137 /* _tests */,
F65B59A52C6C511800059339 /* algorithm */,
F65B59A62C6C511800059339 /* Data.hpp */,
F65B59A72C6C511800059339 /* Executor.hpp */,
F65B59A82C6C511800059339 /* ExecutorManual.hpp */,
F65B59A92C6C511800059339 /* ExecutorThreaded.hpp */,
F65B59AA2C6C511800059339 /* Prunable.hpp */,
F65B59AB2C6C511800059339 /* Pruning.hpp */,
F65B59AD2C6C511800059339 /* Registry.cpp */,
F65B59AE2C6C511800059339 /* Registry.hpp */,
);
path = prune;
sourceTree = "<group>";
};
F65B59B12C6C511800059339 /* remove */ = {
isa = PBXGroup;
children = (
F65B59B02C6C511800059339 /* SizeAllocatorPool_locking.hpp */,
);
path = remove;
sourceTree = "<group>";
};
F65B59CA2C6C511800059339 /* allocator */ = {
isa = PBXGroup;
children = (
F61F9BBD2C6DA69C00F79137 /* _tests */,
F65B59AF2C6C511800059339 /* prune */,
F65B59B12C6C511800059339 /* remove */,
F65B59B22C6C511800059339 /* AllocatorBoilerPlateC++11.h */,
F65B59B32C6C511800059339 /* AllocatorFunctions.hpp */,
F65B59B42C6C511800059339 /* AllocatorPool.hpp */,
F65B59B62C6C511800059339 /* ClassAllocatorPool.hpp */,
F65B59B82C6C511800059339 /* IOAllocator.hpp */,
F65B59B92C6C511800059339 /* MapAllocator.hpp */,
F65B59BA2C6C511800059339 /* SFINAE.hpp */,
F65B59BB2C6C511800059339 /* Size.h */,
F65B59BC2C6C511800059339 /* Size.hpp */,
F65B59BD2C6C511800059339 /* SizeAllocatorPool.hpp */,
F65B59BF2C6C511800059339 /* Stack_lockfree.hpp */,
F65B59C02C6C511800059339 /* Stack_locking.hpp */,
F65B59C22C6C511800059339 /* StackAllocatorPool.hpp */,
F65B59C32C6C511800059339 /* StackNode.hpp */,
F65B59C42C6C511800059339 /* StaticAllocator.hpp */,
F65B59C52C6C511800059339 /* StaticAllocatorPool.hpp */,
F65B59C62C6C511800059339 /* StaticAllocatorPoolOf.hpp */,
F65B59C72C6C511800059339 /* StrongAllocator.hpp */,
F65B59C82C6C511800059339 /* VectorPool.hpp */,
);
path = allocator;
sourceTree = "<group>";
};
F65B59CB2C6C511800059339 /* core */ = {
isa = PBXGroup;
children = (
F65B59CE2C6C51A500059339 /* Precompile.pch */,
F65B59CA2C6C511800059339 /* allocator */,
);
path = core;
sourceTree = "<group>";
};
F65B59D52C6C53A400059339 /* Products */ = {
isa = PBXGroup;
children = (
F65B59D42C6C53A400059339 /* libCore_Allocator.a */,
);
name = Products;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
F65B59D02C6C53A400059339 /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
F65B59D32C6C53A400059339 /* Core_Allocator */ = {
isa = PBXNativeTarget;
buildConfigurationList = F65B59D62C6C53A400059339 /* Build configuration list for PBXNativeTarget "Core_Allocator" */;
buildPhases = (
F65B59D02C6C53A400059339 /* Headers */,
F65B59D12C6C53A400059339 /* Sources */,
F65B59D22C6C53A400059339 /* Frameworks */,
);
buildRules = (
);
dependencies = (
);
name = Core_Allocator;
productName = Core_Allocator;
productReference = F65B59D42C6C53A400059339 /* libCore_Allocator.a */;
productType = "com.apple.product-type.library.static";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
F65B599D2C6C50C300059339 /* Project object */ = {
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = 1;
LastUpgradeCheck = 1530;
TargetAttributes = {
F65B59D32C6C53A400059339 = {
CreatedOnToolsVersion = 15.3;
};
};
};
buildConfigurationList = F65B59A02C6C50C300059339 /* Build configuration list for PBXProject "Core_Allocator" */;
compatibilityVersion = "Xcode 14.0";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = F65B599C2C6C50C300059339;
productRefGroup = F65B59D52C6C53A400059339 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
F65B59D32C6C53A400059339 /* Core_Allocator */,
);
};
/* End PBXProject section */
/* Begin PBXSourcesBuildPhase section */
F65B59D12C6C53A400059339 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
F65B59D92C6C53BF00059339 /* Registry.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
F65B59A12C6C50C300059339 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
HEADER_SEARCH_PATHS = (
../Core_Zero,
../Core_Future,
../Libraries/sdk/Darwin/include,
);
LIBRARY_SEARCH_PATHS = "";
"LIBRARY_SEARCH_PATHS[sdk=iphoneos*][arch=arm64]" = (
"../Libraries/sdk/Darwin/lib/Debug.iOS-arm64",
"../Libraries/project/Debug.iOS-arm64",
);
"LIBRARY_SEARCH_PATHS[sdk=iphonesimulator*]" = (
"../Libraries/sdk/Darwin/lib/Debug.iOS-sim",
"../Libraries/project/Debug.iOS-sim",
);
"LIBRARY_SEARCH_PATHS[sdk=macosx*][arch=arm64]" = (
"../Libraries/sdk/Darwin/lib/Debug.Darwin-arm64",
"../Libraries/project/Debug.Darwin-arm64",
);
USE_HEADERMAP = NO;
};
name = Debug;
};
F65B59A22C6C50C300059339 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
HEADER_SEARCH_PATHS = (
../Core_Zero,
../Core_Future,
../Libraries/sdk/Darwin/include,
);
LIBRARY_SEARCH_PATHS = "";
"LIBRARY_SEARCH_PATHS[sdk=iphoneos*]" = (
"../Libraries/sdk/Darwin/lib/Release.iOS-arm64",
"../Libraries/project/Release.iOS-arm64",
);
"LIBRARY_SEARCH_PATHS[sdk=iphonesimulator*]" = (
"../Libraries/sdk/Darwin/lib/Release.iOS-sim",
"../Libraries/project/Release.iOS-sim",
);
"LIBRARY_SEARCH_PATHS[sdk=macosx*][arch=arm64]" = (
"../Libraries/sdk/Darwin/lib/Release.Darwin-arm64",
"../Libraries/project/Release.Darwin-arm64",
);
USE_HEADERMAP = NO;
};
name = Release;
};
F65B59D72C6C53A400059339 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
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;
CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = T2M28D3T75;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
EXECUTABLE_PREFIX = lib;
GCC_C_LANGUAGE_STANDARD = gnu17;
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;
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MACOSX_DEPLOYMENT_TARGET = 14.4;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = macosx;
SKIP_INSTALL = YES;
};
name = Debug;
};
F65B59D82C6C53A400059339 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
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;
CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = T2M28D3T75;
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
EXECUTABLE_PREFIX = lib;
GCC_C_LANGUAGE_STANDARD = gnu17;
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;
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MACOSX_DEPLOYMENT_TARGET = 14.4;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = macosx;
SKIP_INSTALL = YES;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
F65B59A02C6C50C300059339 /* Build configuration list for PBXProject "Core_Allocator" */ = {
isa = XCConfigurationList;
buildConfigurations = (
F65B59A12C6C50C300059339 /* Debug */,
F65B59A22C6C50C300059339 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
F65B59D62C6C53A400059339 /* Build configuration list for PBXNativeTarget "Core_Allocator" */ = {
isa = XCConfigurationList;
buildConfigurations = (
F65B59D72C6C53A400059339 /* Debug */,
F65B59D82C6C53A400059339 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = F65B599D2C6C50C300059339 /* Project object */;
}

2
Makefile Normal file
View File

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

7
Makefile.def Executable file
View File

@@ -0,0 +1,7 @@
timprepscius.core_allocator.include := -I $(dir $(realpath $(lastword $(MAKEFILE_LIST))))
timprepscius.core_allocator.link := -L $(dir $(realpath $(lastword $(MAKEFILE_LIST))))/.bin/$(OBJDIR)
timprepscius.core.include := $(timprepscius.core.include) $(timprepscius.core_allocator.include)
timprepscius.core.link := $(timprepscius.core.link) $(timprepscius.core_allocator.link)

18
Makefile.project Executable file
View File

@@ -0,0 +1,18 @@
include $(MAKEDIR)/Makefile.base
# use: ls -d core/*/ core/*/*/ | rev | cut -c 2- | rev | sed 's/$/ \\/'
PROJECTS := \
tjp/core/allocator \
tjp/core/allocator/prune \
SRC_PCH := tjp/core/Precompile.pch
INCPATH := \
$(timprepscius.libraries.cpp.include) \
$(timprepscius.core.include)
LIBFILE := libCore_Allocator.a
COPYTO := $(LIBRARIES_PROJECT)
include $(MAKEDIR)/Makefile.lib

1
tests/Makefile Symbolic link
View File

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

31
tests/Makefile.project Executable file
View File

@@ -0,0 +1,31 @@
include $(MAKEDIR)/Makefile.base
# use: ls -d core/*/ core/*/*/ | rev | cut -c 2- | rev | sed 's/$/ \\/'
PROJECTS := \
. \
../core/allocator/_tests \
../core/allocator/prune/_tests
INCPATH := \
$(timprepscius.libraries.cpp.include) \
$(timprepscius.core.include)
LDPATH := $(timprepscius.libraries.cpp.link)
LIBS := \
-lCore_Zero \
-lCore_Misc \
-lCore_Allocator \
-lz_
EXEFILE := Core_Allocator_Tests.exe
#COPYTO := $(ROOTDIR)/.bin
ifeq (Darwin,$(SYS_NAME))
LIBS += -lc++
endif
include $(MAKEDIR)/Makefile.bin

17
tests/main.cpp Executable file
View File

@@ -0,0 +1,17 @@
#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_Allocator_Tests.txt");
xLogActivateStory("testing");
xLogActivateStory("debug");
int result = Catch::Session().run( argc, argv );
return result;
}

25
tjp/core/Precompile.pch Normal file
View File

@@ -0,0 +1,25 @@
#define USE_PRECOMPILED_HEADERS
#ifdef USE_PRECOMPILED_HEADERS
#include <iostream>
#include <sstream>
#include <string>
#include <string_view>
#include <list>
#include <map>
#include <vector>
#include <mutex>
#include <shared_mutex>
#include <condition_variable>
#include <thread>
#include <algorithm>
#include <memory>
#include <functional>
#endif

View File

@@ -0,0 +1,87 @@
// TJP COPYRIGHT HEADER
template <class T>
class allocator
{
public:
using value_type = T;
// using pointer = value_type*;
// using const_pointer = typename std::pointer_traits<pointer>::template
// rebind<value_type const>;
// using void_pointer = typename std::pointer_traits<pointer>::template
// rebind<void>;
// using const_void_pointer = typename std::pointer_traits<pointer>::template
// rebind<const void>;
// using difference_type = typename std::pointer_traits<pointer>::difference_type;
// using size_type = std::make_unsigned_t<difference_type>;
// template <class U> struct rebind {typedef allocator<U> other;};
allocator() noexcept {} // not required, unless used
template <class U> allocator(allocator<U> const&) noexcept {}
value_type* // Use pointer if pointer is not a value_type*
allocate(std::size_t n)
{
return static_cast<value_type*>(::operator new (n*sizeof(value_type)));
}
void
deallocate(value_type* p, std::size_t) noexcept // Use pointer if pointer is not a value_type*
{
::operator delete(p);
}
// value_type*
// allocate(std::size_t n, const_void_pointer)
// {
// return allocate(n);
// }
// template <class U, class ...Args>
// void
// construct(U* p, Args&& ...args)
// {
// ::new(p) U(std::forward<Args>(args)...);
// }
// template <class U>
// void
// destroy(U* p) noexcept
// {
// p->~U();
// }
// std::size_t
// max_size() const noexcept
// {
// return std::numeric_limits<size_type>::max();
// }
// allocator
// select_on_container_copy_construction() const
// {
// return *this;
// }
// using propagate_on_container_copy_assignment = std::false_type;
// using propagate_on_container_move_assignment = std::false_type;
// using propagate_on_container_swap = std::false_type;
// using is_always_equal = std::is_empty<allocator>;
};
template <class T, class U>
bool
operator==(allocator<T> const&, allocator<U> const&) noexcept
{
return true;
}
template <class T, class U>
bool
operator!=(allocator<T> const& x, allocator<U> const& y) noexcept
{
return !(x == y);
}

View File

@@ -0,0 +1,32 @@
// TJP COPYRIGHT HEADER
#pragma once
#include <utility>
namespace tjp::core {
struct AllocatorFunctions
{
template<typename T>
static void construct(T *__p)
{
::new((void*)__p) T();
}
template<typename U, typename... Args>
static void construct(U* p, Args&&... args)
{
::new((void*)p) U(std::forward<Args>(args)...);
}
template<typename T>
static void destroy(T *p)
{
p->~T();
}
} ;
} // namespace

View File

@@ -0,0 +1,88 @@
// TJP COPYRIGHT HEADER
#pragma once
#include "StaticAllocatorPoolOf.hpp"
namespace tjp::core {
template<typename T>
class AllocatorPool
{
public:
typedef size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
typedef T value_type;
public:
template<typename _Tp1> struct rebind {
typedef AllocatorPool<_Tp1> other;
};
using Pool = StaticAllocatorPoolOf<T>;
Pool pool;
public:
AllocatorPool() {}
AllocatorPool (const AllocatorPool &) {}
~AllocatorPool () {}
template <class _Up>
AllocatorPool (const _Up &) { }
pointer allocate (size_t size)
{
debug_assert(size == 1);
auto t = pool.allocate();
return (pointer)t;
}
void deallocate(T *o, size_t size)
{
debug_assert(size == 1);
pool.deallocate(o);
}
void construct(pointer __p)
{
AllocatorFunctions::construct(__p);
}
template<typename U, typename... Args>
void construct(U* p, Args&&... args)
{
AllocatorFunctions::construct(p, std::forward<Args>(args)...);
}
void destroy(pointer p)
{
AllocatorFunctions::destroy(p);
}
template<typename U>
void destroy(U* p)
{
AllocatorFunctions::destroy(p);
}
} ;
template<class T, class U>
bool operator ==(const AllocatorPool<T> &lhs, const AllocatorPool<U> &rhs) noexcept
{
return true;
}
template<class T, class U>
bool operator !=(const AllocatorPool<T> &lhs, const AllocatorPool<U> &rhs) noexcept
{
return !(lhs == rhs);
}
} // namespace

View File

@@ -0,0 +1,77 @@
// TJP COPYRIGHT HEADER
#pragma once
#include "SizeAllocatorPool.hpp"
namespace tjp::core {
template<typename T>
struct ClassAllocatorPool
{
using Allocator = SizeAllocatorPool<sizeof(T), alignof(T)>;
Allocator allocator;
typedef T value_type;
template<typename _Tp1> struct rebind { typedef ClassAllocatorPool<_Tp1> other; };
template<typename ...Args>
ClassAllocatorPool(Args&& ...args) {}
T *allocate ()
{
return (T *)allocator.allocate();
}
void deallocate (T *t)
{
return allocator.deallocate(t);
}
auto &getSize()
{
return allocator.getSize();
}
void prune ()
{
allocator.prune();
}
};
template<typename T>
struct ClassAllocatorPoolPartitioned
{
SizeAllocatorPool<sizeof(T), alignof(T), T> allocator;
typedef T value_type;
template<typename _Tp1> struct rebind { typedef ClassAllocatorPoolPartitioned<_Tp1> other; };
template<typename ...Args>
ClassAllocatorPoolPartitioned(Args&& ...args) {}
T *allocate ()
{
return (T *)allocator.allocate();
}
void deallocate (T *t)
{
return allocator.deallocate(t);
}
auto &getSize()
{
return allocator.getSize();
}
void prune ()
{
allocator.prune();
}
};
} // namespace

View File

@@ -0,0 +1,18 @@
// TJP COPYRIGHT HEADER
#pragma once
#include "StrongAllocator.hpp"
namespace tjp::core::allocators {
struct IOAllocator : StrongAllocator
{
template<typename IO, typename T>
void allocate(IO &io, StrongPtr<T> &t)
{
t = this->strong<T>();
}
} ;
} // namespace

View File

@@ -0,0 +1,14 @@
// TJP COPYRIGHT HEADER
#pragma once
#include "AllocatorPool.hpp"
namespace tjp::core {
template<typename K, typename V>
using MapAllocator = AllocatorPool<std::pair<const K, V>>;
} // namespace

View File

@@ -0,0 +1,59 @@
// TJP COPYRIGHT HEADER
#pragma once
#include <tjp/core/sfinae/if_or.hpp>
namespace tjp::core::allocators {
template <typename T>
class has_allocator
{
typedef char yes;
struct no {char x[2];};
template<typename C> static yes test(typename C::Allocator*);
template<typename C> static no test(...);
public:
enum { value = sizeof(test<T>(0)) == sizeof (char)};
};
// This should use invocable, but I haven't figured it out yet
template<typename T> struct is_strong_allocator : std::false_type {};
template <typename T>
class has_strong_allocator_flag
{
typedef char yes;
struct no { char x[2];};
template<typename C> static yes test(typename C::is_strong_allocator*);
template<typename C> static no test(...);
public:
enum { value = sizeof(test<T>(0)) == sizeof (char)};
};
template <
typename T,
typename T2=void
// typename std::enable_if<!has_allocator<T>::value, char>::type
>
struct has_strong_allocator {
enum { value = false };
};
template<typename T>
struct has_strong_allocator<
T,
typename std::enable_if<has_allocator<T>::value>::type
>
{
typedef typename sfinae::if_or<
has_strong_allocator_flag<typename T::Allocator>::value,
std::true_type,
std::false_type>::type type;
public:
static constexpr bool value = type::value;
};
} // namespace

11
tjp/core/allocator/Size.h Executable file
View File

@@ -0,0 +1,11 @@
// TJP COPYRIGHT HEADER
#pragma once
namespace tjp::core::allocator_pool {
struct Size;
} // namespace

16
tjp/core/allocator/Size.hpp Executable file
View File

@@ -0,0 +1,16 @@
// TJP COPYRIGHT HEADER
#pragma once
#include <tjp/core/threads/Atomic.hpp>
namespace tjp::core::allocator_pool {
struct Size {
Atomic<size_t> used = 0;
Atomic<size_t> freed = 0;
} ;
} // namespace

View File

@@ -0,0 +1,45 @@
// TJP COPYRIGHT HEADER
#pragma once
#include "Stack_locking.hpp"
#include "Stack_lockfree.hpp"
#include "StackAllocatorPool.hpp"
#include <tjp/core/threads/SpinMutex.hpp>
namespace tjp::core {
template<size_t size, size_t alignment, typename C=void>
using SizeAllocatorPool_lockfree =
allocator_pool::StackAllocatorPool<
allocator_pool::Stack_lockfree<
allocator_pool::Allocation<size, alignment>
>,
C
>;
template<size_t size, size_t alignment, typename C=void>
using SizeAllocatorPool_locking =
allocator_pool::StackAllocatorPool<
allocator_pool::Stack_locking<
allocator_pool::Allocation<size, alignment>
>,
C
>;
template<size_t size, size_t alignment, typename C=void>
using SizeAllocatorPool_locking_spinlock =
allocator_pool::StackAllocatorPool<
allocator_pool::Stack_locking<
allocator_pool::Allocation<size, alignment>,
SpinMutex
>,
C
>;
template<size_t size, size_t alignment, typename C=void>
using SizeAllocatorPool = SizeAllocatorPool_locking_spinlock<size, alignment, C>;
} // namespace

View File

@@ -0,0 +1,160 @@
// TJP COPYRIGHT HEADER
#pragma once
#include <tjp/core/threads/Lock.hpp>
#include <tjp/core/threads/Atomic.hpp>
#include <tjp/core/debug/Debug.h>
#include "Size.hpp"
namespace tjp::core::allocator_pool {
template<size_t size_, size_t alignment_>
struct Allocation
{
static constexpr size_t size = size_;
static constexpr size_t alignment = alignment_;
char t[size_];
} __attribute__ ((aligned(alignment_)));
template<typename T, typename C=void>
class StackAllocatorPool_Real
{
private:
using Stack = T;
using Node = typename T::node_type;
Stack stack;
Size size;
public:
using value_type = void;
public:
~StackAllocatorPool_Real ()
{
while (!stack.empty())
prune();
}
void *allocate ()
{
auto node = stack.pop();
if (node)
{
size.freed--;
}
else
{
node = new Node();
}
size.used++;
return &node->t;
}
void deallocate(void *v)
{
if (!v)
return;
static_assert(offsetof(Node, t) == 0);
constexpr size_t offset_t = offsetof(Node, t);
Node *node;
if constexpr(offset_t == 0)
node = (Node *)v;
else
node = (Node *)((char *)v - offset_t);
stack.push(node);
size.used--;
size.freed++;
}
const Size &getSize ()
{
return size;
}
void prune()
{
auto node = stack.pop();
if (node)
{
delete node;
size.freed--;
}
}
} ;
template<typename T=void>
struct StackAllocatorPool_Fake_Debug_Variables_ {
static bool use_real_pool;
} ;
template<typename T>
bool StackAllocatorPool_Fake_Debug_Variables_<T>::use_real_pool = false;
using StackAllocatorPool_Fake_Debug_Variables = StackAllocatorPool_Fake_Debug_Variables_<void>;
template<typename T_, typename C=void>
struct StackAllocatorPool_Fake
{
using T = T_;
Size size;
using value_type = void;
using RealPool = StackAllocatorPool_Real<T_, C>;
RealPool pool;
void *allocate ()
{
if (StackAllocatorPool_Fake_Debug_Variables::use_real_pool)
return pool.allocate();
size.used += T::Type::size;
auto alignment = T::Type::alignment;
(void)alignment;
auto size = T::Type::size;
auto result = malloc(size);
// auto result = std::aligned_alloc(alignment, size);
debug_assert(result);
return result;
}
void deallocate(void *v)
{
if (StackAllocatorPool_Fake_Debug_Variables::use_real_pool)
return pool.deallocate(v);
std::free(v);
size.used -= T::Type::size;
}
const Size &getSize ()
{
return size;
}
void prune()
{
}
} ;
template<typename T, typename C=void>
using StackAllocatorPool = StackAllocatorPool_Fake<T, C>;
//template<typename T, typename C=void>
//using StackAllocatorPool = StackAllocatorPool_Real<T, C>;
} // namespace

View File

@@ -0,0 +1,26 @@
// TJP COPYRIGHT HEADER
#pragma once
#include <tjp/core/threads/Atomic.hpp>
namespace tjp::core::allocator_pool {
template<typename T>
struct StackNode {
using value_type = T;
T t;
StackNode *next;
} ;
template<>
struct StackNode<void> {
using value_type = void;
StackNode *next;
} ;
} // namespace

View File

@@ -0,0 +1,81 @@
// TJP COPYRIGHT HEADER
#pragma once
#include <tjp/core/assert/debug_assert.h>
#include <tjp/core/threads/Atomic.hpp>
#include "StackNode.hpp"
namespace tjp::core::allocator_pool {
template<typename T>
class Stack_lockfree
{
public:
using Type = T;
using Node = StackNode<T>;
using node_type = Node;
private:
Atomic<Node *> head = nullptr;
public:
Node *pop()
{
// this method DOES NOT WORK
// because:
// thread A:
// next = top->next (Y)
// thread B:
// X = pop top, Y = pop top
// push X
// thread A:
// exchange pop X
// now top == Y, even though Y is not there
// there has to be a double test, for instance, is(top == head and top->next still equal to next)
debug_assert(false);
Node *top = head.load();
while (top != nullptr)
{
Node *next = top->next;
if (head.compare_exchange_weak(top, next))
break;
}
return top;
}
void push(Node *node)
{
Node *expected_head = head.load();
do
{
node->next = expected_head;
}
while(!head.compare_exchange_weak(expected_head, node));
}
bool empty() const
{
return head == nullptr;
}
size_t size_not_thread_safe() const
{
size_t result = 0;
Node *node = head;
while (node)
{
result++;
node = node->next;
}
return result;
}
} ;
} // namespace

View File

@@ -0,0 +1,65 @@
// TJP COPYRIGHT HEADER
#pragma once
#include <tjp/core/threads/Lock.hpp>
#include "StackNode.hpp"
namespace tjp::core::allocator_pool {
template<typename T, typename M=Mutex>
class Stack_locking
{
public:
using Type = T;
using Node = StackNode<T>;
using node_type = Node;
using mutex_type = M;
private:
mutable M mutex;
Node *head = nullptr;
public:
Node *pop()
{
auto lock = lock_of(mutex);
auto *a = head;
if (a != nullptr)
head = a->next;
return a;
}
void push(Node *a)
{
auto lock = lock_of(mutex);
a->next = head;
head = a;
}
bool empty() const
{
auto lock = lock_of(mutex);
return head == nullptr;
}
size_t size_not_thread_safe() const
{
size_t result = 0;
Node *node = head;
while (node)
{
result++;
node = node->next;
}
return result;
}
} ;
} // namespace

View File

@@ -0,0 +1,19 @@
// TJP COPYRIGHT HEADER
#pragma once
namespace tjp::core {
template<typename T>
class StaticAllocator
{
public:
typedef T Allocator;
static Allocator allocator;
} ;
template<typename T> typename StaticAllocator<T>::Allocator StaticAllocator<T>::allocator;
} // namespace

View File

@@ -0,0 +1,37 @@
// TJP COPYRIGHT HEADER
#pragma once
namespace tjp {
namespace core {
template<typename T>
class StaticAllocatorPool
{
public:
typedef T Allocator;
static Allocator allocator;
static auto allocate ()
{
return allocator.allocate();
}
template<typename U>
static void deallocate(U *o)
{
allocator.deallocate(o);
}
static void prune()
{
allocator.prune();
}
} ;
template<typename T> typename StaticAllocatorPool<T>::Allocator StaticAllocatorPool<T>::allocator;
} // namespace
} // namespace

View File

@@ -0,0 +1,70 @@
// TJP COPYRIGHT HEADER
#pragma once
#include "StaticAllocatorPool.hpp"
#include "AllocatorFunctions.hpp"
#include "SizeAllocatorPool.hpp"
#include "prune/Pruning.hpp"
namespace tjp::core {
template<size_t size, size_t alignment, typename C=void>
struct StaticAllocatorPoolOf_ {
using SizeAllocator = SizeAllocatorPool<size, alignment, C>;
using Allocator = allocator_pool::prune::Pruning<SizeAllocator>;
static Allocator allocator;
static auto allocate ()
{
return allocator.allocate();
}
template<typename U>
static void deallocate(U *o)
{
allocator.deallocate(o);
}
static void prune()
{
allocator.prune();
}
} ;
template<size_t size, size_t alignment, typename C> typename
StaticAllocatorPoolOf_<size, alignment, C>::Allocator StaticAllocatorPoolOf_<size, alignment, C>::allocator;
template<typename T>
class StaticAllocatorPoolOf
{
public:
using Allocator = StaticAllocatorPoolOf_<sizeof(T), alignof(T)>;
Allocator allocator;
using value_type = T;
auto allocate ()
{
return (T *)allocator.allocate();
}
template<typename U>
void deallocate(U *o)
{
allocator.deallocate(o);
}
void prune()
{
allocator.prune();
}
} ;
} // namespace

View File

@@ -0,0 +1,25 @@
// TJP COPYRIGHT HEADER
#pragma once
#include "AllocatorPool.hpp"
#include <tjp/core/ptr/Ptr.hpp>
namespace tjp::core::allocators {
struct StrongAllocator
{
typedef void is_strong_allocator;
template<typename T, typename ... Args>
auto strong(Args && ...args)
{
return strong_with_allocator<T>(
core::AllocatorPool<T>(),
std::forward<Args>(args)...
);
}
} ;
} // namespace

159
tjp/core/allocator/VectorPool.hpp Executable file
View File

@@ -0,0 +1,159 @@
// TJP COPYRIGHT HEADER
#pragma once
#include <vector>
#include "../allocator/StaticAllocator.hpp"
#include "../allocator/SizeAllocatorPool.hpp"
#include <tjp/core/log/Log.h>
#include <tjp/core/log/LogOf.h>
namespace tjp::core {
namespace vectorpool {
//https://stackoverflow.com/questions/994593/how-to-do-an-integer-log2-in-c
inline
int uint64_log2(uint64_t n)
{
#define S(k) if (n >= (UINT64_C(1) << k)) { i += k; n >>= k; }
int i = -(n == 0); S(32); S(16); S(8); S(4); S(2); S(1); return i;
#undef S
}
inline
int scale(uint64_t n)
{
return n ?
uint64_log2(n-1)+2 :
0;
}
inline
constexpr size_t unscale(int n)
{
return n ?
1 << (n-1) :
0;
}
template<typename T>
constexpr size_t unscale(int n)
{
return unscale(n) * sizeof(T);
}
template <typename T, typename DefaultAllocator=std::allocator<T>>
class Allocator {
public:
// The type definitions required for an allocator
using value_type = T;
using pointer = value_type*;
using const_pointer =
typename std::pointer_traits<pointer>::template
rebind<value_type const>;
using void_pointer =
typename std::pointer_traits<pointer>::template
rebind<void>;
using const_void_pointer =
typename std::pointer_traits<pointer>::template
rebind<const void>;
using difference_type = typename std::pointer_traits<pointer>::difference_type;
using size_type = std::make_unsigned_t<difference_type>;
using propagate_on_container_move_assignment = std::true_type;
[[no_unique_address]]
DefaultAllocator defaultAllocator;
// Default constructor (no state to maintain in this basic example)
Allocator() noexcept {}
// Allocate memory for n objects of type T
T* allocate(std::size_t n)
{
auto s = scale(n);
sLogDebug("core::vectorpool", logVar(n) << logVar(s) << logVar(unscale(s)) << logVar(unscale<T>(s)));
void *result = nullptr;
switch(s) {
case 0: result = nullptr;
break;
case 1: result = StaticAllocator<SizeAllocatorPool<unscale<T>(1),alignof(T)>>::allocator.allocate();
break;
case 2: result = StaticAllocator<SizeAllocatorPool<unscale<T>(2),alignof(T)>>::allocator.allocate();
break;
case 3: result = StaticAllocator<SizeAllocatorPool<unscale<T>(3),alignof(T)>>::allocator.allocate();
break;
case 4: result = StaticAllocator<SizeAllocatorPool<unscale<T>(4),alignof(T)>>::allocator.allocate();
break;
default: result = defaultAllocator.allocate(n);
}
return static_cast<T *>(result);
}
// Deallocate memory for n objects of type T
void deallocate(T* p, std::size_t n)
{
auto s = scale(n);
sLogDebug("core::vectorpool", logVar(n) << logVar(s) << logVar(unscale(s)) << logVar(unscale<T>(s)));
switch(s) {
case 0: return;
case 1: return StaticAllocator<SizeAllocatorPool<unscale<T>(1),alignof(T)>>::allocator.deallocate(p);
case 2: return StaticAllocator<SizeAllocatorPool<unscale<T>(2),alignof(T)>>::allocator.deallocate(p);
case 3: return StaticAllocator<SizeAllocatorPool<unscale<T>(3),alignof(T)>>::allocator.deallocate(p);
case 4: return StaticAllocator<SizeAllocatorPool<unscale<T>(4),alignof(T)>>::allocator.deallocate(p);
default: return defaultAllocator.deallocate(p, n);
}
}
// Copy constructor (not strictly needed for std::vector)
template <typename U>
Allocator(const Allocator<U>&) noexcept {}
// Move constructor (not strictly needed for std::vector)
template <typename U>
Allocator(Allocator<U>&&) noexcept {}
// Copy assignment (not strictly needed for std::vector)
template <typename U>
Allocator& operator=(const Allocator<U>&) noexcept { return *this; }
// Move assignment (not strictly needed for std::vector)
template <typename U>
Allocator& operator=(Allocator<U>&&) noexcept { return *this; }
};
template<class T, class U, class V, class W>
bool operator ==(const Allocator<T, U> &lhs, const Allocator<V, W> &rhs) noexcept
{
return true;
}
template<class T, class U, class V, class W>
bool operator !=(const Allocator<T, U> &lhs, const Allocator<V, W> &rhs) noexcept
{
return !(lhs == rhs);
}
} // namespace
template <typename T, typename DefaultAllocator=std::allocator<T>>
using VectorPool = vectorpool::Allocator<T,DefaultAllocator>;
} // namespace

View File

@@ -0,0 +1,23 @@
// TJP COPYRIGHT HEADER
#include <tjp/core/allocator/AllocatorPool.hpp>
#include <tjp/core/testing/catch.hpp>
namespace tjp::core {
namespace {
SCENARIO("core::allocator")
{
GIVEN("two allocators")
{
AllocatorPool<char> a;
AllocatorPool<int> b;
REQUIRE(a == b);
REQUIRE((a != b) == false);
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,72 @@
// TJP COPYRIGHT HEADER
#include <tjp/core/allocator/ClassAllocatorPool.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/iterators/range.hpp>
#include <tjp/core/algorithm/unused.hpp>
#include <tjp/core/containers/Set.hpp>
namespace tjp::core::allocator {
namespace {
SCENARIO("ClassAllocatorPool")
{
GIVEN("allocator")
{
ClassAllocatorPool<int> p;
auto num = 10;
std::set<int *> a0;
for (auto i : range(num))
{
unused(i);
int *a = p.allocate();
a0.insert(a);
}
REQUIRE(p.getSize().freed == 0);
REQUIRE(p.getSize().used == num);
for (auto *a : a0)
p.deallocate(a);
REQUIRE(p.getSize().freed == num);
REQUIRE(p.getSize().used == 0);
std::set<int *> a1;
for (auto i : range(num))
{
unused(i);
int *a = p.allocate();
a1.insert(a);
}
REQUIRE(p.getSize().freed == 0);
REQUIRE(p.getSize().used == num);
REQUIRE(a0 == a1);
for (auto *a : a1)
p.deallocate(a);
REQUIRE(p.getSize().freed == num);
REQUIRE(p.getSize().used == 0);
for (auto i : range(num))
{
p.prune();
}
REQUIRE(p.getSize().freed == 0);
REQUIRE(p.getSize().used == 0);
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,150 @@
// TJP COPYRIGHT HEADER
#include <tjp/core/allocator/SizeAllocatorPool.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/testing/NO_WHEN.h>
#include <tjp/core/iterators/range.hpp>
#include <tjp/core/containers/Set.hpp>
#include <tjp/core/algorithm/unused.hpp>
#include <tjp/core/containers/Vector.hpp>
namespace tjp::core::allocator {
namespace {
SCENARIO("SizeAllocatorPool")
{
GIVEN("allocator locking")
{
SizeAllocatorPool_locking_spinlock<1, 1> p;
WHEN("allocate a deallocate and allocate again")
{
auto num = 10;
std::set<void *> a0;
for (auto i : range(num))
{
unused(i);
a0.insert(p.allocate());
}
for (auto *a : a0)
p.deallocate(a);
Set<void *> a1;
for (auto i : range(num))
{
unused(i);
a1.insert(p.allocate());
}
REQUIRE(a0 == a1);
}
WHEN("allocate and deallocate with threads")
{
using namespace std::literals;
Vector<std::thread> threads;
auto numThreads = 128;
threads.reserve(numThreads);
auto numNodesPerThread = 2048;
const std::chrono::time_point<std::chrono::system_clock> now = std::chrono::system_clock::now();
auto future = now + 200ms;
for (auto threadID : range(numThreads))
{
threads.emplace_back(
[&]() {
std::this_thread::sleep_until(future);
for (auto i: range(numNodesPerThread))
{
auto *a = p.allocate();
if (!a)
abort();
p.deallocate(a);
}
}
);
}
for (auto &thread: threads)
thread.join();
}
}
NO_GIVEN("allocator lockfree")
{
SizeAllocatorPool_lockfree<1, 1> p;
NO_WHEN("allocate a deallocate and allocate again")
{
auto num = 10;
std::set<void *> a0;
for (auto i : range(num))
{
unused(i);
a0.insert(p.allocate());
}
for (auto *a : a0)
p.deallocate(a);
Set<void *> a1;
for (auto i : range(num))
{
unused(i);
a1.insert(p.allocate());
}
REQUIRE(a0 == a1);
}
WHEN("allocate and deallocate with threads")
{
using namespace std::literals;
Vector<std::thread> threads;
auto numThreads = 128;
threads.reserve(numThreads);
auto numNodesPerThread = 2048;
const std::chrono::time_point<std::chrono::system_clock> now = std::chrono::system_clock::now();
auto future = now + 200ms;
for (auto threadID : range(numThreads))
{
threads.emplace_back(
[&]() {
std::this_thread::sleep_until(future);
for (auto i: range(numNodesPerThread))
{
auto *a = p.allocate();
if (!a)
abort();
p.deallocate(a);
}
}
);
}
for (auto &thread: threads)
thread.join();
}
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,207 @@
// TJP COPYRIGHT HEADER
#include <tjp/core/allocator/SizeAllocatorPool.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/testing/NO_WHEN.h>
#include <tjp/core/iterators/range.hpp>
#include <tjp/core/containers/Set.hpp>
#include <tjp/core/algorithm/unused.hpp>
#include <tjp/core/containers/Vector.hpp>
namespace tjp::core::allocator_pool {
namespace {
SCENARIO("allocator_pool::Stack")
{
GIVEN("locking")
{
using Stack = Stack_locking<void>;
using Node = Stack::node_type;
Stack p;
WHEN("allocate and deallocate with threads")
{
using namespace std::literals;
Vector<std::thread> threads;
threads.reserve(128);
const std::chrono::time_point<std::chrono::system_clock> now = std::chrono::system_clock::now();
auto futurePush = now + 200ms;
auto numThreads = 512;
auto numNodesPerThread = 1024;
auto totalNodes = numThreads * numNodesPerThread;
Vector<Node> memory(totalNodes);
Atomic<size_t> numPushed = 0;
for (auto threadID : range(numThreads))
{
threads.emplace_back(
[&, id=threadID]() {
Node *nodes = memory.data() + (id * numNodesPerThread);
std::this_thread::sleep_until(futurePush);
for (auto i: range(numNodesPerThread))
{
p.push(&nodes[i]);
numPushed++;
}
}
);
}
for (auto &thread: threads)
thread.join();
threads.clear();
auto size = p.size_not_thread_safe();
REQUIRE(numPushed == size);
REQUIRE(size == totalNodes);
WHEN("the nodes are popped")
{
const std::chrono::time_point<std::chrono::system_clock> now = std::chrono::system_clock::now();
auto futurePop = now + 200ms;
Atomic<size_t> numPopped = 0;
Vector<Node *> popped(totalNodes);
for (auto threadID : range(numThreads))
{
threads.emplace_back(
[&, id=threadID]() {
Node **popped_ = popped.data () + (id * numNodesPerThread);
std::this_thread::sleep_until(futurePop);
for (auto i : range(numNodesPerThread))
{
popped_[i] = p.pop();
numPopped++;
}
}
);
}
for (auto &thread: threads)
thread.join();
threads.clear();
auto size = p.size_not_thread_safe();
REQUIRE(numPopped == totalNodes);
REQUIRE(size == 0);
THEN("the number of unique nodes matches")
{
Set<Node *> unique(popped.begin(), popped.end());
REQUIRE(unique.size() == totalNodes);
}
}
}
}
NO_GIVEN("allocator lockfree")
{
using Stack = Stack_lockfree<void>;
using Node = Stack::node_type;
Stack p;
WHEN("allocate and deallocate with threads")
{
using namespace std::literals;
Vector<std::thread> threads;
threads.reserve(128);
const std::chrono::time_point<std::chrono::system_clock> now = std::chrono::system_clock::now();
auto futurePush = now + 200ms;
auto numThreads = 512;
auto numNodesPerThread = 1024;
auto totalNodes = numThreads * numNodesPerThread;
Vector<Node> memory(totalNodes);
Atomic<size_t> numPushed = 0;
for (auto threadID : range(numThreads))
{
threads.emplace_back(
[&, id=threadID]() {
Node *nodes = memory.data() + (id * numNodesPerThread);
std::this_thread::sleep_until(futurePush);
for (auto i: range(numNodesPerThread))
{
p.push(&nodes[i]);
numPushed++;
}
}
);
}
for (auto &thread: threads)
thread.join();
threads.clear();
auto size = p.size_not_thread_safe();
REQUIRE(numPushed == size);
REQUIRE(size == totalNodes);
WHEN("the nodes are popped")
{
const std::chrono::time_point<std::chrono::system_clock> now = std::chrono::system_clock::now();
auto futurePop = now + 200ms;
Atomic<size_t> numPopped = 0;
Vector<Node *> popped(totalNodes);
for (auto threadID : range(numThreads))
{
threads.emplace_back(
[&, id=threadID]() {
Node **popped_ = popped.data () + (id * numNodesPerThread);
std::this_thread::sleep_until(futurePop);
for (auto i : range(numNodesPerThread))
{
popped_[i] = p.pop();
numPopped++;
}
}
);
}
for (auto &thread: threads)
thread.join();
threads.clear();
auto size = p.size_not_thread_safe();
REQUIRE(numPopped == totalNodes);
REQUIRE(size == 0);
THEN("the number of unique nodes matches")
{
Set<Node *> unique(popped.begin(), popped.end());
REQUIRE(unique.size() == totalNodes);
}
}
}
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,179 @@
// TJP COPYRIGHT HEADER
#include <tjp/core/ptr/Ptr.hpp>
#include <tjp/core/ptr/Ptr+IO.h>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/testing/NO_WHEN.h>
//#include "std/CustomControlBlock.h"
#include <tjp/core/allocator/StrongAllocator.hpp>
namespace tjp::core::allocator {
namespace {
struct A
{
int i;
~A ()
{
i = 2;
}
} ;
struct B
{
static int allocations;
int x = 5;
B () {
allocations++;
}
~B () {
allocations--;
}
};
int B::allocations = 0;
int num_c_deallocations = 0;
int num_c_destroys = 0;
struct C
{
int x= 5;
~C ()
{
num_c_destroys++;
x = 2;
}
} ;
void on_deallocate(C *p)
{
num_c_deallocations++;
}
struct CustomDeleter : StrongThis<CustomDeleter>
{
int called = 0;
template<typename T>
void deallocate(T *t)
{
called++;
delete t;
}
} ;
SCENARIO("core::allocator::ptr")
{
GIVEN("a ptr to normal")
{
WHEN("a ptr is created normal")
{
B::allocations = 0;
auto ptr = strong<B>();
REQUIRE(B::allocations == 1);
ptr = nullptr;
REQUIRE(B::allocations == 0);
}
}
GIVEN("a ptr")
{
WHEN("a ptr is created normal")
{
num_c_deallocations = num_c_destroys = 0;
auto ptr = strong<C>();
ptr = nullptr;
REQUIRE(num_c_deallocations == 1);
REQUIRE(num_c_destroys == 1);
}
WHEN("a ptr is created with a custom deleter")
{
CustomDeleter deleter;
num_c_deallocations = num_c_destroys = 0;
auto ptr = strong_with_delete<C>(
new C(), [&](C *t) { deleter.deallocate(t); }
);
ptr = nullptr;
REQUIRE(num_c_deallocations == 1);
REQUIRE(num_c_destroys == 1);
REQUIRE(deleter.called == 1);
}
WHEN("create a pointer with custom allcoator")
{
typedef AllocatorPool<C> Allocator;
num_c_deallocations = num_c_destroys = 0;
auto ptr = strong_with_allocator<C>(Allocator());
ptr = nullptr;
REQUIRE(num_c_deallocations == 1);
REQUIRE(num_c_destroys == 1);
}
}
GIVEN("a ptr with a custom deleter")
{
CustomDeleter deleter;
WHEN("create a pointer")
{
auto a = strong_with_delete<A>(
new A(), [&](A *t) { deleter.deallocate(t); }
);
WHEN("transfer the pointer elsewherez")
{
auto b = a;
a = nullptr;
WHEN("nullify the pointer")
{
b = nullptr;
REQUIRE(deleter.called == 1);
}
}
}
}
GIVEN("a ptr with an allocator")
{
WHEN("create a pointer")
{
typedef AllocatorPool<A> Allocator;
auto a = strong_with_allocator<A>(Allocator());
WHEN("transfer the pointer elsewherez")
{
auto b = a;
a = nullptr;
WHEN("nullify the pointer")
{
b = nullptr;
}
}
}
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,55 @@
// TJP COPYRIGHT HEADER
#include <tjp/core/allocator/VectorPool.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/iterators/range.hpp>
#include <list>
#include <tjp/core/log/Log.h>
#include <tjp/core/log/LogOf.h>
namespace tjp::core::vectorpool {
namespace {
template<typename T>
using MyVector = std::vector<T, Allocator<T>>;
SCENARIO("vectorpool" )
{
xLogActivateStory("core::vectorpool");
MyVector<int> myVec;
GIVEN("scales")
{
for (int i = 0; i < 256; ++i) {
sLogTest("testing", logVar(i) << logVar(scale(i)) << logVar(unscale(scale(i))));
auto s = scale(i);
auto u = unscale(s);
// REQUIRE(u >= i);
}
}
GIVEN("some numbers")
{
for (int i = 0; i < 1024; ++i) {
myVec.push_back(i);
}
sLogDebug("testing", logVar(myVec));
}
GIVEN("a move")
{
MyVector<int> b;
b = std::move(myVec);
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,20 @@
/**
* legal header
*/
#pragma once
#include <tjp/core/types/Types.h>
namespace tjp::core::allocator_pool {
namespace prune {
struct Data
{
size_t id = 0;
} ;
} // namespace
} // namespace

View File

@@ -0,0 +1,20 @@
/**
* legal header
*/
#pragma once
namespace tjp::core::allocator_pool::prune {
struct Registry;
struct Executor
{
virtual ~Executor() {}
virtual void start(Registry *) {}
virtual void stop(Registry *) {}
} ;
} // namespace

View File

@@ -0,0 +1,49 @@
/**
* legal header
*/
#pragma once
#include "Registry.hpp"
#include "Executor.hpp"
#include <tjp/core/assert/debug_assert.h>
#include <thread>
namespace tjp::core::allocator_pool::prune {
template<typename T>
struct ExecutorManual : Executor
{
T algorithm;
Registry *registry = nullptr;
template<typename ...Args>
ExecutorManual(Args&& ...args) :
algorithm(std::forward<Args>(args)...)
{
}
void start(Registry *registry_) override
{
registry = registry_;
}
void stop(Registry *registry_) override
{
debug_assert(registry == registry_);
registry = nullptr;
}
void cycle ()
{
auto lock = lock_of(registry->mutex);
for (auto prunable : registry->prunables)
{
algorithm.cycle(prunable);
}
}
} ;
} // namespace

View File

@@ -0,0 +1,71 @@
/**
* legal header
*/
#pragma once
#include "Registry.hpp"
#include "Executor.hpp"
#include <tjp/core/assert/debug_assert.h>
#include <thread>
namespace tjp::core::allocator_pool::prune {
template<typename T>
struct ExecutorThreaded : Executor
{
T algorithm;
Registry *registry = nullptr;
template<typename ...Args>
ExecutorThreaded(Args&& ...args) :
algorithm(std::forward<Args>(args)...)
{
}
void start(Registry *registry_) override
{
ended = false;
registry = registry_;
executor = std::thread([this]() {
run();
});
}
void stop(Registry *registry_) override
{
ended = true;
debug_assert(registry == registry_);
registry = nullptr;
}
std::thread executor;
bool ended = false;
int delayMS = 1000;
void run()
{
while (!ended)
{
if (registry)
cycle();
std::this_thread::sleep_for(std::chrono::milliseconds(delayMS));
}
}
void cycle ()
{
auto lock = lock_of(registry->mutex);
for (auto prunable : registry->prunables)
{
algorithm.cycle(prunable);
}
}
} ;
} // namespace

View File

@@ -0,0 +1,24 @@
/**
* legal header
*/
#pragma once
#include "Data.hpp"
#include "../Size.h"
namespace tjp::core::allocator_pool {
namespace prune {
struct Prunable
{
Data *pruneData = nullptr;
virtual const Size &getSize() = 0;
virtual void prune() = 0;
} ;
} // namespace
} // namespace

View File

@@ -0,0 +1,60 @@
/**
* legal header
*/
#pragma once
#include "Prunable.hpp"
#include "Registry.hpp"
#include <tjp/core/threads/Lock.hpp>
#include <tjp/core/algorithm/vector_erase_if_value.hpp>
namespace tjp::core::allocator_pool {
namespace prune {
template<typename A>
struct Pruning : Prunable
{
A allocator;
using value_type = typename A::value_type;
template<typename _Tp1> struct rebind { typedef Pruning<_Tp1> other; };
template<typename ...Args>
Pruning(Args&& ...args) :
allocator(std::forward<Args>(args)...)
{
Registry::shared()->insert(this);
}
virtual ~Pruning()
{
Registry::shared()->erase(this);
}
value_type *allocate ()
{
return allocator.allocate();
}
template<typename U>
void deallocate (U *t)
{
return allocator.deallocate(t);
}
const Size &getSize() override
{
return allocator.getSize();
}
void prune() override
{
allocator.prune();
}
};
} // namespace
} // namespace

View File

@@ -0,0 +1,19 @@
/**
* legal header
*/
#include "Registry.hpp"
namespace tjp::core::allocator_pool {
namespace prune {
Registry *Registry::shared()
{
static Registry *registry = new Registry();
return registry;
}
} // namespace
} // namespace

View File

@@ -0,0 +1,52 @@
/**
* legal header
*/
#pragma once
#include "Prunable.hpp"
#include "Executor.hpp"
#include <tjp/core/threads/Lock.hpp>
#include <tjp/core/algorithm/vector_erase_if_value.hpp>
#include <tjp/core/containers/Vector.h>
namespace tjp::core::allocator_pool {
namespace prune {
struct Registry
{
Executor *executor = nullptr;
Mutex mutex;
Vector<Prunable *> prunables;
void insert(Prunable *p)
{
auto lock = lock_of(mutex);
prunables.push_back(p);
}
void erase(Prunable *p)
{
auto lock = lock_of(mutex);
vector_erase_if_value(prunables, [p](auto *v) { return v == p; });
}
void setAlgorithm(Executor *executor_)
{
if (executor)
executor->stop(this);
executor = executor_;
executor->start(this);
}
static Registry *shared();
} ;
} // namespace
} // namespace

View File

@@ -0,0 +1,64 @@
/**
* legal header
*/
#include <tjp/core/allocator/prune/Pruning.hpp>
#include <tjp/core/allocator/prune/Registry.hpp>
#include <tjp/core/allocator/prune/ExecutorManual.hpp>
#include <tjp/core/allocator/prune/algorithm/Averaging.hpp>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/iterators/range.hpp>
#include <tjp/core/containers/Set.hpp>
#include <tjp/core/algorithm/unused.hpp>
#include <tjp/core/allocator/ClassAllocatorPool.hpp>
namespace tjp::core::allocator_pool::prune {
namespace {
SCENARIO("core::allocator_pool::prune::Pruning")
{
GIVEN("allocator")
{
auto *pruneExecutor = new ExecutorManual<algorithm::Averaging>(50, 1.4);
Registry::shared()->setAlgorithm(pruneExecutor);
Pruning<ClassAllocatorPool<int>> p;
auto &size = p.getSize();
WHEN("allocate a deallocate and allocate again")
{
auto num = 100;
std::set<int *> a0;
for (auto i : range(num))
{
unused(i);
a0.insert(p.allocate());
}
REQUIRE(size.freed == 0);
REQUIRE(size.used == num);
for (auto _: range(100))
pruneExecutor->cycle();
for (auto *a : a0)
p.deallocate(a);
REQUIRE(size.used == 0);
REQUIRE(size.freed == num);
for (auto _: range(100))
pruneExecutor->cycle();
REQUIRE(size.used == 0);
REQUIRE(size.freed < num);
}
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,96 @@
/**
* legal header
*/
#pragma once
#include "../Data.hpp"
#include "../../Size.hpp"
#include <tjp/core/log/Log.h>
#include <tjp/core/log/LogOf.h>
#include <algorithm>
#include <cmath>
namespace tjp::core::allocator_pool::prune::algorithm {
struct AverageData : Data
{
public:
using Real = double;
Real windowSize;
Real m;
Real averageUsed = 0;
size_t threshold = 0;
public:
static const size_t ID = 0xABCD;
AverageData(size_t windowSize_, float m_) :
windowSize(windowSize_),
m(m_)
{
id = ID;
}
void sample (size_t freed, size_t used)
{
if (used > averageUsed)
averageUsed = used;
else
averageUsed -= (averageUsed - used) / windowSize;
threshold = std::max((size_t)averageUsed, used);
threshold = std::round(m * threshold);
}
bool shouldPrune(size_t freed, size_t used)
{
return
freed > 0 &&
used + freed > threshold;
}
} ;
struct Averaging
{
using Real = double;
size_t windowSize;
Real m;
Averaging(size_t windowSize_, Real m_) :
windowSize(windowSize_),
m(m_)
{
}
void cycle(Prunable *pool)
{
if (!pool->pruneData || pool->pruneData->id != AverageData::ID)
{
delete pool->pruneData;
pool->pruneData = new AverageData(windowSize, m);
}
auto data = (AverageData *)pool->pruneData;
auto &size = pool->getSize();
data->sample(size.freed, size.used);
auto pruned = 0;
while (data->shouldPrune(size.freed, size.used))
{
pool->prune();
pruned++;
}
sLogDebugIf((size.freed + size.used > 0), "core::allocator_pool", logVar(pool) << logVar(size.freed) << logVar(size.used) << logVar(data->averageUsed) << logVar(data->threshold) << logVar(pruned));
}
} ;
} // namespace

View File

@@ -0,0 +1,23 @@
/**
* legal header
*/
#pragma once
#include "AllocatorPoolPrunable.hpp"
namespace tjp::core::allocator_pool {
namespace algorithm {
struct None
{
public:
void cycle(AllocatorPoolPrunable *)
{
}
} ;
} // namespace
} // namespace

View File

@@ -0,0 +1,129 @@
/**
* legal header
*/
#pragma once
#include "../threads/Lock.hpp"
#include "Size.hpp"
namespace tjp::core::allocator_pool {
namespace sizeallocatorpool_locking {
template<size_t allocationSize, size_t alignment, typename C=void>
class SizeAllocatorPool
{
public:
struct Allocation
{
char t[allocationSize];
Allocation *next;
} __attribute__ ((aligned(alignment)));
typedef Mutex MutexT;
static constexpr size_t multiples = 1;
private:
MutexT mutex;
Allocation *head = nullptr;
Size size;
public:
SizeAllocatorPool ()
{
static_assert(offsetof(Allocation, t) == 0);
}
~SizeAllocatorPool ()
{
while (head)
{
auto a = pop();
if (a)
delete a;
}
size.used = size.freed = 0;
}
Allocation *pop()
{
auto lock = lock_of(mutex);
Allocation *a = head;
if (a != nullptr)
head = a->next;
return a;
}
void push(Allocation *a)
{
auto lock = lock_of(mutex);
a->next = head;
head = a;
}
void *allocate ()
{
// sLogDebug("debug", logVar(allocationSize) << logVar(alignment));
auto a = pop();
if (a)
{
size.used++;
size.freed--;
return (void *)&a->t;
}
size.used++;
auto allocation = new Allocation();
return &allocation->t;
}
void deallocate(void *o)
{
// sLogDebug("debug", logVar(allocationSize) << logVar(alignment));
if (!o)
return;
static_assert(offsetof(Allocation, t) == 0);
auto allocation = (Allocation *)o;
push(allocation);
size.used--;
size.freed++;
}
const Size &getSize ()
{
return size;
}
void prune()
{
auto lock = lock_of(mutex);
if (head)
{
auto next = head->next;
delete head;
head = next;
size.freed--;
}
}
} ;
} // namespace
} // namespace