Seed Core_IO from doc snapshot
This commit is contained in:
673
Core_IO.xcodeproj/project.pbxproj
Normal file
673
Core_IO.xcodeproj/project.pbxproj
Normal 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 */;
|
||||||
|
}
|
||||||
7
Core_IO.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Normal file
7
Core_IO.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Workspace
|
||||||
|
version = "1.0">
|
||||||
|
<FileRef
|
||||||
|
location = "self:">
|
||||||
|
</FileRef>
|
||||||
|
</Workspace>
|
||||||
@@ -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>
|
||||||
BIN
Core_IO.xcodeproj/project.xcworkspace/xcuserdata/tprepscius.xcuserdatad/UserInterfaceState.xcuserstate
generated
Normal file
BIN
Core_IO.xcodeproj/project.xcworkspace/xcuserdata/tprepscius.xcuserdatad/UserInterfaceState.xcuserstate
generated
Normal file
Binary file not shown.
@@ -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>
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Bucket
|
||||||
|
uuid = "4109D93F-EDDA-4746-8351-DC600656F7C7"
|
||||||
|
type = "1"
|
||||||
|
version = "2.0">
|
||||||
|
</Bucket>
|
||||||
@@ -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
26
LICENSE
Executable 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
2
Makefile
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
ROOTDIR := $(realpath $(dir $(lastword $(MAKEFILE_LIST)))..)
|
||||||
|
include $(ROOTDIR)/Core_Make/tjp/Make/Makefile
|
||||||
6
Makefile.def
Executable file
6
Makefile.def
Executable file
@@ -0,0 +1,6 @@
|
|||||||
|
timprepscius.core.include := $(timprepscius.core.include) -I $(dir $(realpath $(lastword $(MAKEFILE_LIST))))
|
||||||
|
timprepscius.core.link := $(timprepscius.core.link) -L $(dir $(realpath $(lastword $(MAKEFILE_LIST))))/.bin/$(OBJDIR)
|
||||||
|
|
||||||
|
timprepscius.core_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
15
Makefile.project
Executable 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
157
ReadMe.md
Executable 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
2
tests/Core_IO_Tests.txt
Normal 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
1
tests/Makefile
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../../Make/Makefile
|
||||||
32
tests/Makefile.project
Executable file
32
tests/Makefile.project
Executable 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
21
tests/main.cpp
Normal 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
14
tjp/core/io/Exception.h
Normal 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
56
tjp/core/io/IO+config.h
Executable 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
4
tjp/core/io/IO.cpp
Normal 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
49
tjp/core/io/IO.h
Executable 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
17
tjp/core/io/IO_.h
Normal 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
23
tjp/core/io/IO_dispatch.h
Executable 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
112
tjp/core/io/IO_encoder.h
Executable 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
7
tjp/core/io/Notes.txt
Normal 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
13
tjp/core/io/bin/Debug.h
Normal 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
357
tjp/core/io/bin/IO.h
Normal 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"
|
||||||
105
tjp/core/io/bin/_tests/ConstString+IO.cpp
Normal file
105
tjp/core/io/bin/_tests/ConstString+IO.cpp
Normal 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
|
||||||
361
tjp/core/io/bin/_tests/IO_bin.cpp
Normal file
361
tjp/core/io/bin/_tests/IO_bin.cpp
Normal 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
|
||||||
179
tjp/core/io/bin/_tests/IO_bin_versioning.cpp
Normal file
179
tjp/core/io/bin/_tests/IO_bin_versioning.cpp
Normal 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
|
||||||
56
tjp/core/io/bin/_tests/Ptr+IO.cpp
Normal file
56
tjp/core/io/bin/_tests/Ptr+IO.cpp
Normal 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
|
||||||
86
tjp/core/io/bin/dictionary.h
Normal file
86
tjp/core/io/bin/dictionary.h
Normal 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
619
tjp/core/io/bin/in.h
Normal 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
86
tjp/core/io/bin/in.inl
Normal 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
|
||||||
18
tjp/core/io/bin/in_file.hpp
Normal file
18
tjp/core/io/bin/in_file.hpp
Normal 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
16
tjp/core/io/bin/in_fwd.h
Normal 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
26
tjp/core/io/bin/json.inl
Normal 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
543
tjp/core/io/bin/out.h
Normal 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
65
tjp/core/io/bin/out.inl
Normal 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
|
||||||
18
tjp/core/io/bin/out_file.hpp
Normal file
18
tjp/core/io/bin/out_file.hpp
Normal 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
23
tjp/core/io/bin/out_fwd.h
Normal 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
38
tjp/core/io/calls.hpp
Executable 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
227
tjp/core/io/json/IO.h
Normal 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
|
||||||
415
tjp/core/io/json/_tests/IO_json.cpp
Normal file
415
tjp/core/io/json/_tests/IO_json.cpp
Normal 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
|
||||||
39
tjp/core/io/json/in_file.hpp
Normal file
39
tjp/core/io/json/in_file.hpp
Normal 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
|
||||||
831
tjp/core/io/json/in_sajson.h
Normal file
831
tjp/core/io/json/in_sajson.h
Normal 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"
|
||||||
76
tjp/core/io/json/in_sajson.inl
Normal file
76
tjp/core/io/json/in_sajson.inl
Normal 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
26
tjp/core/io/json/json.inl
Normal 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
650
tjp/core/io/json/out.h
Normal 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
72
tjp/core/io/json/out.inl
Normal 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
|
||||||
21
tjp/core/io/json/out_file.hpp
Normal file
21
tjp/core/io/json/out_file.hpp
Normal 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
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
2642
tjp/core/json/sajson.h
Normal file
File diff suppressed because it is too large
Load Diff
8
transfer-to-lava
Executable file
8
transfer-to-lava
Executable file
@@ -0,0 +1,8 @@
|
|||||||
|
HOST=lava
|
||||||
|
rsync -avz ./ genome@$HOST:Core_IO/ \
|
||||||
|
--exclude '.bin' \
|
||||||
|
--exclude 'venv' \
|
||||||
|
--exclude '*.a' \
|
||||||
|
--exclude '*.o' \
|
||||||
|
--delete \
|
||||||
|
|
||||||
Reference in New Issue
Block a user