Seed Core_IO from doc snapshot

This commit is contained in:
Local Seed
2026-02-11 16:14:01 -05:00
commit 25a8076064
53 changed files with 11472 additions and 0 deletions

View File

@@ -0,0 +1,673 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 55;
objects = {
/* Begin PBXBuildFile section */
F608A97B2826B5D5005C276B /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F608A97A2826B5D5005C276B /* main.cpp */; };
F608A9812826B5FA005C276B /* IO_bin.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F608A8FC2826A471005C276B /* IO_bin.cpp */; };
F608AAFA28271F4F005C276B /* libCore_Zero.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F608AAF928271F4F005C276B /* libCore_Zero.a */; };
F60A19B1284579080040CD24 /* IO_json.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F608A9042826A471005C276B /* IO_json.cpp */; };
F61F9BD72C6E0EE800F79137 /* Ptr+IO.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F61F9BD62C6E0EE800F79137 /* Ptr+IO.cpp */; };
F61F9BD92C6E0F2A00F79137 /* ConstString+IO.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F61F9BD82C6E0F2A00F79137 /* ConstString+IO.cpp */; };
F61F9BE02C6E2DD200F79137 /* libCore_Allocator.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F61F9BDF2C6E2DD200F79137 /* libCore_Allocator.a */; };
F62B987928D60EF700ACC388 /* sajson.h in Headers */ = {isa = PBXBuildFile; fileRef = F62B987828D60EF700ACC388 /* sajson.h */; };
F62B987A28D60EF700ACC388 /* sajson.h in Headers */ = {isa = PBXBuildFile; fileRef = F62B987828D60EF700ACC388 /* sajson.h */; };
F62B987C28D618E800ACC388 /* libCore_Misc.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F62B987B28D618E800ACC388 /* libCore_Misc.a */; };
F62B987E28D61A7300ACC388 /* libresolv.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = F62B987D28D61A7300ACC388 /* libresolv.tbd */; };
F633E94E2916E027007A4C26 /* IO_bin_versioning.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F633E94D2916DB18007A4C26 /* IO_bin_versioning.cpp */; };
F69548882828853E005D1B64 /* IO.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F695488728288532005D1B64 /* IO.cpp */; };
F6971F25282B1171008FBD17 /* IO.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F695488728288532005D1B64 /* IO.cpp */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
F608AAF728271F30005C276B /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = F608A8E52826A411005C276B /* Project object */;
proxyType = 1;
remoteGlobalIDString = F608A8EC2826A412005C276B;
remoteInfo = Core_IO;
};
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
F608A9762826B5D5005C276B /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = /usr/share/man/man1/;
dstSubfolderSpec = 0;
files = (
);
runOnlyForDeploymentPostprocessing = 1;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
F608A8ED2826A412005C276B /* libCore_IO.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libCore_IO.a; sourceTree = BUILT_PRODUCTS_DIR; };
F608A8F62826A470005C276B /* in_file.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = in_file.hpp; sourceTree = "<group>"; };
F608A8F72826A470005C276B /* out.inl */ = {isa = PBXFileReference; lastKnownFileType = text; path = out.inl; sourceTree = "<group>"; };
F608A8F82826A470005C276B /* Debug.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Debug.h; sourceTree = "<group>"; };
F608A8F92826A470005C276B /* in_sajson.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = in_sajson.h; sourceTree = "<group>"; };
F608A8FA2826A470005C276B /* out.inl */ = {isa = PBXFileReference; lastKnownFileType = text; path = out.inl; sourceTree = "<group>"; };
F608A8FB2826A471005C276B /* in.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = in.h; sourceTree = "<group>"; };
F608A8FC2826A471005C276B /* IO_bin.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = IO_bin.cpp; sourceTree = "<group>"; };
F608A8FD2826A471005C276B /* in_file.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = in_file.hpp; sourceTree = "<group>"; };
F608A8FE2826A471005C276B /* out_file.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = out_file.hpp; sourceTree = "<group>"; };
F608A8FF2826A471005C276B /* out_file.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = out_file.hpp; sourceTree = "<group>"; };
F608A9002826A471005C276B /* IO.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IO.h; sourceTree = "<group>"; };
F608A9012826A471005C276B /* json.inl */ = {isa = PBXFileReference; lastKnownFileType = text; path = json.inl; sourceTree = "<group>"; };
F608A9022826A471005C276B /* in_sajson.inl */ = {isa = PBXFileReference; lastKnownFileType = text; path = in_sajson.inl; sourceTree = "<group>"; };
F608A9032826A471005C276B /* out.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = out.h; sourceTree = "<group>"; };
F608A9042826A471005C276B /* IO_json.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = IO_json.cpp; sourceTree = "<group>"; };
F608A9062826A471005C276B /* IO.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IO.h; sourceTree = "<group>"; };
F608A9072826A471005C276B /* IO.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IO.h; sourceTree = "<group>"; };
F608A9082826A471005C276B /* out.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = out.h; sourceTree = "<group>"; };
F608A9092826A471005C276B /* in.inl */ = {isa = PBXFileReference; lastKnownFileType = text; path = in.inl; sourceTree = "<group>"; };
F608A9782826B5D5005C276B /* Core_IO_Tests */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = Core_IO_Tests; sourceTree = BUILT_PRODUCTS_DIR; };
F608A97A2826B5D5005C276B /* main.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = "<group>"; };
F608AAF928271F4F005C276B /* libCore_Zero.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libCore_Zero.a; sourceTree = BUILT_PRODUCTS_DIR; };
F608AB672827F3B1005C276B /* Makefile.def */ = {isa = PBXFileReference; lastKnownFileType = text; path = Makefile.def; sourceTree = "<group>"; };
F608AB682827F3B1005C276B /* Makefile.project */ = {isa = PBXFileReference; lastKnownFileType = text; path = Makefile.project; sourceTree = "<group>"; };
F61DB8F428580CCF00B74C99 /* Exception.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Exception.h; sourceTree = "<group>"; };
F61F9BD62C6E0EE800F79137 /* Ptr+IO.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = "Ptr+IO.cpp"; sourceTree = "<group>"; };
F61F9BD82C6E0F2A00F79137 /* ConstString+IO.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = "ConstString+IO.cpp"; sourceTree = "<group>"; };
F61F9BDF2C6E2DD200F79137 /* libCore_Allocator.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libCore_Allocator.a; sourceTree = BUILT_PRODUCTS_DIR; };
F61F9BF42C6E4FAD00F79137 /* Makefile.project */ = {isa = PBXFileReference; lastKnownFileType = text; path = Makefile.project; sourceTree = "<group>"; };
F62B987828D60EF700ACC388 /* sajson.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sajson.h; sourceTree = "<group>"; };
F62B987B28D618E800ACC388 /* libCore_Misc.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libCore_Misc.a; sourceTree = BUILT_PRODUCTS_DIR; };
F62B987D28D61A7300ACC388 /* libresolv.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libresolv.tbd; path = usr/lib/libresolv.tbd; sourceTree = SDKROOT; };
F62DCFDE2A69F9B9001E4F2C /* dictionary.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = dictionary.h; sourceTree = "<group>"; };
F633E94D2916DB18007A4C26 /* IO_bin_versioning.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = IO_bin_versioning.cpp; sourceTree = "<group>"; };
F64D834B2E4B6A1F009AD431 /* json.inl */ = {isa = PBXFileReference; lastKnownFileType = text; path = json.inl; sourceTree = "<group>"; };
F6757C802BD3EDA600B22032 /* IO_encoder.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IO_encoder.h; sourceTree = "<group>"; };
F6757C812BD3EDC500B22032 /* IO_dispatch.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IO_dispatch.h; sourceTree = "<group>"; };
F695488728288532005D1B64 /* IO.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = IO.cpp; sourceTree = "<group>"; };
F6971F2A282B1171008FBD17 /* libCore_IO_iOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libCore_IO_iOS.a; sourceTree = BUILT_PRODUCTS_DIR; };
F69AB7332B1579A9000115BC /* out_fwd.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = out_fwd.h; sourceTree = "<group>"; };
F69AB7342B157A54000115BC /* in_fwd.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = in_fwd.h; sourceTree = "<group>"; };
F6ACACB62B65FCD400581C16 /* sajson-save.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "sajson-save.h"; sourceTree = "<group>"; };
F6BF9BE62E39022F002E6AF0 /* Makefile */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = "<group>"; };
F6F10D1D2E37C2750082E9D9 /* IO_.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IO_.h; sourceTree = "<group>"; };
F6F858C42E7C2F6E002A1971 /* LICENSE */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENSE; sourceTree = "<group>"; };
F6F858C62E7C3125002A1971 /* ReadMe.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = ReadMe.md; sourceTree = "<group>"; };
F6FC229D284F736500A6381D /* Notes.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = Notes.txt; sourceTree = "<group>"; };
F6FD255D2E5E0EC300C2380E /* calls.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = calls.hpp; sourceTree = "<group>"; };
F6FD255E2E5E0F2400C2380E /* IO+config.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "IO+config.h"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
F608A8EB2826A412005C276B /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
F608A9752826B5D5005C276B /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
F62B987E28D61A7300ACC388 /* libresolv.tbd in Frameworks */,
F61F9BE02C6E2DD200F79137 /* libCore_Allocator.a in Frameworks */,
F62B987C28D618E800ACC388 /* libCore_Misc.a in Frameworks */,
F608AAFA28271F4F005C276B /* libCore_Zero.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
F6971F26282B1171008FBD17 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
F608A8E42826A411005C276B = {
isa = PBXGroup;
children = (
F608A97F2826B5F0005C276B /* Frameworks */,
F6F858C42E7C2F6E002A1971 /* LICENSE */,
F6BF9BE62E39022F002E6AF0 /* Makefile */,
F608AB672827F3B1005C276B /* Makefile.def */,
F608AB682827F3B1005C276B /* Makefile.project */,
F608A8EE2826A412005C276B /* Products */,
F6F858C62E7C3125002A1971 /* ReadMe.md */,
F608A9822826B613005C276B /* tests */,
F61D7C432E381697002A1AED /* tjp */,
);
sourceTree = "<group>";
};
F608A8EE2826A412005C276B /* Products */ = {
isa = PBXGroup;
children = (
F608A8ED2826A412005C276B /* libCore_IO.a */,
F608A9782826B5D5005C276B /* Core_IO_Tests */,
F6971F2A282B1171008FBD17 /* libCore_IO_iOS.a */,
);
name = Products;
sourceTree = "<group>";
};
F608A8F42826A422005C276B /* core */ = {
isa = PBXGroup;
children = (
F62B987728D60EF700ACC388 /* json */,
F608A8F52826A42A005C276B /* io */,
);
path = core;
sourceTree = "<group>";
};
F608A8F52826A42A005C276B /* io */ = {
isa = PBXGroup;
children = (
F662436C2E4552CE00859693 /* json */,
F662436B2E4552C800859693 /* bin */,
F6FC229D284F736500A6381D /* Notes.txt */,
F61DB8F428580CCF00B74C99 /* Exception.h */,
F6F10D1D2E37C2750082E9D9 /* IO_.h */,
F6757C802BD3EDA600B22032 /* IO_encoder.h */,
F6757C812BD3EDC500B22032 /* IO_dispatch.h */,
F695488728288532005D1B64 /* IO.cpp */,
F6FD255D2E5E0EC300C2380E /* calls.hpp */,
F6FD255E2E5E0F2400C2380E /* IO+config.h */,
F608A9072826A471005C276B /* IO.h */,
);
path = io;
sourceTree = "<group>";
};
F608A97F2826B5F0005C276B /* Frameworks */ = {
isa = PBXGroup;
children = (
F61F9BDF2C6E2DD200F79137 /* libCore_Allocator.a */,
F62B987D28D61A7300ACC388 /* libresolv.tbd */,
F62B987B28D618E800ACC388 /* libCore_Misc.a */,
F608AAF928271F4F005C276B /* libCore_Zero.a */,
);
name = Frameworks;
sourceTree = "<group>";
};
F608A9822826B613005C276B /* tests */ = {
isa = PBXGroup;
children = (
F61F9BF42C6E4FAD00F79137 /* Makefile.project */,
F608A97A2826B5D5005C276B /* main.cpp */,
);
path = tests;
sourceTree = "<group>";
};
F61D7C432E381697002A1AED /* tjp */ = {
isa = PBXGroup;
children = (
F608A8F42826A422005C276B /* core */,
);
path = tjp;
sourceTree = "<group>";
};
F61F9BD52C6DE0CE00F79137 /* _tests */ = {
isa = PBXGroup;
children = (
F608A8FC2826A471005C276B /* IO_bin.cpp */,
F61F9BD62C6E0EE800F79137 /* Ptr+IO.cpp */,
F61F9BD82C6E0F2A00F79137 /* ConstString+IO.cpp */,
F633E94D2916DB18007A4C26 /* IO_bin_versioning.cpp */,
);
path = _tests;
sourceTree = "<group>";
};
F62B987728D60EF700ACC388 /* json */ = {
isa = PBXGroup;
children = (
F6ACACB62B65FCD400581C16 /* sajson-save.h */,
F62B987828D60EF700ACC388 /* sajson.h */,
);
path = json;
sourceTree = "<group>";
};
F662436B2E4552C800859693 /* bin */ = {
isa = PBXGroup;
children = (
F61F9BD52C6DE0CE00F79137 /* _tests */,
F608A8F82826A470005C276B /* Debug.h */,
F69AB7332B1579A9000115BC /* out_fwd.h */,
F62DCFDE2A69F9B9001E4F2C /* dictionary.h */,
F608A8FD2826A471005C276B /* in_file.hpp */,
F608A8FB2826A471005C276B /* in.h */,
F69AB7342B157A54000115BC /* in_fwd.h */,
F608A9092826A471005C276B /* in.inl */,
F608A9012826A471005C276B /* json.inl */,
F608A8FE2826A471005C276B /* out_file.hpp */,
F608A9082826A471005C276B /* out.h */,
F608A8FA2826A470005C276B /* out.inl */,
F608A9062826A471005C276B /* IO.h */,
);
path = bin;
sourceTree = "<group>";
};
F662436C2E4552CE00859693 /* json */ = {
isa = PBXGroup;
children = (
F662436D2E455EB700859693 /* _tests */,
F608A8F62826A470005C276B /* in_file.hpp */,
F608A8F92826A470005C276B /* in_sajson.h */,
F608A9022826A471005C276B /* in_sajson.inl */,
F608A8FF2826A471005C276B /* out_file.hpp */,
F64D834B2E4B6A1F009AD431 /* json.inl */,
F608A9032826A471005C276B /* out.h */,
F608A8F72826A470005C276B /* out.inl */,
F608A9002826A471005C276B /* IO.h */,
);
path = json;
sourceTree = "<group>";
};
F662436D2E455EB700859693 /* _tests */ = {
isa = PBXGroup;
children = (
F608A9042826A471005C276B /* IO_json.cpp */,
);
path = _tests;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
F608A8E92826A412005C276B /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
F62B987928D60EF700ACC388 /* sajson.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
F6971F23282B1171008FBD17 /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
F62B987A28D60EF700ACC388 /* sajson.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
F608A8EC2826A412005C276B /* Core_IO */ = {
isa = PBXNativeTarget;
buildConfigurationList = F608A8F12826A412005C276B /* Build configuration list for PBXNativeTarget "Core_IO" */;
buildPhases = (
F608A8E92826A412005C276B /* Headers */,
F608A8EA2826A412005C276B /* Sources */,
F608A8EB2826A412005C276B /* Frameworks */,
);
buildRules = (
);
dependencies = (
);
name = Core_IO;
productName = Core_IO;
productReference = F608A8ED2826A412005C276B /* libCore_IO.a */;
productType = "com.apple.product-type.library.static";
};
F608A9772826B5D5005C276B /* Core_IO_Tests */ = {
isa = PBXNativeTarget;
buildConfigurationList = F608A97E2826B5D5005C276B /* Build configuration list for PBXNativeTarget "Core_IO_Tests" */;
buildPhases = (
F608A9742826B5D5005C276B /* Sources */,
F608A9752826B5D5005C276B /* Frameworks */,
F608A9762826B5D5005C276B /* CopyFiles */,
);
buildRules = (
);
dependencies = (
F608AAF828271F30005C276B /* PBXTargetDependency */,
);
name = Core_IO_Tests;
productName = Core_IO_Tests;
productReference = F608A9782826B5D5005C276B /* Core_IO_Tests */;
productType = "com.apple.product-type.tool";
};
F6971F22282B1171008FBD17 /* Core_IO_iOS */ = {
isa = PBXNativeTarget;
buildConfigurationList = F6971F27282B1171008FBD17 /* Build configuration list for PBXNativeTarget "Core_IO_iOS" */;
buildPhases = (
F6971F23282B1171008FBD17 /* Headers */,
F6971F24282B1171008FBD17 /* Sources */,
F6971F26282B1171008FBD17 /* Frameworks */,
);
buildRules = (
);
dependencies = (
);
name = Core_IO_iOS;
productName = Core_IO;
productReference = F6971F2A282B1171008FBD17 /* libCore_IO_iOS.a */;
productType = "com.apple.product-type.library.static";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
F608A8E52826A411005C276B /* Project object */ = {
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = 1;
DefaultBuildSystemTypeForWorkspace = Original;
LastUpgradeCheck = 1330;
TargetAttributes = {
F608A8EC2826A412005C276B = {
CreatedOnToolsVersion = 13.3;
};
F608A9772826B5D5005C276B = {
CreatedOnToolsVersion = 13.3;
};
};
};
buildConfigurationList = F608A8E82826A411005C276B /* Build configuration list for PBXProject "Core_IO" */;
compatibilityVersion = "Xcode 13.0";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = F608A8E42826A411005C276B;
productRefGroup = F608A8EE2826A412005C276B /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
F608A8EC2826A412005C276B /* Core_IO */,
F6971F22282B1171008FBD17 /* Core_IO_iOS */,
F608A9772826B5D5005C276B /* Core_IO_Tests */,
);
};
/* End PBXProject section */
/* Begin PBXSourcesBuildPhase section */
F608A8EA2826A412005C276B /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
F69548882828853E005D1B64 /* IO.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
F608A9742826B5D5005C276B /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
F60A19B1284579080040CD24 /* IO_json.cpp in Sources */,
F633E94E2916E027007A4C26 /* IO_bin_versioning.cpp in Sources */,
F61F9BD92C6E0F2A00F79137 /* ConstString+IO.cpp in Sources */,
F608A97B2826B5D5005C276B /* main.cpp in Sources */,
F608A9812826B5FA005C276B /* IO_bin.cpp in Sources */,
F61F9BD72C6E0EE800F79137 /* Ptr+IO.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
F6971F24282B1171008FBD17 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
F6971F25282B1171008FBD17 /* IO.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
F608AAF828271F30005C276B /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = F608A8EC2826A412005C276B /* Core_IO */;
targetProxy = F608AAF728271F30005C276B /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin XCBuildConfiguration section */
F608A8EF2826A412005C276B /* 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_SYMBOLS_PRIVATE_EXTERN = 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,
../Core_Allocator,
);
IPHONEOS_DEPLOYMENT_TARGET = 13.6;
LIBRARY_SEARCH_PATHS = ../Libraries/project/Debug.osx;
"LIBRARY_SEARCH_PATHS[sdk=iphoneos*]" = ../Libraries/project/Debug.ios;
MACOSX_DEPLOYMENT_TARGET = 10.15;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
USE_HEADERMAP = NO;
};
name = Debug;
};
F608A8F02826A412005C276B /* 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_SYMBOLS_PRIVATE_EXTERN = 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,
../Core_Allocator,
);
IPHONEOS_DEPLOYMENT_TARGET = 13.6;
LIBRARY_SEARCH_PATHS = ../Libraries/project/Release.osx;
"LIBRARY_SEARCH_PATHS[sdk=iphoneos*]" = ../Libraries/project/Release.ios;
MACOSX_DEPLOYMENT_TARGET = 10.15;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = macosx;
USE_HEADERMAP = NO;
};
name = Release;
};
F608A8F22826A412005C276B /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = T2M28D3T75;
EXECUTABLE_PREFIX = lib;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
};
name = Debug;
};
F608A8F32826A412005C276B /* 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;
};
F608A97C2826B5D5005C276B /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = T2M28D3T75;
ENABLE_HARDENED_RUNTIME = YES;
HEADER_SEARCH_PATHS = (
"${inherited}",
../Core_IO,
);
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
};
F608A97D2826B5D5005C276B /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = T2M28D3T75;
ENABLE_HARDENED_RUNTIME = YES;
HEADER_SEARCH_PATHS = (
"${inherited}",
../Core_IO,
);
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
};
F6971F28282B1171008FBD17 /* 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;
};
F6971F29282B1171008FBD17 /* 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 */
F608A8E82826A411005C276B /* Build configuration list for PBXProject "Core_IO" */ = {
isa = XCConfigurationList;
buildConfigurations = (
F608A8EF2826A412005C276B /* Debug */,
F608A8F02826A412005C276B /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
F608A8F12826A412005C276B /* Build configuration list for PBXNativeTarget "Core_IO" */ = {
isa = XCConfigurationList;
buildConfigurations = (
F608A8F22826A412005C276B /* Debug */,
F608A8F32826A412005C276B /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
F608A97E2826B5D5005C276B /* Build configuration list for PBXNativeTarget "Core_IO_Tests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
F608A97C2826B5D5005C276B /* Debug */,
F608A97D2826B5D5005C276B /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
F6971F27282B1171008FBD17 /* Build configuration list for PBXNativeTarget "Core_IO_iOS" */ = {
isa = XCConfigurationList;
buildConfigurations = (
F6971F28282B1171008FBD17 /* Debug */,
F6971F29282B1171008FBD17 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = F608A8E52826A411005C276B /* Project object */;
}

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:">
</FileRef>
</Workspace>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View File

@@ -0,0 +1,88 @@
<?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 = "F608A9772826B5D5005C276B"
BuildableName = "Core_IO_Tests"
BlueprintName = "Core_IO_Tests"
ReferencedContainer = "container:Core_IO.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 = "F608A9772826B5D5005C276B"
BuildableName = "Core_IO_Tests"
BlueprintName = "Core_IO_Tests"
ReferencedContainer = "container:Core_IO.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<CommandLineArguments>
<CommandLineArgument
argument = "-s"
isEnabled = "YES">
</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 = "F608A9772826B5D5005C276B"
BuildableName = "Core_IO_Tests"
BlueprintName = "Core_IO_Tests"
ReferencedContainer = "container:Core_IO.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Bucket
uuid = "4109D93F-EDDA-4746-8351-DC600656F7C7"
type = "1"
version = "2.0">
</Bucket>

View File

@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>SchemeUserState</key>
<dict>
<key>Core_IO copy.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>76</integer>
</dict>
<key>Core_IO.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>22</integer>
</dict>
<key>Core_IO_Tests.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>3</integer>
</dict>
<key>Core_IO_iOS.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>19</integer>
</dict>
</dict>
<key>SuppressBuildableAutocreation</key>
<dict>
<key>F608A9772826B5D5005C276B</key>
<dict>
<key>primary</key>
<true/>
</dict>
</dict>
</dict>
</plist>

26
LICENSE Executable file
View File

@@ -0,0 +1,26 @@
MIT NON-AI License
Copyright (c) 2025, Timothy Prepscius
Permission is hereby granted, free of charge, to any person obtaining a copy of the software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions.
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
In addition, the following restrictions apply:
1. The Software and any modifications made to it may not be used for the purpose of training or improving machine learning algorithms,
including but not limited to artificial intelligence, natural language processing, or data mining. This condition applies to any derivatives,
modifications, or updates based on the Software code. Any usage of the Software in an AI-training dataset is considered a breach of this License.
2. The Software may not be included in any dataset used for training or improving machine learning algorithms,
including but not limited to artificial intelligence, natural language processing, or data mining.
3. Any person or organization found to be in violation of these restrictions will be subject to legal action and may be held liable
for any damages resulting from such use.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

2
Makefile Normal file
View File

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

6
Makefile.def Executable file
View File

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

15
Makefile.project Executable file
View File

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

157
ReadMe.md Executable file
View File

@@ -0,0 +1,157 @@
# Core_IO
IO foundational classes
IO classes which optimize super well, super fast, super memory efficient.
JSON is based on sajson which is nearly as fast as memcpy (which blows my mind).
## Building
IO is header only.
## How to use
### Declare your data
```
namespace my_namespace {
struct MyOtherData {
float f;
} ;
struct MyData {
char c;
int i;
std::string s;
MyOtherData o;
} ;
} // my_namespace
```
### Somewhere in the same namespace, declare the serializer:
```
namespace my_namespace {
template<typename IO>
void io_(IO &io, MyOtherData &v)
{
io.object(
"f", v.f
);
)
template<typename IO>
void io_(IO &io, MyData &v)
{
io.object(
"c", v.c,
"i", v.i,
"s", v.s,
"o", v.o
);
)
} // my_namespace
```
### To serialize and deserialize as json:
```
#include <tjp/core/json/in_sajson.h>
#include <tjp/core/json/out.h>
namespace any_namespace {
void somewhere ()
{
my_namespace::MyData myData;
auto serialized = tjp::core::io::json::serialize(myData);
auto deserialized = tjp::core::io::json::deserialize<my_namespace::MyData>(serialized);
}
} // any_namespace
```
### To serialize and deserialize as binary:
```
#include <tjp/core/bin/in.h>
#include <tjp/core/bin/out.h>
namespace any_namespace {
void somewhere ()
{
my_namespace::MyData myData;
auto serialized = tjp::core::io::bin::serialize(myData);
auto deserialized = tjp::core::io::bin::deserialize<my_namespace::MyData>(serialized);
}
} // any_namespace
```
### To do versioning
I use versioning, however I declared it outside the scope of the library.
The method I ended up using was to deserialize a version number at the beginning of a
deserialization and store in the IO class. Then when deserializing data which is versioned,
check the version number and dispatch to the appropriate function.
It ends up looking like this:
```
template<typename IO>
void io_(IO &io, TimeSpecification &v, serializer::Version<100> &&)
{
io.object(
"clock", v.clock,
"bounds", v.bounds
);
}
template<typename IO>
void io_(IO &io, TimeSpecification &v, serializer::Version<104> &&)
{
io.object(
"clock", v.clock,
"bounds", v.bounds,
"flags", v.flags
);
}
template<typename IO>
void io_(IO &io, TimeSpecification &v)
{
if (io.version.my_version_number < 104)
return io_(io, v, serializer::Version<104>{});
return io_(io, v, serializer::Version<104>{});
}
```
###
You can make your own serialization IO by implementing a new IO class
It's not trivial, but it's not hard.
Generally, I'll be putting in some time to clean up these IO classes in the end of 2025.
### Other examples
Look at `Core_IO/bin/_tests/IO_bin.cpp` for more examples on how to use this library.

2
tests/Core_IO_Tests.txt Normal file
View File

@@ -0,0 +1,2 @@
20240816_17:25:39.857162 1eefafac0 | [testing] ius::core::log::Logs::activate logging activated
20240816_17:25:39.857224 1eefafac0 | [debug] ius::core::log::Logs::activate logging activated

1
tests/Makefile Symbolic link
View File

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

32
tests/Makefile.project Executable file
View File

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

21
tests/main.cpp Normal file
View File

@@ -0,0 +1,21 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#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_IO_Tests.txt");
xLogActivateStory("testing");
xLogActivateStory("debug");
int result = Catch::Session().run( argc, argv );
return result;
}

14
tjp/core/io/Exception.h Normal file
View File

@@ -0,0 +1,14 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include <tjp/core/exception/Exception.hpp>
namespace tjp::core::io {
DECLARE_EXCEPTION(Exception);
} // namespace

56
tjp/core/io/IO+config.h Executable file
View File

@@ -0,0 +1,56 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#define IO_USE_NON_RECURSIVE_APPLY
#ifdef IO_USE_NON_RECURSIVE_APPLY
#include "calls.hpp"
#endif
namespace tjp::core::io {
#ifdef IO_USE_NON_RECURSIVE_APPLY
template<typename F, typename ... Args>
void call_expand_1(
F &&f,
Args && ...args
)
{
call_f_1s(std::forward<F>(f), std::forward<Args>(args)...);
}
template<typename F, typename ... Args>
void call_expand_2(
F &&f,
Args && ...args
)
{
call_f_2s(std::forward<F>(f), std::forward<Args>(args)...);
}
#else
template<typename F, typename A, typename ... Args>
void call_expand_1(F &&f, A &&a Args&& ...args)
{
f(std::forward<A>(a));
call_expand_2(std::forward<F>(f), std::forward<Args>(args)...);
}
template<typename F, typename A, typename B, typename ... Args>
void call_expand_2(F &&f, A &&a, B &&b, Args&& ...args)
{
f(std::forward<A>(a), std::forward<B>(b));
call_expand_2(std::forward<F>(f), std::forward<Args>(args)...);
}
#endif
}

4
tjp/core/io/IO.cpp Normal file
View File

@@ -0,0 +1,4 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius

49
tjp/core/io/IO.h Executable file
View File

@@ -0,0 +1,49 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include <tjp/core/type_traits/always_false.hpp>
namespace tjp::core {
//namespace variant { struct Variant; }
template<typename IO, typename T>
void io_dispatch_failed(IO &io, T &t)
{
static_assert(always_false<T>::value, "io_ or (io_w and io_r) must be defined for non trivial types");
}
template<typename IO, typename T>
void io_(IO &io, T &t)
{
io.on_dispatch_any(t);
}
template<typename IO, typename T>
void io_w(IO &io, const T &t)
{
io_(io, const_cast<T &>(t));
}
template<typename IO, typename T>
void io_w_(IO &io, const T &t)
{
io_w(io, t);
}
template<typename IO, typename T>
void io_r(IO &io, T &t)
{
io_(io, t);
}
template<typename IO, typename T>
void io_r_(IO &io, T &t)
{
io_r(io, t);
}
} // namespace

17
tjp/core/io/IO_.h Normal file
View File

@@ -0,0 +1,17 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
namespace tjp {
namespace core {
template<typename T>
void io_resize_vector(T &t, size_t size)
{
t.resize(size);
}
} //
} //

23
tjp/core/io/IO_dispatch.h Executable file
View File

@@ -0,0 +1,23 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "IO.h"
namespace tjp::core {
template<typename T>
struct DispatchIO
{
T *t;
} ;
template<typename T>
DispatchIO<T> makeDispatchIO(T &t)
{
return DispatchIO<T>{&t};
}
} // namespace

112
tjp/core/io/IO_encoder.h Executable file
View File

@@ -0,0 +1,112 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "IO.h"
#include <tjp/core/bases/Base64.h>
#include <tjp/core/string/String.h>
#include <type_traits>
#include <tjp/core/string/to_string.hpp>
#include <tjp/core/string/from_string.hpp>
namespace tjp::core {
template<typename T>
struct BinaryEncoder
{
T *t;
} ;
template<typename T>
BinaryEncoder<T> makeBinaryEncoder(T &t)
{
return BinaryEncoder<T>{&t};
}
template<typename T>
struct StringEncoder
{
T *t;
} ;
template<typename T>
StringEncoder<T> makeStringEncoder(T &t)
{
return StringEncoder<T>{&t};
}
template<typename IO, typename T>
void io_bin_r(IO &io, BinaryEncoder<T> &v)
{
io.any(*v.t);
}
template<typename IO, typename T>
void io_bin_w(IO &io, const BinaryEncoder<T> &v)
{
io.any(*v.t);
}
template<typename IO, typename T>
void io_bin_r(IO &io, StringEncoder<T> &v)
{
io.any(*v.t);
}
template<typename IO, typename T>
void io_bin_w(IO &io, const StringEncoder<T> &v)
{
io.any(*v.t);
}
template<typename IO, typename T>
void io_r(IO &io, BinaryEncoder<T> &v)
{
auto t = v.t;
using U = std::remove_reference_t<decltype(*t->data())>;
static_assert(std::is_fundamental_v<U> == true);
String s;
io.any(s);
auto size_byte = base64DecodeSize(s.size());
auto size = size_byte / sizeof(U);
t->resize(size);
fromBase64(s, (char *)t->data(), size_byte);
}
template<typename IO, typename T>
void io_w(IO &io, const BinaryEncoder<T> &v)
{
auto t = v.t;
using U = std::remove_reference_t<decltype(*t->data())>;
static_assert(std::is_fundamental_v<U> == true);
auto size_byte = sizeof(U) * t->size();
io.any(toBase64((const char *)t->data(), size_byte));
}
template<typename IO, typename T>
void io_r(IO &io, StringEncoder<T> &v)
{
String s;
io.any(s);
auto t = v.t;
core::from_string(*t, s);
}
template<typename IO, typename T>
void io_w(IO &io, const StringEncoder<T> &v)
{
auto t = v.t;
io.any(core::to_string(*t));
}
} // namespace

7
tjp/core/io/Notes.txt Normal file
View File

@@ -0,0 +1,7 @@
I want to put a checkSize when I read a size, to verify that the readSize is reasonable
Or - I want to check every read before I do it.
It should just be f.validateReadSize(s)
and be used everywhere.

13
tjp/core/io/bin/Debug.h Normal file
View File

@@ -0,0 +1,13 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
//#define IO_BIN_USE_LOGGING
#ifdef IO_BIN_USE_LOGGING
#define IO_BIN_LOG(...) sLogRelease("io_bin", x)
#else
#define IO_BIN_LOG(...)
#endif

357
tjp/core/io/bin/IO.h Normal file
View File

@@ -0,0 +1,357 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "../IO.h"
#include "../IO_encoder.h"
#include "../IO_dispatch.h"
#include "../IO_.h"
#include "Debug.h"
#include "../Exception.h"
#include <tjp/core/types/Types.h>
#include <tjp/core/type_traits/is_mappish.hpp>
#include <tjp/core/type_traits/is_string.hpp>
#include <tjp/core/type_traits/is_iterable.hpp>
#include <tjp/core/type_traits/always_false.hpp>
#include <tjp/core/assert/debug_assert.h>
#include <cmath>
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <memory.h>
#include <typeinfo>
#include <optional>
//#include <tjp/core/allocator/AllocatorPool.hpp>
#include <tjp/core/system/System.h>
#include "dictionary.h"
namespace tjp::core::io::bin {
using Size = u32;
typedef const char *KeyType;
template <typename IO, typename T, typename = void>
struct has_io_bin : std::false_type {};
template <typename IO, typename T>
struct has_io_bin<IO, T,
std::void_t<decltype(io_bin(std::declval<IO&>(),
std::declval<T&>())) >> : std::true_type {};
//template<typename IO, typename T>
//void io_bin(IO &io, T &t)
//{
// io_(io, t);
//}
//
template<typename IO, typename T>
void io_bin_w_integer(IO &io, const T &t_)
{
constexpr u8 sevenBits = 0b01111111;
constexpr u8 eighthBit = 0b10000000;
// // check
// io.intrinsic(t_);
constexpr size_t maxBytes = sizeof(T) + sizeof(T)/8 + 1;
u8 bytes[maxBytes];
size_t count = 0;
u8 *out = bytes;
const T zero = T(0);
T t = t_;
do
{
u8 byte = t & sevenBits;
t >>= 7;
if (t != zero)
byte |= eighthBit;
*out++ = byte;
count++;
}
while (t > 0);
debug_assert(0 < count && count <= maxBytes);
io.intrinsic((const char *)bytes, count);
}
template<typename IO, typename T>
void io_bin_r_integer(IO &io, T &t)
{
constexpr u8 sevenBits = 0b01111111;
constexpr u8 eighthBit = 0b10000000;
// T check;
// io.intrinsic(check);
u8 reverse[sizeof(T) + sizeof(T)/8 + 1];
u8 *r = reverse;
t = 0;
u8 byte;
do
{
io.intrinsic(byte);
*r = byte;
++r;
}
while ((byte & eighthBit) != 0);
while (r != reverse)
{
--r;
t <<= 7;
t |= T(*r & sevenBits);
}
}
template<typename IO, typename T>
void io_bin_w_integer_signed(IO &io, const T &t_)
{
using UT = typename std::make_unsigned<T>::type;
UT t;
if (t_ < 0)
{
t = -t_;
t <<= 1;
t |= UT(1);
}
else
{
t = UT(t_) << 1;
}
io_bin_w_integer(io, t);
}
template<typename IO, typename T>
void io_bin_r_integer_signed(IO &io, T &t_)
{
using UT = typename std::make_unsigned<T>::type;
UT t;
io_bin_r_integer(io, t);
auto isNegative = t & 1;
t_ = t >> 1;
if (isNegative)
t_ = -t_;
}
template<typename IO> void io_bin(IO &io, bool &t) { io.intrinsic((s8&)t); }
template<typename IO> void io_bin(IO &io, u8 &t) { io.intrinsic(t); }
template<typename IO> void io_bin(IO &io, char &t) { io.intrinsic((s8&)t); }
template<typename IO> void io_bin(IO &io, s8 &t) { io.intrinsic(t); }
/*
template<typename IO> void io_bin(IO &io, u16 &t) { io.intrinsic(t); }
template<typename IO> void io_bin(IO &io, u32 &t) { io.intrinsic(t); }
template<typename IO> void io_bin(IO &io, u64 &t) { io.intrinsic(t); }
template<typename IO> void io_bin(IO &io, u128 &t) { io.intrinsic(t); }
template<typename IO> void io_bin(IO &io, s16 &t) { io.intrinsic(t); }
template<typename IO> void io_bin(IO &io, s32 &t) { io.intrinsic(t); }
template<typename IO> void io_bin(IO &io, s64 &t) { io.intrinsic(t); }
template<typename IO> void io_bin(IO &io, s128 &t) { io.intrinsic(t); }
*/
template<typename IO> void io_bin_w(IO &io, const u16 &t) { io_bin_w_integer(io, t); }
template<typename IO> void io_bin_w(IO &io, const u32 &t) { io_bin_w_integer(io, t); }
template<typename IO> void io_bin_w(IO &io, const u64 &t) { io_bin_w_integer(io, t); }
template<typename IO> void io_bin_w(IO &io, const u128 &t) { io_bin_w_integer(io, t); }
template<typename IO> void io_bin_w(IO &io, const s16 &t) { io_bin_w_integer_signed(io, t); }
template<typename IO> void io_bin_w(IO &io, const s32 &t) { io_bin_w_integer_signed(io, t); }
template<typename IO> void io_bin_w(IO &io, const s64 &t) { io_bin_w_integer_signed(io, t); }
template<typename IO> void io_bin_w(IO &io, const s128 &t) { io_bin_w_integer_signed(io, t); }
template<typename IO> void io_bin_r(IO &io, u16 &t) { io_bin_r_integer(io, t); }
template<typename IO> void io_bin_r(IO &io, u32 &t) { io_bin_r_integer(io, t); }
template<typename IO> void io_bin_r(IO &io, u64 &t) { io_bin_r_integer(io, t); }
template<typename IO> void io_bin_r(IO &io, u128 &t) { io_bin_r_integer(io, t); }
template<typename IO> void io_bin_r(IO &io, s16 &t) { io_bin_r_integer_signed(io, t); }
template<typename IO> void io_bin_r(IO &io, s32 &t) { io_bin_r_integer_signed(io, t); }
template<typename IO> void io_bin_r(IO &io, s64 &t) { io_bin_r_integer_signed(io, t); }
template<typename IO> void io_bin_r(IO &io, s128 &t) { io_bin_r_integer_signed(io, t); }
template<typename IO, typename T>
void io_bin_w_real(IO &io, const T &t_)
{
bool downcast = false; // io.flags & IO_FLAGS_DOWNCAST_REAL;
if (downcast)
{
io.intrinsic(static_cast<r32>(t_));
}
else
{
io.intrinsic(t_);
}
}
template<typename IO, typename T>
void io_bin_r_real(IO &io, T &t)
{
bool downcast = false; // io.flags & IO_FLAGS_DOWNCAST_REAL;
if (downcast)
{
r32 t_;
io.intrinsic(t_);
t = static_cast<T>(t_);
}
else
{
io.intrinsic(t);
}
}
template<typename IO> void io_bin_r(IO &io, r32 &t) { io_bin_r_real(io, t); }
template<typename IO> void io_bin_r(IO &io, r64 &t) { io_bin_r_real(io, t); }
template<typename IO> void io_bin_r(IO &io, r128 &t) { io_bin_r_real(io, t); }
template<typename IO> void io_bin_w(IO &io, const r32 &t) { io_bin_w_real(io, t); }
template<typename IO> void io_bin_w(IO &io, const r64 &t) { io_bin_w_real(io, t); }
template<typename IO> void io_bin_w(IO &io, const r128 &t) { io_bin_w_real(io, t); }
template<typename IO> void io_bin(IO &io, std::string &t) { io.intrinsic_string(t); }
#if defined(SYS_MAC) || defined(SYS_IOS)
/*
template<typename IO> void io_bin(IO &io, unsigned long &t) { io.intrinsic(t); }
template<typename IO> void io_bin(IO &io, signed long &t) { io.intrinsic(t); }
*/
template<typename IO> void io_bin_w(IO &io, const unsigned long &t) { io_bin_w_integer(io, t); }
template<typename IO> void io_bin_w(IO &io, const signed long &t) { io_bin_w_integer(io, t); }
template<typename IO> void io_bin_r(IO &io, unsigned long &t) { io_bin_r_integer(io, t); }
template<typename IO> void io_bin_r(IO &io, signed long &t) { io_bin_r_integer(io, t); }
#endif
template<typename T>
struct Optional
{
T &v;
bool write;
} ;
template<typename T>
Optional<T> optional(T &t, bool write=true) { return Optional<T> { t, write }; }
template<typename IO, typename T>
void io_bin(IO &io, Optional<T> &t) {
io.any(t.write);
if (t.write)
io.any(t.v);
}
template<typename P, typename T>
struct Pointer
{
P *p;
bool write;
} ;
template<typename IO, typename T>
void io_ptr_allocate(IO &io, T *&t)
{
io.allocate(t);
}
template<typename IO, typename T>
void io_ptr_allocate_default(IO &io, T *&t)
{
t = new T();
}
template<typename IO, typename T> void io_bin(IO &io, T *&t)
{
auto w = io.template pointer<T>(t);
io.any(w);
}
template<typename IO, typename B, typename T>
void io_bin_w(IO &io, const Pointer<B, T> &t)
{
io.any(t.write);
if (t.write)
io.any(**t.p);
}
template<typename IO, typename B, typename T>
void io_bin_r(IO &io, Pointer<B, T> &t)
{
io.any(t.write);
if (t.write)
{
io_ptr_allocate(io, *t.p);
io.any(**t.p);
}
}
typedef std::vector<char> Serialization;
template<typename T>
struct Custom
{
T *p;
} ;
template<typename IO, typename T>
void io_bin(IO &io, Custom<T> &t)
{
io.template dispatch_custom<>(io, *t.p);
}
template<typename IO, typename ...T>
void io_bin(IO &io, std::tuple<T...> &t)
{
std::apply([&io](auto &...x){(io.any(x), ...);}, t);
}
//#ifdef SYS_APPLE
// std::vector<bool> fixes
template<typename IO>
void io_bin_w(IO &io, const std::vector<bool>::const_iterator::reference t)
{
bool b = t;
io.intrinsic(b);
}
template<typename IO>
void io_bin_r(IO &io, std::vector<bool>::iterator::reference &t)
{
bool b;
io.intrinsic(b);
t = b;
}
//#endif
} // namespace
#include "in.h"
#include "out.h"

View File

@@ -0,0 +1,105 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include <tjp/core/string/Str.hpp>
#include <tjp/core/string/Str+IO.h>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/io/bin/IO.h>
#include <tjp/core/io/json/in_sajson.h>
#include <tjp/core/io/json/out.h>
#include <tjp/core/testing/catch.hpp>
namespace tjp::core::str {
namespace {
SCENARIO("core::string::str+io")
{
GIVEN("args")
{
core::from_string<core::Str>("1");
}
GIVEN("a const string")
{
Str one("1");
Str one_again("1");
Str two("2");
std::string v;
for (auto i=0;i<256;++i)
v += "a";
Str longString(v);
REQUIRE(one == one);
REQUIRE(one == "1");
REQUIRE(one != "2");
REQUIRE(one != two);
REQUIRE(one == one_again);
REQUIRE(longString == longString);
REQUIRE(longString != one);
}
GIVEN("a const string")
{
Str a("Aweoiwefo wefoij wefioj wefoi jwefo ijwefijo w");
Str b("Bweoiwefo wefoij wefioj wefoi jwefo ijwefijo w wefiojwefoi jwefio wefoij wefoij wefijo ewfioj wefjio wef");
Str c("Cweo");
WHEN("bin")
{
auto s = io::bin::serialize(a);
auto b = io::bin::deserialize<decltype(a)>(s);
REQUIRE(a == b);
}
WHEN("json")
{
auto s = io::json::serialize(a);
auto b = io::json::deserialize<decltype(a)>(s);
REQUIRE(a == b);
}
WHEN("bin multi")
{
io::bin::Writer<io::bin::memory_out> o;
o.object("a", a, "b", b, "c", c);
auto s = o.serialization();
io::bin::Reader<io::bin::memory_in> i(io::bin::memory_in(s.data(), s.size()));
Str a_, b_, c_;
i.object("a", a_, "b", b_, "c", c_);
REQUIRE(a == a_);
REQUIRE(b == b_);
REQUIRE(c == c_);
}
WHEN("json multi")
{
io::json::Serialization s;
omemstream stream(s);
io::json::Writer<io::json::json_out> o(stream);
o.object("a", a, "b", b, "c", c);
io::json::Reader<io::json::json_in> i(std::move(s));
Str a_, b_, c_;
i.object("a", a_, "b", b_, "c", c_);
REQUIRE(a == a_);
REQUIRE(b == b_);
REQUIRE(c == c_);
}
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,361 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include <tjp/core/io/bin/IO.h>
#include <tjp/core/testing/catch.hpp>
namespace tjp::core {
namespace {
struct VV : std::vector<int>
{
} ;
template<typename IO>
void io_bin(IO &io, VV &v)
{
std::string b = "b";
io.any(
b
);
};
struct VS {
int x;
} ;
bool operator ==(const VS &l, const VS &r)
{
return l.x == r.x;
}
std::ostream &operator <<(std::ostream &o, const VS &v)
{
return o << v.x;
}
std::istream &operator >>(std::istream &i, VS &v)
{
return i >> v.x;
}
struct A {
bool w;
int x;
std::string s;
std::vector<int> y;
std::vector<std::vector<int>> z;
std::string empty;
std::vector<int> v_b;
VS v_s;
bool operator ==(const A &rhs) const
{
return
w == rhs.w &&
x == rhs.x &&
y == rhs.y &&
z == rhs.z &&
v_b == rhs.v_b &&
v_s == rhs.v_s;
}
} ;
struct B {
int i;
} ;
template<typename IO>
void io_bin(IO &io, A &a)
{
io.object(
"w", a.w, "x", a.x, "y", a.y, "z", a.z, "s", a.s, "e", a.empty,
"v_b", makeBinaryEncoder(a.v_b),
"v_s", makeStringEncoder(a.v_s)
);
}
template<typename IO>
void io_bin(IO &io, VS &v)
{
io.object(
"x", v.x
);
}
SCENARIO("io bin serialization", "[core::io]" )
{
GIVEN("maliscous size")
{
io::bin::Size s;
s = 10000;
auto a = io::bin::serialize(s);
REQUIRE_THROWS(io::bin::deserialize<String>(a));
REQUIRE_THROWS(io::bin::deserialize<Vector<int>>(a));
}
GIVEN("a custom array with serializer")
{
auto v = VV();
auto vs = io::bin::serialize(v);
std::string b = "b";
auto vsi = io::bin::serialize(b);
REQUIRE(vs == vsi);
v = io::bin::deserialize<VV>(vs);
REQUIRE(v.empty());
}
GIVEN("interesting -1 s64")
{
s64 a = -1;
WHEN("serialize")
{
auto sa = io::bin::serialize(a);
THEN("size is one byte")
{
REQUIRE(sa.size() == 1);
}
}
}
GIVEN("interesting u32s")
{
typedef std::vector<u32> Numbers;
Numbers a { (u32)-1, (u32)0, (u32)1 };
WHEN("serialize and deserializee")
{
auto sa = io::bin::serialize(a);
auto a_ = io::bin::deserialize<Numbers>(std::move(sa));
THEN("is same")
{
REQUIRE(a_ == a);
}
}
}
GIVEN("interesting s32s")
{
typedef s32 Number;
typedef std::vector<Number> Numbers;
Numbers a { (Number)-1, (Number)0, (Number)1 };
WHEN("serialize and deserializee")
{
auto sa = io::bin::serialize(a);
auto a_ = io::bin::deserialize<Numbers>(std::move(sa));
THEN("is same")
{
REQUIRE(a_ == a);
}
}
}
GIVEN("vector of interesting s64 integers")
{
typedef std::vector<u64> Numbers;
Numbers a { 0xF, 0xF, 0xFF, 0xFFF, 0xFFFF, 0xFFFFF, 0xFFFFFF, 0xFFFFFFF, 0xFFFFFFFF };
WHEN("serialize and deserialize, is same")
{
auto sa = io::bin::serialize(a);
auto a_ = io::bin::deserialize<Numbers>(std::move(sa));
REQUIRE(a_ == a);
}
}
GIVEN("a structure")
{
A a = {
true, 13, std::string("hi"),
{ 2, 3, 4 },
{ { 1, 2, 3 }, { 4, 5, 6 } },
.empty = {},
.v_b = { 1, 2, 3, 4, 5, 6, 7 },
.v_s = { 1 }
};
WHEN("serialize and deserialize, is same")
{
auto sa = io::bin::serialize(a);
auto a_ = io::bin::deserialize<A>(std::move(sa));
bool same = a == a_;
REQUIRE(same);
}
}
GIVEN("an empty structure")
{
A a = { true, 13 };
WHEN("serialize and deserialize, is same")
{
auto sa = io::bin::serialize(a);
auto a_ = io::bin::deserialize<A>(std::move(sa));
bool same = a == a_;
REQUIRE(same);
}
}
GIVEN("a vector of bool")
{
typedef std::vector<bool> Bools;
Bools a { true, false, true, true };
WHEN("serialize and deserialize, is same")
{
auto sa = io::bin::serialize(a);
auto a_ = io::bin::deserialize<Bools>(std::move(sa));
REQUIRE(a_ == a);
}
}
GIVEN("a vector of char")
{
typedef std::vector<char> Chars;
Chars a { 'a', 'b', 'c', 'd' };
WHEN("serialize and deserialize, is same")
{
auto sa = io::bin::serialize(a);
auto a_ = io::bin::deserialize<Chars>(std::move(sa));
REQUIRE(a_ == a);
}
}
GIVEN("a vector of double including infinities")
{
typedef std::vector<double> Doubles;
Doubles a { 1.0, 1.5, 2.0, 2.5, std::numeric_limits<double>::infinity(), -std::numeric_limits<double>::infinity() };
WHEN("serialize and deserialize, is same")
{
auto sa = io::bin::serialize(a);
auto a_ = io::bin::deserialize<Doubles>(std::move(sa));
THEN("is same")
{
REQUIRE(a_ == a);
}
}
}
GIVEN("NAN")
{
double a = std::numeric_limits<double>::quiet_NaN();
WHEN("serialize and deserialize, is same")
{
auto sa = io::bin::serialize(a);
auto a_ = io::bin::deserialize<double>(std::move(sa));
REQUIRE(std::isnan(a_));
}
}
GIVEN("an empty vector")
{
typedef std::vector<int> V;
V a;
WHEN("serialize and deserialize")
{
auto sa = io::bin::serialize(a);
auto a_ = io::bin::deserialize<V>(std::move(sa));
THEN("is same")
{
REQUIRE(a_ == a);
}
}
}
GIVEN("an empty string")
{
typedef std::string V;
V a;
WHEN("serialize and deserialize")
{
auto sa = io::bin::serialize(a);
auto a_ = io::bin::deserialize<V>(std::move(sa));
THEN("is same")
{
REQUIRE(a_ == a);
}
}
}
GIVEN("same string multiple times")
{
typedef std::vector<std::string> V;
V a = { "a", "a", "a", "a", "b", "c", "c", "c", "b", "", "" };
WHEN("serialize and deserialize")
{
auto sa = io::bin::serialize(a);
auto a_ = io::bin::deserialize<V>(std::move(sa));
THEN("is same")
{
REQUIRE(a_ == a);
}
}
}
GIVEN("multiple embeds")
{
typedef std::vector<std::string> V;
V a = { "a", "a", "a", "a", "b", "c", "c", "c", "b", "", "" };
WHEN("serialize and deserialize")
{
io::bin::Writer<io::bin::memory_out> e {};
e.any(a);
io::bin::Writer<io::bin::memory_out> w {};
w.embed(e);
w.embed(e);
w.embed(e);
auto numExpected = 3;
auto sa = w.serialization();
io::bin::Reader<io::bin::memory_in> r(io::bin::memory_in(sa.data(), sa.size()));
int count = 0;
while (r)
{
auto e = r.embed();
auto a_ = io::bin::deserializeFrom<V>(e);
REQUIRE(a_ == a);
count++;
}
REQUIRE(count == numExpected);
}
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,179 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include <tjp/core/io/bin/IO.h>
#include <tjp/core/testing/catch.hpp>
namespace tjp::core {
namespace {
struct A_0 {
char v;
} ;
template<typename IO>
void io_ (IO &io, A_0 &v)
{
io.object("v", v.v);
}
struct A_1 {
int v;
};
template<typename IO>
void io_ (IO &io, A_1 &v)
{
io.object("v", v.v);
}
struct A_2 {
long v;
} ;
template<typename IO>
void io_ (IO &io, A_2 &v)
{
io.object("v", v.v);
}
struct A_3 {
char v;
} ;
template<typename IO>
void io_ (IO &io, A_3 &v)
{
io.object("v", v.v);
}
A_1 convert(A_0 a)
{
return { (int)a.v + 1};
}
A_2 convert(A_1 a)
{
return { (long)a.v + 1 };
}
A_3 convert(A_2 a)
{
return { (char)(a.v + 1) };
}
using VersionNumber = s8;
template<typename T>
struct Version {
static constexpr VersionNumber V = 0;
};
template<>
struct Version<A_3> {
typedef A_2 Previous;
static constexpr VersionNumber V = 3;
} ;
template<>
struct Version<A_2> {
typedef A_1 Previous;
static constexpr VersionNumber V = 2;
};
template<>
struct Version<A_1> {
typedef A_0 Previous;
static constexpr VersionNumber V = 1;
} ;
template<typename T, typename IO>
T deserialize_version(IO &io, VersionNumber v)
{
if (v == Version<T>::V)
{
T t;
io.any(t);
return t;
}
else
{
if constexpr(Version<T>::V == 0)
{
throw Exception { "Unknown version" };
}
else
{
return convert(deserialize_version<typename Version<T>::Previous>(io, v));
}
}
}
template<typename T, typename S>
T deserialize_version(const S &s)
{
io::bin::Reader<io::bin::memory_in> io(io::bin::memory_in(s.data(), s.size()));
s8 v;
io.object("v", v);
return deserialize_version<T>(io, v);
}
template<typename T>
auto serialize_version(const T &t)
{
io::bin::Writer<io::bin::memory_out> io;
s8 v = Version<T>::V;
io.object("v", v);
io.any(t);
return io.serialization();
}
SCENARIO("io bin serialization with versioning", "[core::io]" )
{
GIVEN("versioned struct 0")
{
A_0 a;
a.v = 0;
WHEN("serialize")
{
auto sa = serialize_version(a);
THEN("deserialize as a version A_0")
{
auto b = deserialize_version<A_0>(sa);
REQUIRE(b.v == 0);
}
THEN("deserialize as a version A_1")
{
auto b = deserialize_version<A_1>(sa);
REQUIRE(b.v == 1);
}
THEN("deserialize as a version A_2")
{
auto b = deserialize_version<A_2>(sa);
REQUIRE(b.v == 2);
}
THEN("deserialize as a version A_3")
{
auto b = deserialize_version<A_3>(sa);
REQUIRE(b.v == 3);
}
}
}
}
} // namespace
} // namespace

View File

@@ -0,0 +1,56 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include <tjp/core/ptr/Ptr.hpp>
#include <tjp/core/ptr/Ptr+IO.h>
#include <tjp/core/io/bin/IO.h>
#include <tjp/core/testing/catch.hpp>
#include <tjp/core/testing/NO_WHEN.h>
namespace tjp {
namespace core {
namespace memory {
namespace test_compile {
struct A
{
int i;
} ;
template<typename IO>
void io_bin(IO &io, A &a)
{
io.object("i", a.i);
}
SCENARIO("core::ptr io")
{
GIVEN("a ptr")
{
StrongPtr<A> a = strong<A>();
WHEN("ptr is serialized")
{
auto result = io::bin::serialize(a);
WHEN("result is unserialized")
{
auto a2 = io::bin::deserialize<StrongPtr<A>>(result);
THEN("results are equal")
{
REQUIRE(a2->i == a->i);
}
}
}
}
}
} // namespace
} // namespace
} // namespace
} // namespace

View File

@@ -0,0 +1,86 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include <string>
#include <vector>
#include <map>
#include <set>
#include <memory.h>
#include <typeinfo>
#include <tjp/core/string/Str.hpp>
#include <tjp/core/allocator/AllocatorPool.hpp>
#include <tjp/core/allocator/VectorPool.hpp>
#include <tjp/core/exception/debug_throw.h>
namespace tjp::core::io::bin {
using DictionaryIndex = u32;
template<typename T>
struct DictionaryOut
{
typedef T K;
typedef DictionaryIndex V;
typedef std::pair<const T, V> KV;
typedef core::AllocatorPool<KV> Allocator;
std::map<K, DictionaryIndex, std::less<K>, Allocator> values;
public:
typedef T value_type;
std::tuple<u32, bool> on(const T &t)
{
auto [ i, inserted ] = values.emplace(t, values.size());
return { i->second, inserted };
}
} ;
template<typename T>
struct DictionaryIn
{
std::vector<T, core::VectorPool<T>> values;
public:
typedef T value_type;
bool has(const DictionaryIndex &i)
{
return i < values.size();
}
const T &get(const DictionaryIndex &i)
{
if (i >= values.size())
debug_throw(io::Exception("Dictionary failure"));
return values[i];
}
T &set(const DictionaryIndex &i, const T &t)
{
debug_assert(i == values.size());
values.push_back(t);
return values.back();
}
template<typename ... Args>
T &emplace(const DictionaryIndex &i, Args&& ... args)
{
if (i != values.size())
debug_throw(io::Exception("Dictionary failure"));
values.emplace_back(std::forward<Args>(args)...);
return values.back();
}
} ;
using DictionaryOutStandard = DictionaryOut<Str>;
using DictionaryInStandard = DictionaryIn<Str>;
} // namespace

619
tjp/core/io/bin/in.h Normal file
View File

@@ -0,0 +1,619 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "in_fwd.h"
#include "../IO+config.h"
#include "Debug.h"
#include "../Exception.h"
#include <tjp/core/algorithm/mem_copy.hpp>
#include <tjp/core/types/Types.h>
#include <tjp/core/type_traits/is_mappish.hpp>
#include <tjp/core/type_traits/is_string.hpp>
#include <tjp/core/type_traits/is_iterable.hpp>
#include <tjp/core/type_traits/always_false.hpp>
#include <tjp/core/assert/debug_assert.h>
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <memory.h>
#include <typeinfo>
#include <tjp/core/ptr/Ptr.hpp>
#include <tjp/core/system/System.h>
namespace tjp::core::io::bin {
template<typename IO, typename T>
void io_bin_r(IO &io, T &t);
template<typename IO, typename T>
void io_bin_r_dispatch(IO &io, T &t);
inline
void readFrom(std::istream &f, char *v, size_t size)
{
f.read(v, size);
}
struct memory_in {
const char *block;
size_t size;
size_t position;
memory_in(const Vector<char> &v) : block(v.data()), size(v.size()), position(0) {}
memory_in(const char *block_, size_t size_) : block(block_), size(size_), position(0) {}
bool eof() const {
return position >= size;
}
bool good() const {
return !eof();
}
} ;
inline
void validate_read_size(memory_in &f, size_t size)
{
if (size > f.size || f.position > f.size - size)
{
debug_throw(io::Exception ("Buffer underflow"));
}
}
inline
auto skip(memory_in &f, size_t size)
{
validate_read_size(f, size);
auto *result = f.block + f.position;
f.position += size;
return result;
}
inline
void readFrom(memory_in &f, char *v, size_t size)
{
auto *start = skip(f, size);
core::mem_copy(v, start, size);
}
struct ReaderEmptyBaseClass {
template<typename IO, typename T>
void dispatch_custom(IO &io, T &t) {}
} ;
struct ReaderAllocatorDefault
{
template<typename IO, typename T>
void allocate(IO &io, T &t)
{
io_ptr_allocate_default(io, t);
}
typedef std::true_type is_strong_allocator;
template<typename T, typename ... Args>
auto strong(Args && ...args)
{
return core::strong<T>(std::forward<Args>(args)...);
}
} ;
template<typename Stream_, typename Base, typename Allocator_>
class Reader : public Base
{
public:
typedef Stream_ Stream;
typedef Allocator_ Allocator;
Stream f;
typedef DictionaryInStandard Dictionary;
Dictionary dictionary;
#ifdef IO_BIN_USE_HEADER_CHECK
u8 count=0;
#endif
public:
Allocator allocator;
template<typename T>
void allocate(T &t)
{
allocator.allocate(*this, t);
}
auto partial(const Serialization &s)
{
using ReaderT = Reader<memory_in, Base, Allocator>;
return strong<ReaderT>(typename ReaderT::Stream(s.data(), s.size()), allocator);
}
public:
Reader (Stream &&f_, Allocator allocator) :
f(std::move(f_)),
allocator(std::move(allocator))
{
}
Reader (Stream &&f_) :
f(std::move(f_))
{
}
Reader embed()
{
Size size;
any(size);
auto *at = skip(f, size);
return Reader(Stream(at, size), allocator);
}
operator bool() const
{
return f.good();
}
template<typename T>
void intrinsic(T &t)
{
read(t);
}
template<typename T>
void intrinsic_string(T &t)
{
read_string(t);
}
template<typename T>
void any(T &t)
{
dispatch_any(t);
}
template<typename T>
void any(T &&t)
{
dispatch_any(t);
}
template<typename ... T>
void all(T&&... t)
{
begin();
all_(t...);
end();
}
template<typename ... T>
void object(T&&... t)
{
object_begin();
object_(t...);
object_end();
}
void object_begin()
{
begin();
}
void object_k(KeyType) {};
template<typename ... T>
void object_kv(T&&... t)
{
object_(t...);
}
void object_end()
{
end();
}
template<typename ... T>
void array(T&&... t)
{
begin();
array_(t...);
end();
}
template<typename T>
void on_dispatch_any(T &t)
{
on_any(t);
}
template<typename T>
void on_dispatch_custom(T &t)
{
Base::dispatch_custom(*this, t);
}
protected:
// ----- read
void read(char *data, size_t size)
{
readFrom(f, data, size);
}
void validateRead (size_t size)
{
validate_read_size(f, size);
}
template<typename T>
void read(T &t)
{
read((char *)&t, sizeof(T));
}
template<typename T>
inline void read_string(T &t)
{
DictionaryIndex index;
any(index);
if (dictionary.has(index))
{
t = T(dictionary.get(index));
}
else
{
Size size;
any(size);
validateRead(size);
t = T(size, 0);
read((char *)t.data(), size);
auto *begin = (char *)t.data();
auto *end = begin + size;
dictionary.emplace(index, begin, end);
}
IO_BIN_LOG("read " << t);
}
// ----- dispatch out and in
template<typename T>
void dispatch_any(T &t)
{
IO_BIN_LOG("one " << type_id<T>().name());
io_bin_r_dispatch(*this, t);
}
void begin ()
{
#ifdef IO_BIN_USE_HEADER_CHECK
u8 c;
read(c);
++count;
debug_assert(c == count);
#endif
}
void end ()
{
#ifdef IO_BIN_USE_HEADER_CHECK
u8 c;
read(c);
debug_assert(c == count);
--count;
#endif
}
// -- handling different containers --
public:
template<typename T>
void any_no_ref(T v)
{
any(v);
}
Size array_begin()
{
Size s;
any(s);
return s;
}
void array_end()
{
}
template<typename T>
void on_vector_begin(T &t)
{
Size s = array_begin();
t = std::move(T(s));
}
template<typename T>
void on_vector_end (T &t)
{
array_end();
}
template<typename T>
void on_vector_value(T &t)
{
any(t);
}
auto map_begin()
{
Size s;
any(s);
return s;
}
template<typename K, typename F>
void map_values(Size s, F &&f)
{
IO_BIN_LOG("map " << type_id<T>().name());
for (auto i=0; i<s; ++i)
{
K key;
any(key);
f(key);
}
}
void map_end()
{
}
template<typename F>
void array_values(size_t size, F &&fun)
{
for (auto i=0;i<size;++i)
fun();
}
protected:
template<typename T>
void on_vector(T &t)
{
IO_BIN_LOG("many " << type_id<T>().name());
on_vector_begin(t);
for (auto &v : t)
on_vector_value(v);
on_vector_end(t);
}
void on_vector(std::vector<bool> &t)
{
typedef std::vector<bool> T;
IO_BIN_LOG("many " << type_id<T>().name());
on_vector_begin(t);
for (auto i = t.begin(); i!=t.end(); ++i)
any_no_ref<typename T::iterator::reference>(*i);
on_vector_end(t);
}
template<typename V, typename T>
void on_set(T &t)
{
IO_BIN_LOG("set " << type_id<T>().name());
Size s;
any(s);
for (auto i=0; i<s; ++i)
{
V v;
any(v);
t.insert(std::move(v));
}
}
template<typename T>
void on_map(T &t)
{
IO_BIN_LOG("map " << type_id<T>().name());
Size s;
any(s);
for (auto i=0; i<s; ++i)
{
typename T::key_type key;
any(key);
typename T::mapped_type value;
any(value);
t.emplace(key, value);
}
}
template<typename T>
void on_optional(T &t)
{
IO_BIN_LOG("map " << type_id<T>().name());
bool s;
any(s);
if (s)
{
t.emplace();
any(*t);
}
}
// -- dispatching different containers --
template<typename T, typename std::enable_if<!is_iterable<T>::value || is_string<T>::value, T>::type* = nullptr>
void on_any(T &t)
{
io_dispatch_failed(*this, t);
}
template<typename V, typename S>
void on_any(std::set<V, S> &t)
{
on_set<V>(t);
}
template<typename T, typename std::enable_if<is_iterable<T>::value && !is_mappish<T>::value && !is_string<T>::value, T>::type* = nullptr>
void on_any(T &t)
{
on_vector(t);
}
template<typename T, typename std::enable_if<is_iterable<T>::value && is_mappish<T>::value, T>::type* = nullptr>
void on_any(T &t)
{
on_map(t);
}
template<typename T>
void on_any(std::optional<T> &t)
{
on_optional(t);
}
// void on_any(variant::Variant &t)
// {
// on_variant(t);
// }
//
// -- handling all --
template<typename T>
void all_(T &t)
{
any(t);
}
template<typename ...Args>
void all_(Args&& ...args)
{
call_expand_1(
[&](auto && ...args) { any(std::forward<decltype(args)>(args)...); },
std::forward<Args>(args)...
);
}
// ---- handling object array ----
void object_()
{
}
template<typename T>
void object__(KeyType, T &t)
{
any(t);
}
template<typename ...Args>
void object_(Args&& ...args)
{
call_expand_2(
[&](auto && ...args) { object__(std::forward<decltype(args)>(args)...); },
std::forward<Args>(args)...
);
}
template<typename T>
void array__(T &t)
{
any(t);
}
template<typename ...Args>
void array_(Args&& ...args)
{
call_expand_1(
[&](auto && ...args) { array__(std::forward<decltype(args)>(args)...); },
std::forward<Args>(args)...
);
}
public:
bool null ()
{
return f.is_null();
}
template<typename T>
Optional<T> optional(T &t, bool write=true)
{
return io::bin::optional(t, write);
}
template<typename T, typename B>
Pointer<B, T> pointer(B &b)
{
return io::bin::Pointer<B, T> { &b };
}
template<typename T>
Custom<T> custom(T &t)
{
return Custom<T> { &t };
}
} ;
// -----------------------
template<typename T, typename Reader>
void deserializeFrom (Reader &reader, T &t);
template<typename T, typename Reader>
T deserializeFrom (Reader &reader);
template<typename R, typename T, typename Allocator>
T deserialize (const Serialization &data, Allocator);
template<typename R, typename T>
T deserialize (const Serialization &data);
template<typename T>
T deserialize (const Serialization &data);
template<typename T>
void deserialize (const Serialization &data, T &t);
template<typename T>
void fromFile (const std::string &fileName, T &t);
} // namespace
#include "in.inl"

86
tjp/core/io/bin/in.inl Normal file
View File

@@ -0,0 +1,86 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "IO.h"
namespace tjp::core::io::bin {
template<typename IO, typename T>
void io_bin_r(IO &io_, T &t)
{
if constexpr (has_io_bin<IO, T>::value)
{
io_bin(io_, t);
}
else
{
io_r(io_, t);
}
}
template<typename IO, typename T>
void io_bin_r_dispatch(IO &io_, T &t)
{
io_bin_r(io_, t);
}
template<typename T, typename Reader>
void deserializeFrom (Reader &reader, T &t)
{
reader.any(t);
}
template<typename T, typename Reader>
T deserializeFrom (Reader &reader)
{
T t;
deserializeFrom(reader, t);
return t;
}
template<typename R, typename T, typename Allocator>
T deserialize (const Serialization &data, Allocator allocator)
{
R reader(typename R::Stream(data.data(), data.size()), allocator);
return deserializeFrom<T>(reader);
}
template<typename R, typename T>
T deserialize (const Serialization &data)
{
R reader(typename R::Stream(data.data(), data.size()));
return deserializeFrom<T>(reader);
}
template<typename R, typename T>
void deserialize (const Serialization &data, T &t)
{
R reader(typename R::Stream(data.data(), data.size()));
deserializeFrom<T>(reader, t);
}
template<typename T>
T deserialize (const Serialization &data)
{
return deserialize<Reader<memory_in>, T>(data);
}
template<typename T>
T deserialize (const Serialization::value_type *begin, size_t size)
{
using R = Reader<memory_in>;
R reader(typename R::Stream(begin, size));
return deserializeFrom<T>(reader);
}
template<typename T>
void deserialize (const Serialization &data, T &t)
{
deserialize<Reader<memory_in>, T>(data, t);
}
} // namespace

View File

@@ -0,0 +1,18 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include <fstream>
namespace tjp::core::io::bin {
template<typename T>
void fromFile (const std::string &fileName, T &t)
{
Reader<std::ifstream> reader(fileName.c_str(), std::ios::binary);
reader.any(t);
}
} // namespace

16
tjp/core/io/bin/in_fwd.h Normal file
View File

@@ -0,0 +1,16 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
namespace tjp::core::io::bin {
struct memory_in;
struct ReaderEmptyBaseClass;
struct ReaderAllocatorDefault;
template<typename Stream_, typename Base=ReaderEmptyBaseClass, typename Allocator_=ReaderAllocatorDefault>
class Reader;
} // namespace

26
tjp/core/io/bin/json.inl Normal file
View File

@@ -0,0 +1,26 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include <vector>
namespace nlohmann {
template<typename IO>
void io_bin_w(IO &io, const json &j)
{
auto cbor = json::to_cbor(j);
io.all(cbor);
}
template<typename IO>
void io_bin_r(IO &io, json &j)
{
std::vector<unsigned char> v;
io.all(v);
j = json::from_cbor(v);
}
} // namespace

543
tjp/core/io/bin/out.h Normal file
View File

@@ -0,0 +1,543 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "out_fwd.h"
#include "../IO+config.h"
#include "Debug.h"
#include <tjp/core/string/Str.hpp>
#include <tjp/core/algorithm/mem_copy.hpp>
#include <tjp/core/rtti/RTTI.hpp>
namespace tjp::core::io::bin {
template<typename IO, typename T>
void io_bin_w(IO &io, const T &t);
template<typename IO, typename T>
void io_bin_w_dispatch(IO &io, const T &t);
inline
void writeTo(std::ostream &f, const char *v, size_t size)
{
f.write(v, size);
}
struct memory_out_ptr
{
using Block = std::vector<char>;
Block *block;
memory_out_ptr(Block *block_) :
block(block_)
{
}
Block &serialization ()
{
return *block;
}
} ;
template<size_t InitialSize>
struct memory_out_sized
{
using Block = std::vector<char>;
Block block;
memory_out_sized(Block &&block_) :
block(block_)
{
}
memory_out_sized()
{
block.reserve(InitialSize);
}
Block &serialization ()
{
return block;
}
} ;
using memory_out = memory_out_sized<4096>;
inline
auto serialization_of(memory_out &m)
{
return m.serialization();
}
inline
auto serialization_of(memory_out_ptr &m)
{
return m.serialization();
}
inline
auto serialization_of(std::ostream &f) {}
inline
void writeTo(memory_out_ptr &f, const char *v, size_t size)
{
auto then = f.block->size();
f.block->resize(then + size);
core::mem_copy(f.block->data() + then, v, size);
}
inline
void writeTo(memory_out &f, const char *v, size_t size)
{
auto then = f.block.size();
f.block.resize(then + size);
core::mem_copy(f.block.data() + then, v, size);
}
// ------------------------
struct EmptyWriterBaseClass {
template<typename IO, typename T>
void dispatch_custom(IO &io, T &t) {}
} ;
struct WriterAllocatorBase {
template<typename T>
void allocate(T &t)
{
io_ptr_allocate_default(*this, t);
}
} ;
template<typename S, typename Base, typename Allocator>
class Writer :
public Base,
public Allocator
{
public:
S f;
typedef DictionaryOutStandard Dictionary;
Dictionary dictionary;
#ifdef IO_BIN_USE_HEADER_CHECK
u8 count=0;
#endif
public:
auto partial()
{
return Writer<memory_out, Base>();
}
auto serialization ()
{
return serialization_of(f);
}
auto partial_serialization ()
{
return serialization();
}
public:
template<class... Args>
Writer (Args&&... args) :
f(args...)
{
}
void embed(Writer &writer)
{
any(writer.f.serialization());
}
operator bool() const
{
return f.good();
}
template<typename T>
void intrinsic(const T &t)
{
write(t);
}
template<typename T>
void intrinsic_string(const T &t)
{
write_string(t);
}
void intrinsic(const char *memory, size_t size)
{
write(memory, size);
}
template<typename T>
void any(const T &t)
{
dispatch_any(t);
}
template<typename ... T>
void all(T&&... t)
{
begin();
all_(t...);
end();
}
template<typename ... T>
void object(T&&... t)
{
object_begin();
object_(t...);
object_end();
}
void object_begin()
{
begin();
}
void object_k(KeyType) {};
template<typename ... T>
void object_kv(T&&... t)
{
object_(t...);
}
void object_end()
{
end();
}
auto map_begin(Size size)
{
begin();
any(size);
return size;
}
template<typename K, typename F>
void map_value_with(const K &key, F &&f)
{
any(key);
f();
}
template<typename K, typename V>
void map_value(const K &key, const V &value)
{
any(key);
any(value);
}
void map_end()
{
end();
}
template<typename ... T>
void array(T&&... t)
{
begin();
array_(t...);
end();
}
template<typename T>
void on_dispatch_any(const T &t)
{
on_any(t);
}
template<typename T>
void on_dispatch_custom(T &t)
{
Base::dispatch_custom(*this, t);
}
protected:
template<typename T>
void dispatch_any(const T &t)
{
IO_BIN_LOG("any " << type_id<T>().name());
io_bin_w_dispatch(*this, t);
}
void begin()
{
#ifdef IO_BIN_USE_HEADER_CHECK
write(++count);
#endif
}
void end()
{
#ifdef IO_BIN_USE_HEADER_CHECK
write(count--);
#endif
}
void write(const char *data, size_t size)
{
writeTo(f, data, size);
}
template<typename T>
void write(const T &t)
{
IO_BIN_LOG("write " << t);
write((const char *)&t, sizeof(T));
}
template<typename T>
inline void write_string(const T &t)
{
auto [index, should_write] = dictionary.on(t);
any(index);
if (should_write)
{
any((Size)t.size());
write(t.data(), t.size());
}
}
// -- handling different containers --
public:
auto array_begin(Size s)
{
any(s);
return s;
}
void array_end()
{
}
template<typename T>
void on_vector_begin (const T &t)
{
array_begin((Size)t.size());
}
template<typename T>
void on_vector_end (const T &t)
{
array_end();
}
template<typename T>
void on_vector_value(const T &t)
{
any(t);
}
protected:
template<typename T>
void on_vector(const T &t)
{
IO_BIN_LOG("many " << type_id<T>().name());
on_vector_begin(t);
// this fails for std::vector<bool> on some platforms, because vector bool
// does some magic to compress to a bit field, and then the iterator
// doesn't pass back a reference
// for (const auto &v : t)
// any(v);
for (auto i = t.begin(); i!=t.end(); ++i)
on_vector_value(*i);
on_vector_end(t);
}
void on_vector(const std::vector<u8> &t)
{
any((Size)t.size());
intrinsic((char *)t.data(), t.size());
}
void on_vector(const std::vector<s8> &t)
{
any((Size)t.size());
intrinsic((char *)t.data(), t.size());
}
void on_vector(const std::vector<char> &t)
{
any((Size)t.size());
intrinsic((char *)t.data(), t.size());
}
template<typename T>
void on_map(const T &t)
{
IO_BIN_LOG("map " << type_id<T>().name());
any((Size)t.size());
for (const auto &v : t)
{
any(v.first);
any(v.second);
}
}
template<typename T>
void on_optional(const T &t)
{
bool s = t.has_value();
any(s);
if (s)
{
any(*t);
}
}
// -- dispatching different containers --
template<typename T, typename std::enable_if<!is_iterable<T>::value || is_string<T>::value, T>::type* = nullptr>
void on_any(const T &t)
{
io_dispatch_failed(*this, t);
}
template<typename T, typename std::enable_if<is_iterable<T>::value && !is_mappish<T>::value && !is_string<T>::value, T>::type* = nullptr>
void on_any(const T &t)
{
on_vector(t);
}
template<typename T, typename std::enable_if<is_iterable<T>::value && is_mappish<T>::value, T>::type* = nullptr>
void on_any(const T &t)
{
on_map(t);
}
template<typename T>
void on_any(const std::optional<T> &t)
{
on_optional(t);
}
// void on_any(const variant::Variant &t)
// {
// on_variant(t);
// }
//
// ---- handling all ----
template<typename T>
void all_(const T &t)
{
any(t);
}
template<typename T, typename ... Rest>
void all_(const T &t, Rest&&... rest)
{
any(t);
all_(rest...);
}
// ---- handling object array ----
void object_()
{
}
template<typename T>
void object__(KeyType, const T &t)
{
any(t);
}
template<typename ...Args>
void object_(Args&& ...args)
{
call_expand_2(
[&](auto && ...args) { object__(std::forward<decltype(args)>(args)...); },
std::forward<Args>(args)...
);
}
template<typename T>
void array__(const T &t)
{
any(t);
}
template<typename ...Args>
void array_(Args&& ...args)
{
call_expand_1(
[&](auto && ...args) { array__(std::forward<decltype(args)>(args)...); },
std::forward<Args>(args)...
);
}
public:
// ----- miscellaneous -----
template<typename T>
Optional<T> optional(T &t, bool write=true)
{
return io::bin::optional(t, write);
}
template<typename T, typename B, typename std::enable_if<!std::is_class<T>::value, T>::type* = nullptr>
Pointer<B, T> pointer(B &b)
{
return io::bin::Pointer<B, T> {
&b, b != nullptr
};
}
template<typename T, typename B, typename std::enable_if<std::is_class<T>::value, T>::type* = nullptr>
Pointer<B, T> pointer(B &b)
{
return io::bin::Pointer<B, T> {
&b, dynamic_cast_ptr<T>(b) != nullptr
};
}
template<typename T>
Custom<T> custom(const T &t)
{
return Custom<T> { const_cast<T*>(&t) };
}
} ;
// ----------
template<typename W, typename T>
Serialization serialize (const T &t);
template<typename T>
Serialization serialize (const T &t);
template<typename T>
void serializeTo (Serialization &serialization, const T &t);
template<typename W, typename T>
Serialization serializeTo(W &w, const T &t);
template<typename T>
void toFile (const std::string &fileName, const T &t);
} // namespace
#include "out.inl"

65
tjp/core/io/bin/out.inl Normal file
View File

@@ -0,0 +1,65 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "IO.h"
namespace tjp::core::io::bin {
template<typename IO, typename T>
void io_bin_w(IO &io_, const T &t)
{
typedef typename std::remove_const<T>::type TC;
if constexpr (has_io_bin<IO, T>::value)
{
auto &t_ = *const_cast<TC *>(&t);
io_bin(io_, t_);
}
else
{
io_w(io_, t);
}
}
template<typename IO, typename T>
void io_bin_w_dispatch(IO &io_, const T &t)
{
io_bin_w(io_, t);
}
template<typename W, typename T>
Serialization serialize (const T &t)
{
W writer;
writer.any(t);
return std::move(writer.serialization());
}
template<typename T>
Serialization serialize (const T &t)
{
return serialize<Writer<memory_out>>(t);
}
template<typename T>
void serializeTo (Serialization &serialization, const T &t)
{
memory_out bout { std::move(serialization) };
Writer<memory_out> writer(bout);
writer.any(t);
serialization = writer.serialization();
}
template<typename W, typename T>
Serialization serializeTo(W &w, const T &t)
{
w.any(t);
return w.serialization();
}
} // namespace

View File

@@ -0,0 +1,18 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include <fstream>
namespace tjp::core::io::json {
template<typename T>
void toFile (const std::string &fileName, const T &t)
{
Writer<std::ofstream> writer(fileName.c_str(), std::ios::binary);
writer.any(t);
}
} // namespace

23
tjp/core/io/bin/out_fwd.h Normal file
View File

@@ -0,0 +1,23 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include <stddef.h>
namespace tjp::core::io::bin {
template<size_t InitialSize>
struct memory_out_sized;
using memory_out = memory_out_sized<4096>;
struct EmptyWriterBaseClass;
struct WriterAllocatorBase;
template<typename S, typename Base=EmptyWriterBaseClass, typename Allocator=WriterAllocatorBase>
class Writer;
} // namespace

38
tjp/core/io/calls.hpp Executable file
View File

@@ -0,0 +1,38 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include <tuple>
#include <utility>
namespace tjp::core::io {
template<typename F, typename... Args>
void call_f_1s(F&& f, Args&&... args) {
(f(std::forward<Args>(args)), ...);
}
template<typename F, typename Tuple, std::size_t... I>
void call_f_2s_(F &&f, Tuple&& tup, std::index_sequence<I...>) {
(f(
std::forward<decltype(std::get<I * 2>(std::forward<Tuple>(tup)))>(
std::get<I * 2>(std::forward<Tuple>(tup))),
std::forward<decltype(std::get<I * 2 + 1>(std::forward<Tuple>(tup)))>(
std::get<I * 2 + 1>(std::forward<Tuple>(tup)))
), ...);
}
template<typename F, typename... Args>
void call_f_2s(F &&f, Args&&... args)
{
static_assert(sizeof...(Args) % 2 == 0, "Arguments must be in key-value pairs");
auto args_tuple = std::forward_as_tuple(std::forward<Args>(args)...);
constexpr std::size_t N = sizeof...(Args) / 2;
call_f_2s_(std::forward<F>(f), args_tuple, std::make_index_sequence<N>{});
}
} // namespace

227
tjp/core/io/json/IO.h Normal file
View File

@@ -0,0 +1,227 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "../IO.h"
#include "../IO_dispatch.h"
#include "../IO_.h"
#include "../IO+config.h"
#include <tjp/core/types/Types.h>
#include <tjp/core/type_traits/is_mappish.hpp>
#include <tjp/core/type_traits/is_string.hpp>
#include <tjp/core/type_traits/is_iterable.hpp>
#include <tjp/core/string/to_string.h>
#include <tjp/core/assert/debug_assert.h>
#include <tjp/core/string/to_string.hpp>
#include <tjp/core/string/from_string.hpp>
#include <tjp/core/system/System.h>
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <list>
#include <optional>
//#ifdef DEBUG
//#define IO_JSON_LOG std::cerr
//#else
#define IO_JSON_LOG if(false) std::cout
//#endif
//#define IO_JSON_USE_LARGE_NUMBER_PROXY
namespace tjp::core::io::json {
using Size = u32;
typedef std::vector<char> Serialization;
// detects whether there is an appropriate intermediate
// io function
template <typename IO, typename T, typename = void>
struct has_io_json : std::false_type {};
template <typename IO, typename T>
struct has_io_json<IO, T,
std::void_t<decltype(io_json(std::declval<IO&>(),
std::declval<T&>())) >> : std::true_type {};
template<typename IO> void io_json(IO &io, bool &t) { io.intrinsic(t); }
template<typename IO> void io_json(IO &io, u8 &t) { io.intrinsic(t); }
template<typename IO> void io_json(IO &io, u16 &t) { io.intrinsic(t); }
template<typename IO> void io_json(IO &io, u32 &t) { io.intrinsic(t); }
template<typename IO> void io_json(IO &io, u64 &t) { io.intrinsic(t); }
template<typename IO> void io_json(IO &io, u128 &t) { io.intrinsic(t); }
template<typename IO> void io_json(IO &io, s8 &t) { io.intrinsic(t); }
template<typename IO> void io_json(IO &io, char &t) { io.intrinsic(t); }
template<typename IO> void io_json(IO &io, s16 &t) { io.intrinsic(t); }
template<typename IO> void io_json(IO &io, s32 &t) { io.intrinsic(t); }
template<typename IO> void io_json(IO &io, s64 &t) { io.intrinsic(t); }
template<typename IO> void io_json(IO &io, s128 &t) { io.intrinsic(t); }
template<typename IO> void io_json(IO &io, r32 &t) { io.intrinsic(t); }
template<typename IO> void io_json(IO &io, r64 &t) { io.intrinsic(t); }
template<typename IO> void io_json(IO &io, r128 &t) { io.intrinsic(t); }
template<typename IO> void io_json(IO &io, std::string &t) { io.intrinsic(t); }
template<typename IO> void io_json(IO &io, std::string_view &t) { io.intrinsic(t); }
#if defined(SYS_MAC) || defined(SYS_IOS)
template<typename IO> void io_json(IO &io, unsigned long &t) { io.intrinsic(t); }
template<typename IO> void io_json(IO &io, signed long &t) { io.intrinsic(t); }
#endif
template<typename T>
struct Optional
{
T &v;
bool write;
} ;
template<typename T>
Optional<T> optional(T &t, bool write=true) { return Optional<T> { t, write }; }
template<typename IO, typename T>
void io_json(IO &io, Optional<T> &t)
{
static_assert(always_false<T>::value, "this should not be dispatched to");
}
template<typename P, typename T>
struct Pointer
{
P *p;
bool write;
} ;
typedef const char *KeyType;
template<typename IO, typename T>
void io_ptr_allocate(IO &io, T *&t)
{
io.allocate(t);
}
template<typename IO, typename T>
void io_ptr_allocate_default(IO &io, T *&t)
{
t = new T();
}
template<typename IO, typename P, typename T>
void io_json(IO &io, Pointer<P, T> &t)
{
io.object("ptr", t);
}
template<typename IO, typename T>
void io_json(IO &io, T *&t)
{
auto p = io.template pointer<T>(t);
io.any(p);
}
template<typename T>
struct AsKeyType {
std::string value;
AsKeyType (const T &t)
{
value = core::to_string(t);
}
operator KeyType()
{
return value.c_str();
}
} ;
template<>
struct AsKeyType<std::string> {
const std::string &value;
AsKeyType (const std::string &value_) :
value(value_)
{
}
operator KeyType()
{
return value.c_str();
}
} ;
template<>
struct AsKeyType<KeyType> {
KeyType value;
AsKeyType (KeyType value_) :
value(value_)
{
}
operator KeyType()
{
return value;
}
} ;
template<typename T>
AsKeyType<T> asKeyType(const T &t)
{
return AsKeyType<T>(t);
}
template<typename T>
struct Custom
{
T *p;
} ;
template<typename IO, typename T>
void io_json(IO &io, Custom<T> &t)
{
io.template dispatch_custom<>(io, *t.p);
}
template<typename IO, typename ...T>
void io_json(IO &io, std::tuple<T...> &t)
{
io.tuple(t);
}
//#ifdef SYS_APPLE
// std::vector<bool> fixes
template<typename IO>
void io_json_w(IO &io, const std::vector<bool>::const_iterator::reference t)
{
bool b = t;
io.intrinsic(b);
}
template<typename IO>
void io_json_r(IO &io, std::vector<bool>::iterator::reference &t)
{
bool b;
io.intrinsic(b);
t = b;
}
//#endif
} // namespace

View File

@@ -0,0 +1,415 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#include <tjp/core/io/json/IO.h>
#include <tjp/core/io/json/in_sajson.h>
#include <tjp/core/io/json/out.h>
#include <tjp/core/io/IO_encoder.h>
#include <tjp/core/testing/catch.hpp>
namespace tjp::core::io_json_test {
struct VS {
int x;
} ;
bool operator ==(const VS &l, const VS &r)
{
return l.x == r.x;
}
std::ostream &operator <<(std::ostream &o, const VS &v)
{
return o << v.x;
}
std::istream &operator >>(std::istream &i, VS &v)
{
return i >> v.x;
}
struct VV : std::vector<int>
{
} ;
template<typename IO>
void io_json(IO &io, VV &v)
{
std::string b = "b";
io.object(
"a",b
);
};
struct A {
bool w;
int x;
std::string s;
u64 _u64;
s64 _s64;
u128 _u128;
s128 _s128;
std::vector<int> y;
std::vector<std::vector<int>> z;
std::vector<int> v_b;
VS v_s;
bool operator ==(const A &rhs) const
{
return
w == rhs.w &&
x == rhs.x &&
y == rhs.y &&
z == rhs.z &&
s == rhs.s &&
v_b == rhs.v_b &&
v_s == rhs.v_s &&
_u64 == rhs._u64 &&
_s64 == rhs._s64 &&
_u128 == rhs._u128 &&
_s128 == rhs._s128
;
}
} ;
struct B {
int i;
} ;
struct C {
s32 i32;
u32 u32;
s64 i64;
u64 u64;
s128 i128;
u128 u128;
bool operator ==(const C &rhs) const
{
return
i32 == rhs.i32 &&
u32 == rhs.u32 &&
i64 == rhs.i64 &&
u64 == rhs.u64 &&
i128 == rhs.i128 &&
u128 == rhs.u128
;
}
} ;
template<typename IO>
void io_json(IO &io, C &a)
{
io.object(
"i32", a.i32,
"u32", a.u32,
"i64", a.i64,
"u64", a.u64,
"i128", a.i128,
"u128", a.u128
);
};
template<typename IO>
void io_json(IO &io, A &a)
{
io.object(
"w", a.w,
"x", a.x,
"y", a.y,
"z", a.z,
"s", a.s,
"_u64", a._u64,
"_s64", a._s64,
"_u128", a._u128,
"_s128", a._s128,
"v_b", makeBinaryEncoder(a.v_b),
"v_s", makeStringEncoder(a.v_s)
);
}
template<typename T>
T make_number()
{
T t;
char *b = (char *)&t;
auto *e = b + sizeof(T);
int i=1;
for (char *v=b; v!=e; ++v)
*v = i++;
return t;
}
SCENARIO("io json serialization", "[core::io]" )
{
GIVEN("a custom array with serializer")
{
auto v = VV();
auto vs = io::json::serialize(v);
auto vss = String(vs.begin(), vs.end());
REQUIRE(vss == "{\"a\":\"b\"}");
auto vs0 = io::json::deserialize<VV>(vs);
REQUIRE(vs0.empty());
}
GIVEN("a simple structure")
{
auto check_each = [](C &c) {
auto vi32_ = io::json::deserialize<decltype(c.i32)>(io::json::serialize(c.i32));
auto vi64_ = io::json::deserialize<decltype(c.i64)>(io::json::serialize(c.i64));
auto vi128_ = io::json::deserialize<decltype(c.i128)>(io::json::serialize(c.i128));
auto vu32_ = io::json::deserialize<decltype(c.u32)>(io::json::serialize(c.u32));
auto vu64_ = io::json::deserialize<decltype(c.u64)>(io::json::serialize(c.u64));
auto vu128_ = io::json::deserialize<decltype(c.u128)>(io::json::serialize(c.u128));
REQUIRE(vi32_ == c.i32);
REQUIRE(vi64_ == c.i64);
REQUIRE(vi128_ == c.i128);
REQUIRE(vu32_ == c.u32);
REQUIRE(vu64_ == c.u64);
REQUIRE(vu128_ == c.u128);
} ;
WHEN("interesting numbers 1")
{
C c = {
.i32 = 0,
.u32 = 0,
.i64 = 0,
.u64 = 0,
.i128 = 0,
.u128 = 0
};
auto sc = io::json::serialize(c);
auto c_ = io::json::deserialize<C>(std::move(sc));
bool same = c == c_;
REQUIRE(same);
check_each(c);
}
WHEN("interesting numbers max")
{
C c = {
.i32 = std::numeric_limits<s32>::max(),
.u32 = std::numeric_limits<u32>::max(),
.i64 = std::numeric_limits<s64>::max(),
.u64 = std::numeric_limits<u64>::max(),
.i128 = std::numeric_limits<s128>::max(),
.u128 = std::numeric_limits<u128>::max()
};
auto sc = io::json::serialize(c);
auto c_ = io::json::deserialize<C>(std::move(sc));
bool same = c == c_;
REQUIRE(same);
check_each(c);
}
WHEN("interesting numbers min")
{
C c = {
.i32 = std::numeric_limits<s32>::min(),
.u32 = std::numeric_limits<u32>::min(),
.i64 = std::numeric_limits<s64>::min(),
.u64 = std::numeric_limits<u64>::min(),
.i128 = std::numeric_limits<s128>::min(),
.u128 = std::numeric_limits<u128>::min()
};
auto sc = io::json::serialize(c);
auto sc_ = std::string(sc.begin(), sc.end());
auto c_ = io::json::deserialize<C>(std::move(sc));
bool same = c == c_;
REQUIRE(same);
check_each(c);
}
WHEN("interesting numbers max-1")
{
C c = {
.i32 = std::numeric_limits<s32>::max()-1,
.u32 = std::numeric_limits<u32>::max()-1,
.i64 = std::numeric_limits<s64>::max()-1,
.u64 = std::numeric_limits<u64>::max()-1,
.i128 = std::numeric_limits<s128>::max()-1,
.u128 = std::numeric_limits<u128>::max()-1
};
auto sc = io::json::serialize(c);
auto c_ = io::json::deserialize<C>(std::move(sc));
bool same = c == c_;
REQUIRE(same);
check_each(c);
}
WHEN("interesting numbers min+1")
{
C c = {
.i32 = std::numeric_limits<s32>::min()+1,
.u32 = std::numeric_limits<u32>::min()+1,
.i64 = std::numeric_limits<s64>::min()+1,
.u64 = std::numeric_limits<u64>::min()+1,
.i128 = std::numeric_limits<s128>::min()+1,
.u128 = std::numeric_limits<u128>::min()+1
};
auto sc = io::json::serialize(c);
auto c_ = io::json::deserialize<C>(std::move(sc));
bool same = c == c_;
REQUIRE(same);
check_each(c);
}
WHEN("interesting numbers max+1")
{
C c = {
.i32 = std::numeric_limits<s16>::max()+1,
.u32 = std::numeric_limits<u16>::max()+1,
.i64 = s64(std::numeric_limits<s32>::max())+1,
.u64 = u64(std::numeric_limits<u32>::max())+1,
.i128 = s128(std::numeric_limits<s64>::max())+1,
.u128 = u128(std::numeric_limits<u64>::max())+1
};
auto sc = io::json::serialize(c);
auto c_ = io::json::deserialize<C>(std::move(sc));
bool same = c == c_;
REQUIRE(same);
check_each(c);
}
}
GIVEN("a structure")
{
A a = {
true, 13,
std::string("hi"),
make_number<u64>(), make_number<s64>(),
make_number<u128>(), make_number<s128>(),
{ 2, 3, 4 },
{ { 1, 2, 3 }, { 4, 5, 6 }},
{ 1, 2, 3, 4, 5, 6, 7, 8 },
{ 1 }
};
WHEN("base64 works")
{
A b;
fromBase64(toBase64((char *)&a._s128, sizeof(a._s128)), (char *)&b._s128, sizeof(b._s128));
fromBase64(toBase64((char *)&a._u128, sizeof(a._u128)), (char *)&b._u128, sizeof(b._u128));
fromBase64(toBase64((char *)&a._s64, sizeof(a._s64)), (char *)&b._s64, sizeof(b._s64));
fromBase64(toBase64((char *)&a._u64, sizeof(a._u64)), (char *)&b._u64, sizeof(b._u64));
REQUIRE(a._s128 == b._s128);
REQUIRE(a._u128 == b._u128);
REQUIRE(a._s64 == b._s64);
REQUIRE(a._u64 == b._u64);
}
WHEN("serialize and deserialize, is same")
{
auto sa = io::json::serialize(a);
auto saX = std::string(sa.data(), sa.size());
auto a_ = io::json::deserialize<A>(std::move(sa));
bool same = a == a_;
REQUIRE(same);
auto sa2 = io::json::serialize(a_);
auto sa2X = std::string(sa2.data(), sa2.size());
REQUIRE(saX == sa2X);
}
}
GIVEN("a structure empty")
{
A a = { true, 13 };
WHEN("serialize and deserialize, is same")
{
auto sa = io::json::serialize(a);
auto a_ = io::json::deserialize<A>(std::move(sa));
bool same = a == a_;
REQUIRE(same);
}
}
GIVEN("a vector of bool")
{
typedef std::vector<bool> Bools;
Bools a { true, false, true, true };
WHEN("serialize and deserialize")
{
auto sa = io::json::serialize(a);
auto a_ = io::json::deserialize<Bools>(std::move(sa));
THEN("is same")
{
REQUIRE(a_ == a);
}
}
}
GIVEN("an empty vector")
{
typedef std::vector<int> V;
V a;
WHEN("serialize and deserialize")
{
auto sa = io::json::serialize(a);
auto a_ = io::json::deserialize<V>(std::move(sa));
THEN("is same")
{
REQUIRE(a_ == a);
}
}
}
GIVEN("an empty string")
{
typedef std::string V;
V a;
WHEN("serialize and deserialize")
{
auto sa = io::json::serialize(a);
auto a_ = io::json::deserialize<V>(std::move(sa));
THEN("is same")
{
REQUIRE(a_ == a);
}
}
}
}
} // namespace

View File

@@ -0,0 +1,39 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include <fstream>
namespace tjp::core::io::json {
template<typename T>
bool fromFile (const std::string &fileName, T &t)
{
std::ifstream inFile;
inFile.open(fileName);
if (!inFile)
return false;
fromStream(inFile, t);
return true;
}
template<typename T>
T fromFile (const std::string &fileName)
{
std::ifstream inFile;
inFile.open(fileName);
if (!inFile)
throw Exception { "File could not be opened" };
T t;
fromStream(inFile, t);
return t;
}
} // namespace

View File

@@ -0,0 +1,831 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "IO.h"
#include <iostream>
#include "../../json/sajson.h"
#include <set>
#include <tjp/core/string/from_string.h>
#include <tjp/core/io/memstream.h>
#include <tjp/core/ptr/Ptr.hpp>
#include <tjp/core/debug/Debug.h>
#include <tjp/core/rtti/RTTI.hpp>
#include "../Exception.h"
#include <tjp/core/system/System.h>
#ifdef IO_JSON_USE_LARGE_NUMBER_PROXY
#include <tjp/core/bases/Base64.h>
#endif
//#ifdef DEBUG
//#define IO_JSON_LOG std::cerr
//#else
#define IO_JSON_LOG if(false) std::cout
//#endif
namespace tjp::core::io::json {
template<typename IO, typename T>
void io_json_r(IO &io, T &t);
template<typename IO, typename T>
void io_json_r_dispatch(IO &io, T &t);
typedef const char *KeyType;
struct json_in {
Serialization underlying;
typedef const sajson::document Document;
Document document;
typedef const sajson::value Node;
struct Current {
Node node;
Current(const Node &node_) :
node(node_)
{
}
int keyIndex = 0;
bool objectKeysFound = false;
std::vector<std::string> objectKeys;
size_t array_size () {
return node.get_length();
}
const std::vector<std::string> &object_keys ()
{
if (!objectKeysFound)
{
auto length = node.get_length();
for (auto i = 0; i<length; ++i)
{
auto key = node.get_object_key(i);
objectKeys.push_back(key.as_string());
}
objectKeysFound = true;
}
return objectKeys;
}
bool isValid()
{
return node.get_type() != sajson::TYPE_NULL;
}
bool is_null ()
{
return node.get_type() == sajson::TYPE_NULL;
}
Node operator[] (int i)
{
if (i >= node.get_length())
throw Exception { "Index out of bounds" };
return node.get_array_element(i);
}
Node operator[] (const std::string &i)
{
auto key = sajson::string(i.c_str(), i.length());
auto element = node.find_object_key(key);
if (element >= node.get_length())
throw Exception { "Key does not exist" };
return node.get_object_value(element);
}
template<typename T>
T get_int()
{
T t;
if (!node.get_integer_value(t))
{
debug_assert(false);
throw Exception { "Value not convertible" };
}
return t;
}
#ifdef IO_JSON_USE_LARGE_NUMBER_PROXY
template<typename T>
T get_proxy()
{
T t;
fromBase64(
node.as_cstring(),
node.get_string_length(),
(char *)&t,
sizeof(t)
);
return t;
}
#endif
// s64 get_int64()
// {
// s64 v = -1;
// if (!node.get_int53_value(&v))
// {
// debug_assert(false);
// // throw something
// }
// return v;
// }
//
// s64 get_int128()
// {
// s64 v = -1;
// if (!node.get_int53_value(&v))
// {
// debug_assert(false);
// // throw something
// }
// return v;
// }
double get_double()
{
return node.get_number_value();
}
std::string_view get_utf8()
{
return node.as_string();
}
bool get_bool ()
{
return node.get_type() == sajson::TYPE_TRUE;
}
} ;
std::list<Current> current;
json_in(Serialization &&serialization) :
underlying(std::move(serialization)),
document(sajson::parse(
sajson::dynamic_allocation(),
sajson::mutable_string_view(underlying.size(), (char *)underlying.data())
))
{
current.emplace_back(document.get_root());
}
size_t array_size()
{
auto &doc = current.back();
return doc.array_size();
}
std::vector<std::string> object_keys()
{
auto &doc = current.back();
return doc.object_keys();
}
void key(const KeyType &key)
{
current.emplace_back(current.back()[key]);
}
// bool hasKey(const KeyType &key_)
// {
// std::string key(key_);
// auto &keys = current.back().object_keys();
// return std::find(keys.begin(), keys.end(), key) != keys.end();
// }
bool hasKeyValue(const KeyType &key_)
{
std::string key(key_);
auto &keys = current.back().object_keys();
auto i= std::find(keys.begin(), keys.end(), key);
if (i == keys.end())
return false;
return current.back()[*i].get_type() != sajson::TYPE_NULL;
}
void next_array_key()
{
auto index = current.back().keyIndex++;
current.emplace_back(current.back()[index]);
}
void endKey()
{
current.pop_back();
}
void begin_element ()
{
}
void begin_object()
{
begin_element();
}
void end_element()
{
// current.pop_back();
}
void end_object()
{
end_element();
}
void begin_array()
{
begin_element();
}
void end_array()
{
end_element();
}
void clearKey ()
{
}
template<typename V>
void v_int(V &v)
{
v = current.back().get_int<V>();
}
#ifdef IO_JSON_USE_LARGE_NUMBER_PROXY
template<typename V>
void v_proxy(V &v)
{
v = current.back().get_proxy<V>();
}
template<>
void v_int(s64 &v)
{
return v_proxy(v);
}
template<>
void v_int(u64 &v)
{
return v_proxy(v);
}
template<>
void v_int(s128 &v)
{
return v_proxy(v);
}
template<>
void v_int(u128 &v)
{
return v_proxy(v);
}
#endif
template<typename V>
void v_string(V &v)
{
v = current.back().get_utf8();
}
template<typename V>
void v_double(V &v)
{
v = current.back().get_double();
}
template<typename V>
void v_bool(V &v)
{
v = current.back().get_bool();
}
void v(u8 &v) { v_int(v); }
void v(u16 &v) { v_int(v); }
void v(u32 &v) { v_int(v); }
void v(u64 &v) { v_int(v); }
void v(u128 &v) { v_int(v); }
void v(s8 &v) { v_int(v); }
void v(char &v) { v_int(v); }
void v(s16 &v) { v_int(v); }
void v(s32 &v) { v_int(v); }
void v(s64 &v) { v_int(v); }
void v(s128 &v) { v_int(v); }
void v(r32 &v) { v_double(v); }
void v(r64 &v) { v_double(v); }
void v(r128 &v) { v_double(v); }
void v(bool &v) { v_bool(v); }
void v(std::string &v) { v_string(v); }
#if defined(SYS_MAC) || defined(SYS_IOS)
void v(unsigned long &v) { v_int(v); }
void v(signed long &v) { v_int(v); }
#endif
bool is_null()
{
return current.back().is_null();
}
} ;
// ------------------------
struct ReaderEmptyBaseClass {
template<typename IO, typename T>
void dispatch_custom(IO &io, T &t) {}
};
struct ReaderAllocatorDefault {
template<typename IO, typename T>
void allocate(IO &io, T &t)
{
io_ptr_allocate_default(io, t);
}
} ;
template<typename Stream_, typename Base=ReaderEmptyBaseClass, typename Allocator=ReaderAllocatorDefault>
class Reader : public Base
{
public:
typedef Stream_ Stream;
Stream f;
u8 count = 0;
public:
Allocator allocator;
template<typename T>
void allocate(T &t)
{
allocator.allocate(*this, t);
}
auto partial(const Serialization &s)
{
using ReaderT = Reader<json_in, Base>;
return strong<ReaderT>(std::move(Serialization(s)));
}
public:
template<class... Args>
Reader (Args&&... args) :
f(std::forward<Args>(args)...)
{
}
operator bool() const
{
return f.good();
}
template<typename T>
void intrinsic(T &t)
{
read(t);
}
template<typename T>
void intrinsic_string(T &t)
{
std::string s;
read(s);
t = s;
}
template<typename T>
void intrinsic_string(std::string &t)
{
read(t);
}
template<typename T>
void any(T &t)
{
dispatch_any(t);
}
template<typename T>
void any(T &&t)
{
dispatch_any(t);
}
template<typename ... T>
void object(T&&... t)
{
object_begin();
object_(t...);
object_end();
}
void object_begin()
{
f.begin_object();
}
template<typename F>
void object_kf(KeyType k, F &&q)
{
f.key(k);
q();
f.endKey();
};
template<typename ... T>
void object_kv(T&&... t)
{
object_(t...);
}
void object_end()
{
f.end_object();
}
template<typename ... T>
void array(T&&... t)
{
f.begin_array();
array_(t...);
f.end_array();
}
template<typename ...T>
void tuple(std::tuple<T...> &t)
{
f.begin_array();
std::apply([this](auto &...x){(av(x), ...);}, t);
f.end_array();
}
template<typename T>
void on_dispatch_any(T &t)
{
on_any(t);
}
template<typename T>
void on_dispatch_custom(T &t)
{
Base::dispatch_custom(*this, t);
}
protected:
// ----- read
template<typename T>
void read(T &t)
{
f.v(t);
}
// ----- dispatch out and in
template<typename T>
void dispatch_any(T &t)
{
IO_JSON_LOG << "dispatch_any " << type_id<T>().name() << std::endl;
io_json_r_dispatch(*this, t);
}
// kv & av -----------
template<typename V>
void kv(KeyType k, V &v)
{
f.key(k);
any(v);
f.endKey();
}
template<typename T>
void kv(KeyType k, Optional<T> &t)
{
if (f.hasKeyValue(k))
{
kv(k, t.v);
}
else
{
}
}
template<typename T>
void kv(KeyType k, std::optional<T> &t)
{
if (f.hasKeyValue(k))
{
t.emplace();
kv(k, *t);
}
else
{
}
}
template<typename B, typename T>
void kv(KeyType k, Pointer<B, T> &t)
{
if (f.hasKeyValue(k))
{
allocator.allocate(*this, *t.p);
kv(k, **t.p);
}
}
template<typename T>
void av(T &v)
{
f.next_array_key();
any(v);
f.endKey();
}
template<typename T>
void av_no_ref(T v)
{
f.next_array_key();
any(v);
f.endKey();
}
// -- handling different containers --
public:
size_t array_begin()
{
f.begin_array();
return f.array_size();
}
void array_end()
{
f.end_array();
}
template<typename T>
void on_vector_begin (T &t)
{
auto count = array_begin();
io_resize_vector(t, count);
}
template<typename T>
void on_vector_end (T &t)
{
array_end();
}
template<typename T>
void on_vector_value(T &t)
{
av(t);
}
template<typename F>
void array_values(size_t size, F &&fun)
{
for (auto i=0;i<size;++i)
fun();
}
template<typename K, typename F>
void object_values(F &&fun)
{
f.begin_object();
auto keys = f.object_keys();
for (auto &k: keys)
{
typedef K Key;
Key key = core::from_string<Key>(k);
f.key(k);
fun(k);
f.endKey();
}
f.end_object();
}
protected:
template<typename T>
void on_vector(T &t)
{
IO_JSON_LOG << "many " << type_id<T>().name() << std::endl;
on_vector_begin(t);
for (auto &v : t)
on_vector_value(v);
on_vector_end(t);
}
void on_vector(std::vector<bool> &t)
{
typedef std::vector<bool> T;
IO_JSON_LOG << "many " << type_id<T>().name() << std::endl;
on_vector_begin(t);
for (auto i = t.begin(); i!=t.end(); ++i)
av_no_ref<typename T::iterator::reference>(*i);
on_vector_end(t);
}
template<typename T>
void on_map(T &t)
{
IO_JSON_LOG << "map " << type_id<T>().name() << std::endl;
f.begin_object();
auto keys = f.object_keys();
for (auto &k: keys)
{
typedef typename T::key_type Key;
Key key = core::from_string<Key>(k);
typename T::mapped_type value;
kv(asKeyType(k), value);
t.emplace(key, value);
}
f.end_object();
}
template<typename V, typename T>
void on_set(T &t)
{
IO_JSON_LOG << "many " << type_id<T>().name() << std::endl;
f.begin_array();
auto count = f.array_size();
for (auto i=0; i<count; ++i)
{
V v;
av(v);
t.insert(v);
}
f.end_array();
}
// void on_any(variant::Variant &t)
// {
// on_variant(t);
// }
//
// -- dispatching different containers --
public:
template<typename T, typename std::enable_if<!is_iterable<T>::value || is_stringish<T>::value, T>::type* = nullptr>
void on_any(T &t)
{
io_dispatch_failed(*this, t);
}
template<typename V, typename S>
void on_any(std::set<V,S> &t)
{
on_set<V>(t);
}
template<typename T, typename std::enable_if<is_iterable<T>::value && !is_mappish<T>::value && !is_stringish<T>::value, T>::type* = nullptr>
void on_any(T &t)
{
on_vector(t);
}
template<typename T, typename std::enable_if<is_iterable<T>::value && is_mappish<T>::value, T>::type* = nullptr>
void on_any(T &t)
{
on_map(t);
}
protected:
// ---- handling object & array ----
void object_()
{
}
template<typename T>
void object__(KeyType key, T &t)
{
IO_JSON_LOG << "key " << key << std::endl;
kv(key, t);
}
template<typename ...Args>
void object_(Args&& ...args)
{
call_expand_2(
[&](auto && ...args) { object__(std::forward<decltype(args)>(args)...); },
std::forward<Args>(args)...
);
}
template<typename T>
void array__(T &t)
{
av(t);
}
template<typename ...Args>
void array_(Args&& ...args)
{
call_expand_1(
[&](auto && ...args) { array__(std::forward<decltype(args)>(args)...); },
std::forward<Args>(args)...
);
}
template<typename ...T>
void tuple_(std::tuple<T...> &t)
{
std::apply([this](auto &...x){(av(x), ...);}, t);
}
// ----- miscellaneous -----
public:
bool null ()
{
return f.is_null();
}
template<typename T>
Optional<T> optional(T &t, bool write=true)
{
return io::json::optional(t, write);
}
template<typename T, typename B>
Pointer<B, T> pointer(B &b)
{
return io::json::Pointer<B, T> { &b };
}
template<typename K>
AsKeyType<K> asKeyType(const K &k)
{
return io::json::asKeyType(k);
}
template<typename T>
Custom<T> custom(T &t)
{
return Custom<T> { &t };
}
} ;
template<typename T, typename Reader>
void deserializeFrom (Reader &reader, T &t);
template<typename T, typename Reader>
T deserializeFrom (Reader &reader);
template<typename R, typename T>
T deserialize (Serialization &&data);
template<typename T>
T deserialize (Serialization &&data);
template<typename T>
T deserialize (const Serialization &data);
} // namespace
#include "in_sajson.inl"

View File

@@ -0,0 +1,76 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "IO.h"
namespace tjp::core::io::json {
template<typename IO, typename T>
void io_json_r(IO &io_, T &t)
{
if constexpr (has_io_json<IO, T>::value)
{
io_json(io_, t);
}
else
{
io_r(io_, t);
}
}
template<typename IO, typename T>
void io_json_r_dispatch(IO &io_, T &t)
{
io_json_r(io_, t);
}
template<typename T, typename Reader>
void deserializeFrom (Reader &reader, T &t)
{
reader.any(t);
}
template<typename T, typename Reader>
T deserializeFrom (Reader &reader)
{
T t;
deserializeFrom(reader, t);
return t;
}
template<typename R, typename T>
T deserialize (Serialization &&data)
{
R reader(std::move(data));
return deserializeFrom<T>(reader);
}
template<typename T>
T deserialize (Serialization &&data)
{
return deserialize<Reader<json_in>, T>(std::move(data));
}
template<typename T>
T deserialize (const Serialization &data)
{
return deserialize<Reader<json_in>, T>(Serialization(data));
}
template<typename T>
void fromStream (const std::istream &stream, T &t)
{
std::vector<char> v;
omemstream s(v);
s << stream.rdbuf(); //read the file
Reader<json_in> reader(std::move(v));
reader.any(t);
}
} // namespace

26
tjp/core/io/json/json.inl Normal file
View File

@@ -0,0 +1,26 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include <vector>
namespace nlohmann {
template<typename IO>
void io_json_w(IO &io, const json &j)
{
auto s = to_string(j);
io.any(s);
}
template<typename IO>
void io_json_r(IO &io, json &j)
{
std::string s;
io.any(s);
j = json(s);
}
} // namespace

650
tjp/core/io/json/out.h Normal file
View File

@@ -0,0 +1,650 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "IO.h"
#include <tjp/core/io/memstream.h>
#include <tjp/core/types/Types+IO.h>
#include <tjp/core/rtti/RTTI.hpp>
#ifdef IO_JSON_USE_LARGE_NUMBER_PROXY
#include <tjp/core/containers/InPlaceArray.hpp>
#include <tjp/core/bases/Base64.h>
#endif
namespace tjp::core::io::json {
template<typename IO, typename T>
void io_json_w(IO &io, const T &t);
template<typename IO, typename T>
void io_json_w_dispatch(IO &io, const T &t);
struct json_out {
std::ostream *out;
char Q = '"';
char C = ':';
char SEP = ',';
bool firstValue=true;
int level = 0;
json_out(std::ostream &out_) :
out(&out_)
{
}
json_out()
{
}
~json_out()
{
}
void prettyPrintX ()
{
(*out) << std::endl;
for (auto i=0; i<level; ++i)
(*out) << " ";
}
void prettyPrint ()
{
}
void valueSeparator()
{
if (!firstValue)
{
(*out) << SEP;
}
}
void endValue ()
{
firstValue = false;
}
void beginValue ()
{
firstValue = true;
}
void key(const KeyType &key)
{
valueSeparator();
beginValue();
prettyPrint();
(*out) << Q << key << Q << C;
}
void begin_object()
{
valueSeparator();
beginValue();
(*out) << '{';
level++;
}
void end_object()
{
level--;
prettyPrint();
(*out) << '}';
endValue();
}
void begin_array()
{
valueSeparator();
beginValue();
(*out) << '[';
level++;
}
void end_array()
{
level--;
(*out) << ']';
endValue();
}
template<typename V>
void v_value(const V &v_)
{
valueSeparator();
(*out) << v_;
endValue();
}
template<typename T>
void v_quoted(const T &v_)
{
valueSeparator();
(*out) << Q;
auto &oss = *out;
for (const char c : v_) {
switch (c) {
case '\"': oss << "\\\""; break;
case '\\': oss << "\\\\"; break;
case '\b': oss << "\\b"; break;
case '\f': oss << "\\f"; break;
case '\n': oss << "\\n"; break;
case '\r': oss << "\\r"; break;
case '\t': oss << "\\t"; break;
default:
if (static_cast<unsigned char>(c) < 0x20)
{
char buffer[7];
std::snprintf(buffer, sizeof(buffer), "\\u%04X", static_cast<unsigned char>(c));
oss << buffer;
}
else
{
oss << c;
}
}
}
(*out) << Q;
endValue();
}
#ifdef IO_JSON_USE_LARGE_NUMBER_PROXY
template<typename V>
void v_value_proxy(const V &v_)
{
constexpr size_t b64Size = sizeof(V) * 4;
InPlaceArray<char, b64Size> b64;
b64.resize(b64Size);
auto size = toBase64((char *)&v_, sizeof(V), b64.data(), b64.size());
b64.resize(size);
v_quoted(b64);
}
#else
template<typename V>
void v_value_proxy(const V &v_)
{
v_value(v_);
}
#endif
template<typename V>
void v(const V &v_)
{
v_value(v_);
}
void v(const std::string &v_)
{
v_quoted(v_);
}
void v(const std::string_view &v_)
{
v_quoted(v_);
}
void v(const u8 &v_)
{
v_value((u32)v_);
}
void v(const s8 &v_)
{
v_value((s32)v_);
}
void v(const char &v_)
{
v_value((s32)v_);
}
void v(const s64 &v_)
{
v_value_proxy(v_);
}
void v(const u64 &v_)
{
v_value_proxy(v_);
}
void v(const s128 &v_)
{
v_value_proxy(v_);
}
void v(const u128 &v_)
{
v_value_proxy(v_);
}
void v(const bool &v_)
{
v_value(v_ ? "true" : "false");
}
void null()
{
v_value("null");
}
} ;
struct json_out_mem : json_out
{
Serialization block;
omemstream s;
json_out_mem() :
s(block)
{
s.precision(17);
out = &s;
}
} ;
inline
auto serialization_of(json_out &m)
{
}
inline
auto serialization_of(json_out_mem &m)
{
return m.block;
}
// ------------------------
struct EmptyWriterBaseClass {
template<typename IO, typename T>
void dispatch_custom(IO &io, T &t) {}
} ;
struct WriterAllocatorBase {
template<typename T>
void allocate(T &t)
{
io_ptr_allocate_default(*this, t);
}
} ;
template<typename S, typename Base=EmptyWriterBaseClass, typename Allocator=WriterAllocatorBase>
class Writer :
public Base,
public Allocator
{
public:
S f;
u8 count=0;
public:
auto partial()
{
return Writer<json_out_mem, Base>();
}
auto serialization ()
{
return serialization_of(f);
}
auto partial_serialization ()
{
return serialization();
}
public:
template<class... Args>
Writer (Args&&... args) :
f(args...)
{
}
operator bool() const
{
return f.good();
}
template<typename T>
void intrinsic(const T &t)
{
write(t);
}
template<typename T>
void intrinsic_string(const T &t)
{
write(std::string_view(t));
}
template<typename T>
void any(const T &t)
{
dispatch_any(t);
}
template<typename ... T>
void object(T&&... t)
{
object_begin();
object_(t...);
object_end();
}
void object_begin()
{
f.begin_object();
}
template<typename F>
void object_kf(KeyType k, F &&q)
{
f.key(k);
q();
};
template<typename ... T>
void object_kv(T&&... t)
{
object_(t...);
}
void object_end()
{
f.end_object();
}
template<typename ... T>
void array(T&&... t)
{
f.begin_array();
array_(t...);
f.end_array();
}
template<typename ...T>
void tuple(std::tuple<T...> &t)
{
f.begin_array();
std::apply([this](auto &...x){(av(x), ...);}, t);
f.end_array();
}
template<typename T>
void on_dispatch_any(const T &t)
{
on_any(t);
}
void null()
{
f.null();
}
template<typename T>
void on_dispatch_custom(T &t)
{
Base::dispatch_custom(*this, t);
}
protected:
template<typename T>
void dispatch_any(const T &t)
{
IO_JSON_LOG << "any " << type_id<T>().name() << std::endl;
io_json_w_dispatch(*this, t);
}
template<typename T>
void write(const T &t)
{
f.v(t);
}
// kv & av -----------
template<typename V>
void kv(KeyType k, const V &v)
{
f.key(k);
any(v);
}
template<typename T>
void kv(KeyType k, const Optional<T> &t)
{
if (t.write)
kv(k, t.v);
}
template<typename T>
void kv(KeyType k, const std::optional<T> &t)
{
if (t.has_value())
kv(k, *t);
}
template<typename B, typename T>
void kv(KeyType k, const Pointer<B, T> &t)
{
if (t.write)
kv(k, *(T *)*t.p);
}
template<typename V>
void av(const V &v)
{
any(v);
}
// -- handling different containers --
public:
void array_begin (Size size)
{
f.begin_array();
}
void array_end()
{
f.end_array();
}
template<typename T>
void on_vector_begin (const T &t)
{
array_begin((Size)t.size());
}
template<typename T>
void on_vector_end (const T &t)
{
array_end();
}
template<typename T>
void on_vector_value(const T &t)
{
av(t);
}
protected:
template<typename T>
void on_vector(const T &t)
{
IO_JSON_LOG << "many " << type_id<T>().name() << std::endl;
on_vector_begin(t);
// this fails for std::vector<bool>, because vector bool
// does some magic to compress to a bit field, and then the iterator
// doesn't pass back a reference
// for (const auto &v : t)
// any(v);
for (auto i = t.begin(); i!=t.end(); ++i)
on_vector_value(*i);
on_vector_end(t);
}
template<typename T>
void on_map(const T &t)
{
IO_JSON_LOG << "map " << type_id<T>().name() << std::endl;
f.begin_object();
for (auto &v : t)
kv(asKeyType(v.first), v.second);
f.end_object();
}
// -- dispatching different containers --
template<typename T, typename std::enable_if<!is_iterable<T>::value || is_stringish<T>::value, T>::type* = nullptr>
void on_any(const T &t)
{
io_dispatch_failed(*this, t);
}
template<typename T, typename std::enable_if<is_iterable<T>::value && !is_mappish<T>::value && !is_stringish<T>::value, T>::type* = nullptr>
void on_any(const T &t)
{
on_vector(t);
}
template<typename T, typename std::enable_if<is_iterable<T>::value && is_mappish<T>::value, T>::type* = nullptr>
void on_any(const T &t)
{
on_map(t);
}
// void on_any(const variant::Variant &t)
// {
// on_variant(t);
// }
//
// ---- handling object & array ----
void object_()
{
}
template<typename T>
void object__(KeyType key, const T &t)
{
kv(key, t);
}
template<typename ...Args>
void object_(Args&& ...args)
{
call_expand_2(
[&](auto && ...args) { object__(std::forward<decltype(args)>(args)...); },
std::forward<Args>(args)...
);
}
template<typename T>
void array__(const T &t)
{
any(t);
}
template<typename ...Args>
void array_(Args&& ...args)
{
call_expand_1(
[&](auto && ...args) { array__(std::forward<decltype(args)>(args)...); },
std::forward<Args>(args)...
);
}
template<typename ...T>
void tuple_(std::tuple<T...> &t)
{
std::apply([this](auto &...x){(av(x), ...);}, t);
}
public:
// ----- miscellaneous -----
template<typename T>
Optional<T> optional(T &t, bool write=true)
{
return io::json::optional(t, write);
}
template<typename T, typename B, typename std::enable_if<!std::is_class<T>::value, T>::type* = nullptr>
Pointer<B, T> pointer(B &b)
{
return io::json::Pointer<B, T> {
&b, b != nullptr
};
}
template<typename T, typename B, typename std::enable_if<std::is_class<T>::value, T>::type* = nullptr>
Pointer<B, T> pointer(B &b)
{
return io::json::Pointer<B, T> {
&b, dynamic_cast_ptr<T>(b) != nullptr
};
}
template<typename K>
AsKeyType<K> asKeyType(const K &k)
{
return io::json::asKeyType(k);
}
template<typename T>
Custom<T> custom(T &t)
{
return Custom<T> { &t };
}
} ;
// -------------------
template<typename W, typename ... X>
Serialization serialize (X&&... x);
template<typename ... X>
Serialization serialize (X&&... x);
template<typename T>
void serializeTo (Serialization &serialization, const T &t);
template<typename W, typename T>
Serialization serializeTo(W &w, const T &t);
template<typename ... X>
void toStream (std::ostream &file, X&& ... x);
template<typename ... X>
bool toFile (const std::string &fileName, X&& ... x);
} // namespace
#include "out.inl"

72
tjp/core/io/json/out.inl Normal file
View File

@@ -0,0 +1,72 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include "IO.h"
namespace tjp::core::io::json {
template<typename IO, typename T>
void io_json_w(IO &io_, const T &t)
{
typedef typename std::remove_const<T>::type TC;
if constexpr (has_io_json<IO, T>::value)
{
auto &t_ = *const_cast<TC *>(&t);
io_json(io_, t_);
}
else
{
io_w(io_, t);
}
}
template<typename IO, typename T>
void io_json_w_dispatch(IO &io_, const T &t)
{
io_json_w(io_, t);
}
template<typename W, typename T>
void serialize_many (W &writer, const T &t)
{
writer.any(t);
}
template<typename W, typename T, typename ... X>
void serialize_many (W &writer, const T &t, X&& ... x)
{
writer.any(t);
serialize_many(writer, x...);
}
template<typename W, typename ... X>
Serialization serialize (X&&... x)
{
Serialization v;
omemstream s(v);
s.precision(17);
W writer(s);
serialize_many(writer, x...);
return v;
};
template<typename ... X>
Serialization serialize (X&&... x)
{
return serialize<Writer<json_out>>(x...);
}
template<typename ... X>
void toStream (std::ostream &file, X&& ... x)
{
Writer<json_out> writer { file };
serialize_many(writer, x...);
}
} // namespace

View File

@@ -0,0 +1,21 @@
// License: Modified MIT (NON-AI)
// See the LICENSE file in the root directory for license information.
// Copyright 2025 Timothy Prepscius
#pragma once
#include <fstream>
namespace tjp::core::io::json {
template<typename ... X>
bool toFile (const std::string &fileName, X&& ... x)
{
std::ofstream stream(fileName);
stream.precision(17);
toStream(stream, x...);
return true;
}
} // namespace

2493
tjp/core/json/sajson-save.h Normal file

File diff suppressed because it is too large Load Diff

2642
tjp/core/json/sajson.h Normal file

File diff suppressed because it is too large Load Diff

8
transfer-to-lava Executable file
View File

@@ -0,0 +1,8 @@
HOST=lava
rsync -avz ./ genome@$HOST:Core_IO/ \
--exclude '.bin' \
--exclude 'venv' \
--exclude '*.a' \
--exclude '*.o' \
--delete \