Add standalone exe build tooling under scripts/exe

build_exe.py compiles every unit in data/compile.json with the pinned toolchain and links Ragexe.exe.
Not part of the decompilation and not in data/compile.json: imports/*.def (original DLL import tables),
jsoncons/ (v0.170.2 headers + JsonCppLoader glue), nProtect/GameGuard.cpp (no-op GameGuard stand-in).
This commit is contained in:
ragnarok-clanker 2026-11-06 15:10:16 +01:00
commit e11260a408
149 changed files with 80735 additions and 0 deletions

188
scripts/exe/build_exe.py Normal file
View file

@ -0,0 +1,188 @@
"""Build every unit in data/compile.json and link them into Ragexe.exe (+ .pdb).
Optional and local: clank checks and merges never run this. It uses only the
toolchain `td toolchain install` provides (the root and runner come from
.td/config.json), with the exact compiler flags of data/compile.json. Vendor
DLL imports (Bink, Granny, Stove, ...) come from scripts/exe/imports/*.def, the
exact import table of the original executable, so a declaration that does not
match the real DLL export fails at link time.
python scripts/exe/build_exe.py # compile + link, fail on any error
python scripts/exe/build_exe.py --force-multiple # accept duplicate definitions
python scripts/exe/build_exe.py --link-only # relink objects from a previous run
"""
import argparse
import concurrent.futures
import json
import os
import re
import subprocess
import sys
from collections import Counter
from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent.parent
EXE_DIR = Path(__file__).resolve().parent
MSVC = "VC/Tools/MSVC/14.29.30133"
SDK_LIB = "Program Files/Windows Kits/10/Lib/10.0.19041.0"
SYSTEM_LIBS = [
"kernel32.lib", "user32.lib", "gdi32.lib", "advapi32.lib", "winmm.lib", "ws2_32.lib",
"ole32.lib", "oleaut32.lib", "uuid.lib", "shell32.lib", "imm32.lib", "version.lib",
"comctl32.lib", "comdlg32.lib", "shlwapi.lib", "wininet.lib", "gdiplus.lib", "bcrypt.lib",
"dxguid.lib", "ddraw.lib", "d3d9.lib", "dinput8.lib", "dbghelp.lib", "crypt32.lib",
"iphlpapi.lib", "psapi.lib", "wintrust.lib", "winhttp.lib", "netapi32.lib",
]
class Toolchain:
"""The td toolchain, run the way td runs it (native on Windows, wine elsewhere)."""
def __init__(self):
config = json.loads((ROOT / ".td" / "config.json").read_text(encoding="utf-8"))
runner = config["runners"]["ragnarok"]
self.kind = runner["type"]
if self.kind not in ("native", "wine"):
sys.exit(f"runner '{self.kind}' is not supported; use td's native (Windows) or wine runner")
self.root = Path(runner["toolchainRoot"])
self.bin = self.root / MSVC / "bin" / "Hostx64" / "x86"
crt = self.root / MSVC / "lib" / "x86"
if not (crt / "msvcrt.lib").exists() or not (self.root / SDK_LIB / "um" / "x86" / "kernel32.Lib").exists():
sys.exit(f"{self.root} has no link libraries (msvcrt.lib, kernel32.lib): run 'td toolchain install' to update it")
self.env = dict(os.environ)
self.env.update(runner.get("env", {}))
self.env["LIB"] = ";".join(self.path(p) for p in (
crt, self.root / MSVC / "atlmfc" / "lib" / "x86",
self.root / SDK_LIB / "ucrt" / "x86", self.root / SDK_LIB / "um" / "x86"))
def path(self, p):
if self.kind == "native":
return str(p)
return subprocess.run(["winepath", "-w", str(p)], capture_output=True, text=True, check=True).stdout.strip()
def run(self, tool, args, env=None, cwd=None):
exe = str(self.bin / tool)
command = [exe, *args] if self.kind == "native" else ["wine", exe, *args]
return subprocess.run(command, env=env or self.env, cwd=cwd, capture_output=True, text=True, errors="replace")
def build_import_libs(tc, out_dir):
lib_dir = out_dir / "importlibs"
lib_dir.mkdir(exist_ok=True)
libs = []
for definition in sorted((EXE_DIR / "imports").glob("*.def")):
lib = lib_dir / (definition.stem + ".lib")
result = tc.run("lib.exe", ["/nologo", "/MACHINE:X86", f"/DEF:{tc.path(definition)}", f"/OUT:{tc.path(lib)}"])
if result.returncode != 0:
sys.exit(f"import library {definition.name} failed:\n{result.stdout}{result.stderr}")
libs.append(lib)
return libs
# Units only the standalone exe needs: stand-ins for third-party code the
# decompilation does not reproduce. Each is compiled with the flags of the
# listed data/compile.json unit plus any extra include directories (relative to
# the repository). Clank does not know about these files.
EXE_ONLY_UNITS = {
"scripts/exe/nProtect/GameGuard.cpp": ("Source/Security/NProtectGameGuardMgr.cpp", []),
"scripts/exe/jsoncons/JsonCppLoaderGlue.cpp": ("Source/Utility/JsonCppLoader.cpp", ["scripts/exe/jsoncons/include"]),
}
def exe_units(config):
"""unit -> (shape index, extra include directories)."""
units = {unit: (shape, []) for unit, shape in config["units"].items()}
for unit, (flags_of, includes) in EXE_ONLY_UNITS.items():
units[unit] = (config["units"][flags_of], includes)
return units
def compile_units(tc, config, out_dir, jobs):
root = tc.path(ROOT).replace("\\", "/")
def expand(value):
return value.replace("${TC}", tc.path(tc.root)).replace("${SRC}", root)
env = dict(tc.env)
for key, value in config["env"].items():
env[key] = expand(value)
def build(item):
unit, (shape, includes) = item
obj = out_dir / (unit.replace("/", "_") + ".obj")
extra = [f"/I{tc.path(ROOT / directory)}" for directory in includes]
args = [*(expand(a) for a in config["shapes"][shape]), *extra, "/Z7", f"/Fo{tc.path(obj)}", tc.path(ROOT / unit)]
result = tc.run("cl.exe", args, env=env, cwd=ROOT)
return unit, obj, result.returncode, result.stdout + result.stderr
with concurrent.futures.ThreadPoolExecutor(jobs) as pool:
results = list(pool.map(build, exe_units(config).items()))
failures = [r for r in results if r[2] != 0]
for unit, _, _, output in failures:
print(f"== {unit}")
print("\n".join(line for line in output.splitlines() if " error " in line or "fatal error" in line))
print(f"compiled {len(results) - len(failures)}/{len(results)} units")
return [r[1] for r in results if r[2] == 0], len(failures)
def link(tc, objects, out_dir, extra_args):
rsp = out_dir / "link.rsp"
rsp.write_text("\n".join([*(f'"{tc.path(o)}"' for o in objects), *extra_args]), encoding="utf-8")
exe = out_dir / "Ragexe.exe"
outputs = (exe, exe.with_suffix(".pdb"))
for stale in outputs:
stale.unlink(missing_ok=True)
args = ["/nologo", "/MACHINE:X86", "/SUBSYSTEM:WINDOWS", "/LARGEADDRESSAWARE",
"/DEBUG:FULL", f"/PDB:{tc.path(exe.with_suffix('.pdb'))}", "/INCREMENTAL:NO", "/OPT:REF", "/OPT:ICF",
"/ERRORLIMIT:0", f"/OUT:{tc.path(exe)}", f"@{tc.path(rsp)}", *SYSTEM_LIBS]
result = tc.run("link.exe", args)
if result.returncode != 0:
for partial in outputs:
partial.unlink(missing_ok=True)
return result.returncode, result.stdout + result.stderr, exe
def summarize(log, out_dir):
(out_dir / "link.log").write_text(log, encoding="utf-8")
duplicates = sorted(set(re.findall(r'(?:error LNK2005|warning LNK4006): "([^"]+)"', log)))
unresolved = sorted(set(a or b for a, b in re.findall(r'unresolved external symbol (?:"[^"]+" \((\S+)\)|(\S+))', log)))
print(f"link log: {out_dir / 'link.log'}")
print(f"duplicate definitions: {len(duplicates)}")
for symbol in duplicates:
print(f" {symbol}")
print(f"unresolved symbols: {len(unresolved)}")
codes = Counter(re.findall(r"error (LNK\d+)", log))
if codes:
print("linker errors: " + ", ".join(f"{code} x{count}" for code, count in codes.most_common()))
def main():
parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument("--out", default=str(ROOT / "build" / "exe"), help="output directory")
parser.add_argument("--jobs", type=int, default=os.cpu_count(), help="parallel compiles")
parser.add_argument("--force-multiple", action="store_true",
help="link despite duplicate definitions (/FORCE:MULTIPLE)")
parser.add_argument("--link-only", action="store_true", help="reuse the objects from a previous run")
args = parser.parse_args()
out_dir = Path(args.out)
out_dir.mkdir(parents=True, exist_ok=True)
config = json.loads((ROOT / "data" / "compile.json").read_text(encoding="utf-8"))
tc = Toolchain()
print(f"toolchain: {tc.root} ({tc.kind})")
if args.link_only:
objects = [out_dir / (unit.replace("/", "_") + ".obj") for unit in exe_units(config)]
compile_failures = 0
else:
objects, compile_failures = compile_units(tc, config, out_dir, args.jobs)
extra = ["/FORCE:MULTIPLE"] if args.force_multiple else []
code, log, exe = link(tc, [*objects, *build_import_libs(tc, out_dir)], out_dir, extra)
summarize(log, out_dir)
if code == 0:
print(f"built {exe}")
sys.exit(1 if code != 0 or compile_failures else 0)
if __name__ == "__main__":
main()

View file

@ -0,0 +1,29 @@
; Imports of the original Ragexe 2026-02-19 from BaseSDK.dll, checked against the shipped DLL's exports.
LIBRARY BaseSDK.dll
EXPORTS
??0CallbackResult@PCSDK@Stove@@QAE@ABU012@@Z
??0StovePCInitializeParam@Base@PCSDK@Stove@@QAE@XZ
??0StovePCShutdown@Base@PCSDK@Stove@@QAE@ABU0123@@Z
??0StovePCUser@Base@PCSDK@Stove@@QAE@XZ
??1CallbackResult@PCSDK@Stove@@QAE@XZ
??1Result@PCSDK@Stove@@QAE@XZ
??1StovePCInitializeParam@Base@PCSDK@Stove@@QAE@XZ
??1StovePCShutdown@Base@PCSDK@Stove@@QAE@XZ
??1StovePCUser@Base@PCSDK@Stove@@QAE@XZ
??4Result@PCSDK@Stove@@QAEAAU012@ABU012@@Z
?GetAccessToken@StovePCToken@Base@PCSDK@Stove@@QBEPB_WXZ
?GetCategory1@StovePCLogEvent@Base@PCSDK@Stove@@QBEPB_WXZ
?GetGameUserId@StovePCUser@Base@PCSDK@Stove@@QBE_KXZ
?GetMemberNumber@StovePCUser@Base@PCSDK@Stove@@QBE_KXZ
?GetResult@CallbackResult@PCSDK@Stove@@QBE?AUResult@23@XZ
?IsSuccessful@Result@PCSDK@Stove@@QBE_NXZ
?SetApplicationKey@StovePCInitializeParam@Base@PCSDK@Stove@@QAEXPB_W@Z
?SetCategory1@StovePCLogEvent@Base@PCSDK@Stove@@QAEXPB_W@Z
?SetEnvironment@StovePCInitializeParam@Base@PCSDK@Stove@@QAEXPB_W@Z
Base_GetAccessToken
Base_GetShutdown
Base_GetUser
Base_Initialize
Base_RestartAppIfNecessary
Base_RunCallback
Base_UnInitialize

View file

@ -0,0 +1,9 @@
; Imports of the original Ragexe 2026-02-19 from D3DX9_43.dll, checked against the shipped DLL's exports.
; D3DX is __stdcall but exports undecorated names, so the decorated import maps to the plain export.
LIBRARY D3DX9_43.dll
EXPORTS
D3DXFilterTexture@16=D3DXFilterTexture
D3DXLoadSurfaceFromMemory@40=D3DXLoadSurfaceFromMemory
D3DXLoadSurfaceFromSurface@32=D3DXLoadSurfaceFromSurface
D3DXMatrixPerspectiveFovLH@20=D3DXMatrixPerspectiveFovLH
D3DXSaveSurfaceToFileA@20=D3DXSaveSurfaceToFileA

View file

@ -0,0 +1,41 @@
; Imports of the original Ragexe 2026-02-19 from IAPSDK.dll, checked against the shipped DLL's exports.
LIBRARY IAPSDK.dll
EXPORTS
??0StovePCFetchProductParam@IAP@PCSDK@Stove@@QAE@XZ
??0StovePCOrderProduct@IAP@PCSDK@Stove@@QAE@XZ
??0StovePCPaymentOption@IAP@PCSDK@Stove@@QAE@ABU0123@@Z
??0StovePCPaymentOption@IAP@PCSDK@Stove@@QAE@XZ
??0StovePCPurchaseResult@IAP@PCSDK@Stove@@QAE@ABU0123@@Z
??0StovePCStartPurchaseParam@IAP@PCSDK@Stove@@QAE@XZ
??0StovePCTermsOption@IAP@PCSDK@Stove@@QAE@XZ
??1StovePCFetchProductParam@IAP@PCSDK@Stove@@QAE@XZ
??1StovePCPurchaseResult@IAP@PCSDK@Stove@@QAE@XZ
??1StovePCStartPurchaseParam@IAP@PCSDK@Stove@@QAE@XZ
?CreateOrderProduct@StovePCStartPurchaseParam@IAP@PCSDK@Stove@@QAEXI@Z
?GetCategoryId@StovePCProduct@IAP@PCSDK@Stove@@QBEPB_WXZ
?GetCategoryId@StovePCPurchasedProduct@IAP@PCSDK@Stove@@QBEPB_WXZ
?GetChargeTypeName@StovePCChargeInfo@IAP@PCSDK@Stove@@QBEPB_WXZ
?GetDisplayNumber@StovePCShopCategory@IAP@PCSDK@Stove@@QBEHXZ
?GetGuidQuantity@StovePCProduct@IAP@PCSDK@Stove@@QBEHXZ
?GetProductId@StovePCOrderProduct@IAP@PCSDK@Stove@@QBE_JXZ
?GetProductId@StovePCOrderProduct@IAP@PCSDK@Stove@@QBE_JXZ
?GetPurchaseLimitCount@StovePCProduct@IAP@PCSDK@Stove@@QBEHXZ
?GetSaleBeginDate@StovePCProduct@IAP@PCSDK@Stove@@QBE_JXZ
?GetSaleEndDate@StovePCProduct@IAP@PCSDK@Stove@@QBE_JXZ
?GetSalePrice@StovePCProduct@IAP@PCSDK@Stove@@QBENXZ
?SetCategoryId@StovePCFetchProductParam@IAP@PCSDK@Stove@@QAEXPB_W@Z
?SetChargeDisplayDeductVal@StovePCChargeInfo@IAP@PCSDK@Stove@@QAEXN@Z
?SetChargeType@StovePCChargeInfo@IAP@PCSDK@Stove@@QAEXH@Z
?SetOperation@StovePCPaymentOption@IAP@PCSDK@Stove@@QAEXW4StovePCPaymentOperation@234@@Z
?SetOperation@StovePCPaymentOption@IAP@PCSDK@Stove@@QAEXW4StovePCPaymentOperation@234@@Z
?SetOrderProduct@StovePCStartPurchaseParam@IAP@PCSDK@Stove@@QAEXHPBUStovePCOrderProduct@234@@Z
?SetPageNumber@StovePCFetchProductParam@IAP@PCSDK@Stove@@QAEXH@Z
?SetPageSize@StovePCFetchProductParam@IAP@PCSDK@Stove@@QAEXH@Z
?SetProductId@StovePCOrderProduct@IAP@PCSDK@Stove@@QAEX_J@Z
?SetPurchaseOption@StovePCStartPurchaseParam@IAP@PCSDK@Stove@@QAEXUStovePCPurchaseOption@234@@Z
IAP_ConfirmPurchase
IAP_FetchProducts
IAP_FetchTermsAgreement
IAP_Initialize
IAP_StartPurchase
IAP_UnInitialize

View file

@ -0,0 +1,50 @@
; Imports of the original Ragexe 2026-02-19 from Mss32.dll, checked against the shipped DLL's exports.
LIBRARY Mss32.dll
EXPORTS
AIL_3D_room_type@4=_AIL_3D_room_type@4
AIL_3D_sample_status@4=_AIL_3D_sample_status@4
AIL_3D_speaker_type@4=_AIL_3D_speaker_type@4
AIL_WAV_info@8=_AIL_WAV_info@8
AIL_allocate_3D_sample_handle@4=_AIL_allocate_3D_sample_handle@4
AIL_allocate_sample_handle@4=_AIL_allocate_sample_handle@4
AIL_close_3D_listener@4=_AIL_close_3D_listener@4
AIL_close_3D_provider@4=_AIL_close_3D_provider@4
AIL_close_digital_driver@4=_AIL_close_digital_driver@4
AIL_close_stream@4=_AIL_close_stream@4
AIL_decompress_ADPCM@12=_AIL_decompress_ADPCM@12
AIL_decompress_ASI@24=_AIL_decompress_ASI@24
AIL_end_3D_sample@4=_AIL_end_3D_sample@4
AIL_end_sample@4=_AIL_end_sample@4
AIL_enumerate_3D_providers@12=_AIL_enumerate_3D_providers@12
AIL_file_type@8=_AIL_file_type@8
AIL_init_sample@4=_AIL_init_sample@4
AIL_mem_free_lock@4=_AIL_mem_free_lock@4
AIL_open_3D_listener@4=_AIL_open_3D_listener@4
AIL_open_3D_provider@4=_AIL_open_3D_provider@4
AIL_open_digital_driver@16=_AIL_open_digital_driver@16
AIL_open_stream@12=_AIL_open_stream@12
AIL_pause_stream@8=_AIL_pause_stream@8
AIL_release_3D_sample_handle@4=_AIL_release_3D_sample_handle@4
AIL_release_sample_handle@4=_AIL_release_sample_handle@4
AIL_sample_status@4=_AIL_sample_status@4
AIL_set_3D_orientation@28=_AIL_set_3D_orientation@28
AIL_set_3D_position@16=_AIL_set_3D_position@16
AIL_set_3D_room_type@8=_AIL_set_3D_room_type@8
AIL_set_3D_sample_distances@12=_AIL_set_3D_sample_distances@12
AIL_set_3D_sample_effects_level@8=_AIL_set_3D_sample_effects_level@8
AIL_set_3D_sample_file@8=_AIL_set_3D_sample_file@8
AIL_set_3D_sample_volume@8=_AIL_set_3D_sample_volume@8
AIL_set_3D_speaker_type@8=_AIL_set_3D_speaker_type@8
AIL_set_preference@8=_AIL_set_preference@8
AIL_set_redist_directory@4=_AIL_set_redist_directory@4
AIL_set_sample_file@12=_AIL_set_sample_file@12
AIL_set_sample_volume@8=_AIL_set_sample_volume@8
AIL_set_stream_loop_count@8=_AIL_set_stream_loop_count@8
AIL_set_stream_volume@8=_AIL_set_stream_volume@8
AIL_shutdown@0=_AIL_shutdown@0
AIL_start_3D_sample@4=_AIL_start_3D_sample@4
AIL_start_sample@4=_AIL_start_sample@4
AIL_start_stream@4=_AIL_start_stream@4
AIL_startup@0=_AIL_startup@0
AIL_stream_status@4=_AIL_stream_status@4
AIL_stream_volume@4=_AIL_stream_volume@4

View file

@ -0,0 +1,16 @@
; Imports of the original Ragexe 2026-02-19 from binkw32.dll, checked against the shipped DLL's exports.
LIBRARY binkw32.dll
EXPORTS
BinkClose@4=_BinkClose@4
BinkCopyToBuffer@28=_BinkCopyToBuffer@28
BinkDoFrame@4=_BinkDoFrame@4
BinkGetError@0=_BinkGetError@0
BinkGoto@12=_BinkGoto@12
BinkNextFrame@4=_BinkNextFrame@4
BinkOpen@8=_BinkOpen@8
BinkOpenDirectSound@4=_BinkOpenDirectSound@4
BinkPause@8=_BinkPause@8
BinkSetSoundSystem@8=_BinkSetSoundSystem@8
BinkSetVolume@12=_BinkSetVolume@12
BinkShouldSkip@4=_BinkShouldSkip@4
BinkWait@4=_BinkWait@4

View file

@ -0,0 +1,49 @@
; Imports of the original Ragexe 2026-02-19 from granny2.dll, checked against the shipped DLL's exports.
LIBRARY granny2.dll
EXPORTS
GrannyPNT332VertexType DATA
GrannyRGBA8888PixelFormat DATA
GrannyBuildWorldPose@24=_GrannyBuildWorldPose@24
GrannyControlModelsNext@4=_GrannyControlModelsNext@4
GrannyCopyMeshIndices@12=_GrannyCopyMeshIndices@12
GrannyCopyMeshVertices@12=_GrannyCopyMeshVertices@12
GrannyCopyTextureImage@32=_GrannyCopyTextureImage@32
GrannyDeformVertices@24=_GrannyDeformVertices@24
GrannyFreeCompletedModelControls@4=_GrannyFreeCompletedModelControls@4
GrannyFreeControl@4=_GrannyFreeControl@4
GrannyFreeFile@4=_GrannyFreeFile@4
GrannyFreeFileSection@8=_GrannyFreeFileSection@8
GrannyFreeLocalPose@4=_GrannyFreeLocalPose@4
GrannyFreeMeshBinding@4=_GrannyFreeMeshBinding@4
GrannyFreeMeshDeformer@4=_GrannyFreeMeshDeformer@4
GrannyFreeModelInstance@4=_GrannyFreeModelInstance@4
GrannyFreeWorldPose@4=_GrannyFreeWorldPose@4
GrannyGetControlDurationLeft@4=_GrannyGetControlDurationLeft@4
GrannyGetFileInfo@4=_GrannyGetFileInfo@4
GrannyGetMaterialTextureByType@8=_GrannyGetMaterialTextureByType@8
GrannyGetMeshBindingToBoneIndices@4=_GrannyGetMeshBindingToBoneIndices@4
GrannyGetMeshBytesPerIndex@4=_GrannyGetMeshBytesPerIndex@4
GrannyGetMeshIndexCount@4=_GrannyGetMeshIndexCount@4
GrannyGetMeshIndices@4=_GrannyGetMeshIndices@4
GrannyGetMeshTriangleGroups@4=_GrannyGetMeshTriangleGroups@4
GrannyGetMeshVertexCount@4=_GrannyGetMeshVertexCount@4
GrannyGetMeshVertexType@4=_GrannyGetMeshVertexType@4
GrannyGetMeshVertices@4=_GrannyGetMeshVertices@4
GrannyGetSecondsElapsed@8=_GrannyGetSecondsElapsed@8
GrannyGetSourceSkeleton@4=_GrannyGetSourceSkeleton@4
GrannyGetSystemSeconds@0=_GrannyGetSystemSeconds@0
GrannyGetWorldPoseComposite4x4@8=_GrannyGetWorldPoseComposite4x4@8
GrannyInstantiateModel@4=_GrannyInstantiateModel@4
GrannyMeshIsRigid@4=_GrannyMeshIsRigid@4
GrannyNewLocalPose@4=_GrannyNewLocalPose@4
GrannyNewMeshBinding@12=_GrannyNewMeshBinding@12
GrannyNewMeshDeformer@12=_GrannyNewMeshDeformer@12
GrannyNewWorldPose@4=_GrannyNewWorldPose@4
GrannyPlayControlledAnimation@12=_GrannyPlayControlledAnimation@12
GrannyReadEntireFileFromMemory@8=_GrannyReadEntireFileFromMemory@8
GrannySampleModelAnimations@16=_GrannySampleModelAnimations@16
GrannySetControlActive@8=_GrannySetControlActive@8
GrannySetControlLoopCount@8=_GrannySetControlLoopCount@8
GrannySetModelClock@8=_GrannySetModelClock@8
GrannyTextureHasAlpha@4=_GrannyTextureHasAlpha@4
GrannyVersionsMatch_@16=_GrannyVersionsMatch_@16

View file

@ -0,0 +1,8 @@
; Imports of the original Ragexe 2026-02-19 from ijl15.dll, checked against the shipped DLL's exports.
; IJL is __stdcall but exports undecorated names, so the decorated import maps to the plain export.
LIBRARY ijl15.dll
EXPORTS
ijlFree@4=ijlFree
ijlInit@4=ijlInit
ijlRead@8=ijlRead
ijlWrite@8=ijlWrite

View file

@ -0,0 +1,124 @@
// jsoncons v0.170.2 entry points used by Source/Utility/JsonCppLoader.cpp,
// linked only into the standalone exe built by scripts/exe/build_exe.py. Clank
// never compiles this file.
//
// The original statically links jsoncons; these ten functions are the
// instantiations JsonCppLoader calls by address (fn_00198 ... fn_00769).
// v0.170.2 is the last release whose basic_json storage tags (short string 6,
// long string 7, byte string 8, array 9, empty object 10, object 11, const
// pointer 12) and basic_json_decode_options layout (virtual base at +8)
// match JsonValue and the loader's option storage.
//
// JsonCppLoader declares them as extern "C" void(), takes their address and
// calls them through __thiscall or __cdecl pointers. The __thiscall ones are
// therefore __thiscall members of the *Thunk types here, and each plain C
// name is an /ALTERNATENAME for the member's decorated name (end of file).
#include <jsoncons/json.hpp>
#include <jsoncons_ext/bson/bson.hpp>
#include <fstream>
#include <functional>
#include <new>
#include <vector>
namespace jsoncons_glue {
using Json = jsoncons::basic_json<char, jsoncons::sorted_policy>;
using JsonOptions = jsoncons::basic_json_decode_options<char>;
using JsonOptionsCommon = jsoncons::basic_json_options_common<char>;
using BsonOptions = jsoncons::bson::bson_decode_options;
using JsonHandler = std::function<bool(jsoncons::json_errc, const jsoncons::ser_context&)>;
static_assert(sizeof(Json) == 0x10);
static_assert(sizeof(JsonHandler) == 40);
static_assert(sizeof(JsonOptions) <= 248);
static_assert(sizeof(BsonOptions) <= 16);
// Each member runs with the object the loader passes in ECX.
struct HandlerThunk : JsonHandler {
// fn_00198: std::function<...>(default_json_parsing), constructed in place
// (the loader passes the storage twice: this and the source argument).
void Construct(void*);
};
struct JsonOptionsThunk : JsonOptions {
// fn_00321: constructor; the flag says whether to build the virtual base.
JsonOptions* Construct(int);
};
struct JsonOptionsCommonThunk : JsonOptionsCommon {
// fn_00368: destructor of the virtual base subobject (loader passes +8).
void Destroy();
};
struct BsonOptionsThunk : BsonOptions {
// fn_00349: constructor, same convention as fn_00321.
BsonOptions* Construct(int);
};
struct JsonThunk : Json {
// fn_00367: destructor.
void Destroy();
// fn_00769: swap, used to move the parsed document into place.
void Swap(Json* other);
};
void HandlerThunk::Construct(void*) {
new (static_cast<JsonHandler*>(this)) JsonHandler(jsoncons::default_json_parsing());
}
JsonOptions* JsonOptionsThunk::Construct(int) {
return new (static_cast<JsonOptions*>(this)) JsonOptions();
}
void JsonOptionsCommonThunk::Destroy() {
this->JsonOptionsCommon::~JsonOptionsCommon();
}
BsonOptions* BsonOptionsThunk::Construct(int) {
return new (static_cast<BsonOptions*>(this)) BsonOptions();
}
void JsonThunk::Destroy() {
static_cast<Json*>(this)->~Json();
}
void JsonThunk::Swap(Json* other) {
static_cast<Json*>(this)->swap(*other);
}
}
using namespace jsoncons_glue;
extern "C" {
// fn_00272: bson::decode_bson<json>(std::istream&, const bson_decode_options&).
Json* __cdecl fn_00272(Json* out, std::ifstream* file, BsonOptions* options) {
return new (out) Json(jsoncons::bson::decode_bson<Json>(*file, *options));
}
// fn_00273: bson::decode_bson<json>(const std::vector<uint8_t>&, const bson_decode_options&).
Json* __cdecl fn_00273(Json* out, const std::vector<unsigned char>* buffer, BsonOptions* options) {
return new (out) Json(jsoncons::bson::decode_bson<Json>(*buffer, *options));
}
// fn_00733: json::parse(std::istream&, const json_decode_options&, handler).
// The handler is passed by value: the callee owns and destroys it.
Json* __cdecl fn_00733(Json* out, std::ifstream* file, JsonOptions* options, JsonHandler handler) {
return new (out) Json(Json::parse(*file, *options, handler));
}
// fn_00734: json::parse(const char*, const json_decode_options&, handler).
Json* __cdecl fn_00734(Json* out, const unsigned char* data, JsonOptions* options, JsonHandler handler) {
return new (out) Json(Json::parse(jsoncons::basic_string_view<char>(reinterpret_cast<const char*>(data)), *options, handler));
}
}
#pragma comment(linker, "/ALTERNATENAME:_fn_00198=?Construct@HandlerThunk@jsoncons_glue@@QAEXPAX@Z")
#pragma comment(linker, "/ALTERNATENAME:_fn_00321=?Construct@JsonOptionsThunk@jsoncons_glue@@QAEPAV?$basic_json_decode_options@D@jsoncons@@H@Z")
#pragma comment(linker, "/ALTERNATENAME:_fn_00368=?Destroy@JsonOptionsCommonThunk@jsoncons_glue@@QAEXXZ")
#pragma comment(linker, "/ALTERNATENAME:_fn_00349=?Construct@BsonOptionsThunk@jsoncons_glue@@QAEPAVbson_decode_options@bson@jsoncons@@H@Z")
#pragma comment(linker, "/ALTERNATENAME:_fn_00367=?Destroy@JsonThunk@jsoncons_glue@@QAEXXZ")
#pragma comment(linker, "/ALTERNATENAME:_fn_00769=?Swap@JsonThunk@jsoncons_glue@@QAEXPAV?$basic_json@DUsorted_policy@jsoncons@@V?$allocator@D@std@@@jsoncons@@@Z")

View file

@ -0,0 +1,28 @@
// Copyright Daniel Parker 2013 - 2020.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE or copy at
// http://www.boost.org/LICENSE_1_0.txt)
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

View file

@ -0,0 +1,38 @@
// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_ALLOCATOR_HOLDER_HPP
#define JSONCONS_ALLOCATOR_HOLDER_HPP
namespace jsoncons {
template <class Allocator>
class allocator_holder
{
public:
using allocator_type = Allocator;
private:
allocator_type alloc_;
public:
allocator_holder() = default;
allocator_holder(const allocator_holder&) = default;
allocator_holder(allocator_holder&&) = default;
allocator_holder& operator=(const allocator_holder&) = default;
allocator_holder& operator=(allocator_holder&&) = default;
allocator_holder(const allocator_type& alloc)
: alloc_(alloc)
{}
~allocator_holder() = default;
allocator_type get_allocator() const
{
return alloc_;
}
};
}
#endif

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,820 @@
// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_BYTE_STRING_HPP
#define JSONCONS_BYTE_STRING_HPP
#include <sstream>
#include <vector>
#include <ostream>
#include <cmath>
#include <cstring> // std::memcmp
#include <memory> // std::allocator
#include <iterator>
#include <exception>
#include <iomanip> // std::setw
#include <initializer_list>
#include <utility> // std::move
#include <jsoncons/config/jsoncons_config.hpp>
#include <jsoncons/json_exception.hpp>
#include <jsoncons/conv_error.hpp>
#include <jsoncons/extension_traits.hpp>
namespace jsoncons {
// Algorithms
namespace detail {
template <class InputIt, class Container>
typename std::enable_if<std::is_same<typename std::iterator_traits<InputIt>::value_type,uint8_t>::value,size_t>::type
encode_base64_generic(InputIt first, InputIt last, const char alphabet[65], Container& result)
{
std::size_t count = 0;
unsigned char a3[3];
unsigned char a4[4];
unsigned char fill = alphabet[64];
int i = 0;
int j = 0;
while (first != last)
{
a3[i++] = *first++;
if (i == 3)
{
a4[0] = (a3[0] & 0xfc) >> 2;
a4[1] = ((a3[0] & 0x03) << 4) + ((a3[1] & 0xf0) >> 4);
a4[2] = ((a3[1] & 0x0f) << 2) + ((a3[2] & 0xc0) >> 6);
a4[3] = a3[2] & 0x3f;
for (i = 0; i < 4; i++)
{
result.push_back(alphabet[a4[i]]);
++count;
}
i = 0;
}
}
if (i > 0)
{
for (j = i; j < 3; ++j)
{
a3[j] = 0;
}
a4[0] = (a3[0] & 0xfc) >> 2;
a4[1] = ((a3[0] & 0x03) << 4) + ((a3[1] & 0xf0) >> 4);
a4[2] = ((a3[1] & 0x0f) << 2) + ((a3[2] & 0xc0) >> 6);
for (j = 0; j < i + 1; ++j)
{
result.push_back(alphabet[a4[j]]);
++count;
}
if (fill != 0)
{
while (i++ < 3)
{
result.push_back(fill);
++count;
}
}
}
return count;
}
template <class InputIt, class F, class Container>
typename std::enable_if<extension_traits::is_back_insertable_byte_container<Container>::value,decode_result<InputIt>>::type
decode_base64_generic(InputIt first, InputIt last,
const uint8_t reverse_alphabet[256],
F f,
Container& result)
{
uint8_t a4[4], a3[3];
uint8_t i = 0;
uint8_t j = 0;
while (first != last && *first != '=')
{
if (!f(*first))
{
return decode_result<InputIt>{first, conv_errc::conversion_failed};
}
a4[i++] = static_cast<uint8_t>(*first++);
if (i == 4)
{
for (i = 0; i < 4; ++i)
{
a4[i] = reverse_alphabet[a4[i]];
}
a3[0] = (a4[0] << 2) + ((a4[1] & 0x30) >> 4);
a3[1] = ((a4[1] & 0xf) << 4) + ((a4[2] & 0x3c) >> 2);
a3[2] = ((a4[2] & 0x3) << 6) + a4[3];
for (i = 0; i < 3; i++)
{
result.push_back(a3[i]);
}
i = 0;
}
}
if (i > 0)
{
for (j = 0; j < i; ++j)
{
a4[j] = reverse_alphabet[a4[j]];
}
a3[0] = (a4[0] << 2) + ((a4[1] & 0x30) >> 4);
a3[1] = ((a4[1] & 0xf) << 4) + ((a4[2] & 0x3c) >> 2);
for (j = 0; j < i - 1; ++j)
{
result.push_back(a3[j]);
}
}
return decode_result<InputIt>{last, conv_errc::success};
}
} // namespace detail
template <class InputIt, class Container>
typename std::enable_if<std::is_same<typename std::iterator_traits<InputIt>::value_type,uint8_t>::value,size_t>::type
encode_base16(InputIt first, InputIt last, Container& result)
{
static constexpr char characters[] = "0123456789ABCDEF";
for (auto it = first; it != last; ++it)
{
uint8_t c = *it;
result.push_back(characters[c >> 4]);
result.push_back(characters[c & 0xf]);
}
return (last-first)*2;
}
template <class InputIt, class Container>
typename std::enable_if<std::is_same<typename std::iterator_traits<InputIt>::value_type,uint8_t>::value,size_t>::type
encode_base64url(InputIt first, InputIt last, Container& result)
{
static constexpr char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789-_"
"\0";
return detail::encode_base64_generic(first, last, alphabet, result);
}
template <class InputIt, class Container>
typename std::enable_if<std::is_same<typename std::iterator_traits<InputIt>::value_type,uint8_t>::value,size_t>::type
encode_base64(InputIt first, InputIt last, Container& result)
{
static constexpr char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/"
"=";
return detail::encode_base64_generic(first, last, alphabet, result);
}
template <class Char>
bool is_base64(Char c)
{
return (c >= 0 && c < 128) && (isalnum((int)c) || c == '+' || c == '/');
}
template <class Char>
bool is_base64url(Char c)
{
return (c >= 0 && c < 128) && (isalnum((int)c) || c == '-' || c == '_');
}
inline
static bool is_base64url(int c)
{
return isalnum(c) || c == '-' || c == '_';
}
// decode
template <class InputIt, class Container>
typename std::enable_if<extension_traits::is_back_insertable_byte_container<Container>::value,decode_result<InputIt>>::type
decode_base64url(InputIt first, InputIt last, Container& result)
{
static constexpr uint8_t reverse_alphabet[256] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 62, 0xff, 0xff,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0xff, 0xff, 0xff, 0xff, 63,
0xff, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
};
auto retval = jsoncons::detail::decode_base64_generic(first, last, reverse_alphabet,
is_base64url<typename std::iterator_traits<InputIt>::value_type>,
result);
return retval.ec == conv_errc::success ? retval : decode_result<InputIt>{retval.it, conv_errc::not_base64url};
}
template <class InputIt, class Container>
typename std::enable_if<extension_traits::is_back_insertable_byte_container<Container>::value,decode_result<InputIt>>::type
decode_base64(InputIt first, InputIt last, Container& result)
{
static constexpr uint8_t reverse_alphabet[256] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 62, 0xff, 0xff, 0xff, 63,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
};
auto retval = jsoncons::detail::decode_base64_generic(first, last, reverse_alphabet,
is_base64<typename std::iterator_traits<InputIt>::value_type>,
result);
return retval.ec == conv_errc::success ? retval : decode_result<InputIt>{retval.it, conv_errc::not_base64};
}
template <class InputIt,class Container>
typename std::enable_if<extension_traits::is_back_insertable_byte_container<Container>::value,decode_result<InputIt>>::type
decode_base16(InputIt first, InputIt last, Container& result)
{
std::size_t len = std::distance(first,last);
if (len & 1)
{
return decode_result<InputIt>{first, conv_errc::not_base16};
}
InputIt it = first;
while (it != last)
{
uint8_t val;
auto a = *it++;
if (a >= '0' && a <= '9')
{
val = static_cast<uint8_t>(a - '0') << 4;
}
else if ((a | 0x20) >= 'a' && (a | 0x20) <= 'f')
{
val = (static_cast<uint8_t>((a | 0x20) - 'a') + 10) << 4;
}
else
{
return decode_result<InputIt>{first, conv_errc::not_base16};
}
auto b = *it++;
if (b >= '0' && b <= '9')
{
val |= (b - '0');
}
else if ((b | 0x20) >= 'a' && (b | 0x20) <= 'f')
{
val |= ((b | 0x20) - 'a' + 10);
}
else
{
return decode_result<InputIt>{first, conv_errc::not_base16};
}
result.push_back(val);
}
return decode_result<InputIt>{last, conv_errc::success};
}
struct byte_traits
{
using char_type = uint8_t;
static constexpr int eof()
{
return std::char_traits<char>::eof();
}
static int compare(const char_type* s1, const char_type* s2, std::size_t count) noexcept
{
return std::memcmp(s1,s2,count);
}
};
// basic_byte_string
template <class Allocator>
class basic_byte_string;
// byte_string_view
class byte_string_view
{
const uint8_t* data_;
std::size_t size_;
public:
using traits_type = byte_traits;
using const_iterator = const uint8_t*;
using iterator = const_iterator;
using size_type = std::size_t;
using value_type = uint8_t;
using reference = uint8_t&;
using const_reference = const uint8_t&;
using difference_type = std::ptrdiff_t;
using pointer = uint8_t*;
using const_pointer = const uint8_t*;
constexpr byte_string_view() noexcept
: data_(nullptr), size_(0)
{
}
constexpr byte_string_view(const uint8_t* data, std::size_t length) noexcept
: data_(data), size_(length)
{
}
template <class Container>
constexpr explicit byte_string_view(const Container& cont,
typename std::enable_if<extension_traits::is_byte_sequence<Container>::value,int>::type = 0)
: data_(reinterpret_cast<const uint8_t*>(cont.data())), size_(cont.size())
{
}
template <class Allocator>
constexpr byte_string_view(const basic_byte_string<Allocator>& bytes);
constexpr byte_string_view(const byte_string_view&) noexcept = default;
JSONCONS_CPP14_CONSTEXPR byte_string_view(byte_string_view&& other) noexcept
: data_(nullptr), size_(0)
{
const_pointer temp_data = data_;
data_ = other.data_;
other.data_ = temp_data;
size_type temp_size = size_;
size_ = other.size_;
other.size_ = temp_size;
}
byte_string_view& operator=(const byte_string_view&) = default;
byte_string_view& operator=(byte_string_view&& other) noexcept
{
std::swap(data_, other.data_);
std::swap(size_, other.size_);
return *this;
}
constexpr const uint8_t* data() const noexcept
{
return data_;
}
#if !defined(JSONCONS_NO_DEPRECATED)
JSONCONS_DEPRECATED_MSG("Instead, use size()")
std::size_t length() const
{
return size_;
}
#endif
constexpr size_t size() const noexcept
{
return size_;
}
// iterator support
constexpr const_iterator begin() const noexcept
{
return data_;
}
constexpr const_iterator end() const noexcept
{
return data_ + size_;
}
constexpr const_iterator cbegin() const noexcept
{
return data_;
}
constexpr const_iterator cend() const noexcept
{
return data_ + size_;
}
constexpr uint8_t operator[](size_type pos) const
{
return data_[pos];
}
JSONCONS_CPP14_CONSTEXPR byte_string_view substr(size_type pos) const
{
if (pos > size_)
{
JSONCONS_THROW(std::out_of_range("pos exceeds size"));
}
std::size_t n = size_ - pos;
return byte_string_view(data_ + pos, n);
}
byte_string_view substr(size_type pos, size_type n) const
{
if (pos > size_)
{
JSONCONS_THROW(std::out_of_range("pos exceeds size"));
}
if (pos + n > size_)
{
n = size_ - pos;
}
return byte_string_view(data_ + pos, n);
}
int compare(const byte_string_view& s) const noexcept
{
const int rc = traits_type::compare(data_, s.data(), (std::min)(size_, s.size()));
return rc != 0 ? rc : (size_ == s.size() ? 0 : size_ < s.size() ? -1 : 1);
}
template <class Allocator>
int compare(const basic_byte_string<Allocator>& s) const noexcept
{
const int rc = traits_type::compare(data_, s.data(), (std::min)(size_, s.size()));
return rc != 0 ? rc : (size_ == s.size() ? 0 : size_ < s.size() ? -1 : 1);
}
template <class CharT>
friend std::basic_ostream<CharT>& operator<<(std::basic_ostream<CharT>& os, const byte_string_view& bstr)
{
std::basic_ostringstream<CharT> ss;
ss.flags(std::ios::hex);
ss.fill('0');
bool first = true;
for (auto b : bstr)
{
if (first)
{
first = false;
}
else
{
ss << ',';
}
ss << std::setw(2) << static_cast<int>(b);
}
os << ss.str();
return os;
}
};
// basic_byte_string
template <class Allocator = std::allocator<uint8_t>>
class basic_byte_string
{
using byte_allocator_type = typename std::allocator_traits<Allocator>:: template rebind_alloc<uint8_t>;
std::vector<uint8_t,byte_allocator_type> data_;
public:
using traits_type = byte_traits;
using allocator_type = byte_allocator_type;
using value_type = typename std::vector<uint8_t,byte_allocator_type>::value_type;
using size_type = typename std::vector<uint8_t,byte_allocator_type>::size_type;
using difference_type = typename std::vector<uint8_t,byte_allocator_type>::difference_type;
using reference = typename std::vector<uint8_t,byte_allocator_type>::reference;
using const_reference = typename std::vector<uint8_t,byte_allocator_type>::const_reference;
using pointer = typename std::vector<uint8_t,byte_allocator_type>::pointer;
using const_pointer = typename std::vector<uint8_t,byte_allocator_type>::const_pointer;
using iterator = typename std::vector<uint8_t,byte_allocator_type>::iterator;
using const_iterator = typename std::vector<uint8_t,byte_allocator_type>::const_iterator;
basic_byte_string() = default;
explicit basic_byte_string(const Allocator& alloc)
: data_(alloc)
{
}
basic_byte_string(std::initializer_list<uint8_t> init)
: data_(std::move(init))
{
}
basic_byte_string(std::initializer_list<uint8_t> init, const Allocator& alloc)
: data_(std::move(init), alloc)
{
}
explicit basic_byte_string(const byte_string_view& v)
: data_(v.begin(),v.end())
{
}
basic_byte_string(const basic_byte_string<Allocator>& v)
: data_(v.data_)
{
}
basic_byte_string(basic_byte_string<Allocator>&& v) noexcept
: data_(std::move(v.data_))
{
}
basic_byte_string(const byte_string_view& v, const Allocator& alloc)
: data_(v.begin(),v.end(),alloc)
{
}
basic_byte_string(const uint8_t* data, std::size_t length, const Allocator& alloc = Allocator())
: data_(data, data+length,alloc)
{
}
Allocator get_allocator() const
{
return data_.get_allocator();
}
basic_byte_string& operator=(const basic_byte_string& s) = default;
basic_byte_string& operator=(basic_byte_string&& other) noexcept
{
data_.swap(other.data_);
return *this;
}
void reserve(std::size_t new_cap)
{
data_.reserve(new_cap);
}
void push_back(uint8_t b)
{
data_.push_back(b);
}
void assign(const uint8_t* s, std::size_t count)
{
data_.clear();
data_.insert(data_.end(), s, s+count);
}
void append(const uint8_t* s, std::size_t count)
{
data_.insert(data_.end(), s, s+count);
}
void clear()
{
data_.clear();
}
uint8_t operator[](size_type pos) const
{
return data_[pos];
}
// iterator support
iterator begin() noexcept
{
return data_.begin();
}
iterator end() noexcept
{
return data_.end();
}
const_iterator begin() const noexcept
{
return data_.begin();
}
const_iterator end() const noexcept
{
return data_.end();
}
uint8_t* data()
{
return data_.data();
}
const uint8_t* data() const
{
return data_.data();
}
std::size_t size() const
{
return data_.size();
}
#if !defined(JSONCONS_NO_DEPRECATED)
JSONCONS_DEPRECATED_MSG("Instead, use size()")
std::size_t length() const
{
return data_.size();
}
#endif
int compare(const byte_string_view& s) const noexcept
{
const int rc = traits_type::compare(data(), s.data(), (std::min)(size(), s.size()));
return rc != 0 ? rc : (size() == s.size() ? 0 : size() < s.size() ? -1 : 1);
}
int compare(const basic_byte_string& s) const noexcept
{
const int rc = traits_type::compare(data(), s.data(), (std::min)(size(), s.size()));
return rc != 0 ? rc : (size() == s.size() ? 0 : size() < s.size() ? -1 : 1);
}
template <class CharT>
friend std::basic_ostream<CharT>& operator<<(std::basic_ostream<CharT>& os, const basic_byte_string& o)
{
os << byte_string_view(o);
return os;
}
};
template <class Allocator>
constexpr byte_string_view::byte_string_view(const basic_byte_string<Allocator>& bytes)
: data_(bytes.data()), size_(bytes.size())
{
}
// ==
inline
bool operator==(const byte_string_view& lhs, const byte_string_view& rhs) noexcept
{
return lhs.compare(rhs) == 0;
}
template<class Allocator>
bool operator==(const byte_string_view& lhs, const basic_byte_string<Allocator>& rhs) noexcept
{
return lhs.compare(rhs) == 0;
}
template<class Allocator>
bool operator==(const basic_byte_string<Allocator>& lhs, const byte_string_view& rhs) noexcept
{
return rhs.compare(lhs) == 0;
}
template<class Allocator>
bool operator==(const basic_byte_string<Allocator>& lhs, const basic_byte_string<Allocator>& rhs) noexcept
{
return rhs.compare(lhs) == 0;
}
// !=
inline
bool operator!=(const byte_string_view& lhs, const byte_string_view& rhs) noexcept
{
return lhs.compare(rhs) != 0;
}
template<class Allocator>
bool operator!=(const byte_string_view& lhs, const basic_byte_string<Allocator>& rhs) noexcept
{
return lhs.compare(rhs) != 0;
}
template<class Allocator>
bool operator!=(const basic_byte_string<Allocator>& lhs, const byte_string_view& rhs) noexcept
{
return rhs.compare(lhs) != 0;
}
template<class Allocator>
bool operator!=(const basic_byte_string<Allocator>& lhs, const basic_byte_string<Allocator>& rhs) noexcept
{
return rhs.compare(lhs) != 0;
}
// <=
inline
bool operator<=(const byte_string_view& lhs, const byte_string_view& rhs) noexcept
{
return lhs.compare(rhs) <= 0;
}
template<class Allocator>
bool operator<=(const byte_string_view& lhs, const basic_byte_string<Allocator>& rhs) noexcept
{
return lhs.compare(rhs) <= 0;
}
template<class Allocator>
bool operator<=(const basic_byte_string<Allocator>& lhs, const byte_string_view& rhs) noexcept
{
return rhs.compare(lhs) >= 0;
}
template<class Allocator>
bool operator<=(const basic_byte_string<Allocator>& lhs, const basic_byte_string<Allocator>& rhs) noexcept
{
return rhs.compare(lhs) >= 0;
}
// <
inline
bool operator<(const byte_string_view& lhs, const byte_string_view& rhs) noexcept
{
return lhs.compare(rhs) < 0;
}
template<class Allocator>
bool operator<(const byte_string_view& lhs, const basic_byte_string<Allocator>& rhs) noexcept
{
return lhs.compare(rhs) < 0;
}
template<class Allocator>
bool operator<(const basic_byte_string<Allocator>& lhs, const byte_string_view& rhs) noexcept
{
return rhs.compare(lhs) > 0;
}
template<class Allocator>
bool operator<(const basic_byte_string<Allocator>& lhs, const basic_byte_string<Allocator>& rhs) noexcept
{
return rhs.compare(lhs) > 0;
}
// >=
inline
bool operator>=(const byte_string_view& lhs, const byte_string_view& rhs) noexcept
{
return lhs.compare(rhs) >= 0;
}
template<class Allocator>
bool operator>=(const byte_string_view& lhs, const basic_byte_string<Allocator>& rhs) noexcept
{
return lhs.compare(rhs) >= 0;
}
template<class Allocator>
bool operator>=(const basic_byte_string<Allocator>& lhs, const byte_string_view& rhs) noexcept
{
return rhs.compare(lhs) <= 0;
}
template<class Allocator>
bool operator>=(const basic_byte_string<Allocator>& lhs, const basic_byte_string<Allocator>& rhs) noexcept
{
return rhs.compare(lhs) <= 0;
}
// >
inline
bool operator>(const byte_string_view& lhs, const byte_string_view& rhs) noexcept
{
return lhs.compare(rhs) > 0;
}
template<class Allocator>
bool operator>(const byte_string_view& lhs, const basic_byte_string<Allocator>& rhs) noexcept
{
return lhs.compare(rhs) > 0;
}
template<class Allocator>
bool operator>(const basic_byte_string<Allocator>& lhs, const byte_string_view& rhs) noexcept
{
return rhs.compare(lhs) < 0;
}
template<class Allocator>
bool operator>(const basic_byte_string<Allocator>& lhs, const basic_byte_string<Allocator>& rhs) noexcept
{
return rhs.compare(lhs) < 0;
}
using byte_string = basic_byte_string<std::allocator<uint8_t>>;
namespace extension_traits {
template <typename T>
struct is_basic_byte_string
: std::false_type
{};
template <typename Allocator>
struct is_basic_byte_string<basic_byte_string<Allocator>>
: std::true_type
{};
} // namespace extension_traits
} // namespace jsoncons
#endif

View file

@ -0,0 +1,226 @@
// Copyright 2017 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_CONFIG_BINARY_CONFIG_HPP
#define JSONCONS_CONFIG_BINARY_CONFIG_HPP
#include <cfloat>
#include <cstddef>
#include <cstdint>
#include <cstring> // std::memcpy
#include <memory>
#include <type_traits> // std::enable_if
// The definitions below follow the definitions in compiler_support_p.h, https://github.com/01org/tinycbor
// MIT license
#ifdef __F16C__
# include <immintrin.h>
#endif
#ifndef __has_builtin
# define __has_builtin(x) 0
#endif
#if defined(__GNUC__)
#if (__GNUC__ * 100 + __GNUC_MINOR__ >= 403) || (__has_builtin(__builtin_bswap64) && __has_builtin(__builtin_bswap32))
# define JSONCONS_BYTE_SWAP_64 __builtin_bswap64
# define JSONCONS_BYTE_SWAP_32 __builtin_bswap32
# ifdef __INTEL_COMPILER
# define JSONCONS_BYTE_SWAP_16 _bswap16
# elif (__GNUC__ * 100 + __GNUC_MINOR__ >= 608) || __has_builtin(__builtin_bswap16)
# define JSONCONS_BYTE_SWAP_16 __builtin_bswap16
# endif
#endif
#elif defined(__sun)
# include <sys/byteorder.h>
#elif defined(_MSC_VER)
// MSVC, which implies sizeof(long) == 4
# define JSONCONS_BYTE_SWAP_64 _byteswap_uint64
# define JSONCONS_BYTE_SWAP_32 _byteswap_ulong
# define JSONCONS_BYTE_SWAP_16 _byteswap_ushort
#endif
namespace jsoncons {
namespace binary {
struct uint128_holder
{
uint64_t lo;
uint64_t hi;
};
static inline bool add_check_overflow(std::size_t v1, std::size_t v2, std::size_t *r)
{
#if ((defined(__GNUC__) && (__GNUC__ >= 5)) && !defined(__INTEL_COMPILER)) || __has_builtin(__builtin_add_overflow)
return __builtin_add_overflow(v1, v2, r);
#else
// unsigned additions are well-defined
*r = v1 + v2;
return v1 > v1 + v2;
#endif
}
#if defined(__apple_build_version__) && ((__clang_major__ < 8) || ((__clang_major__ == 8) && (__clang_minor__ < 1)))
#define APPLE_MISSING_INTRINSICS 1
#endif
inline
uint16_t encode_half(double val)
{
#if defined(__F16C__) && !defined(APPLE_MISSING_INTRINSICS)
return _cvtss_sh((float)val, 3);
#else
uint64_t v;
std::memcpy(&v, &val, sizeof(v));
int64_t sign = static_cast<int64_t>(v >> 63 << 15);
int64_t exp = (v >> 52) & 0x7ff;
int64_t mant = v << 12 >> 12 >> (53-11); /* keep only the 11 most significant bits of the mantissa */
exp -= 1023;
if (exp == 1024) {
/* infinity or NaN */
exp = 16;
mant >>= 1;
} else if (exp >= 16) {
/* overflow, as largest number */
exp = 15;
mant = 1023;
} else if (exp >= -14) {
/* regular normal */
} else if (exp >= -24) {
/* subnormal */
mant |= 1024;
mant >>= -(exp + 14);
exp = -15;
} else {
/* underflow, make zero */
return 0;
}
/* safe cast here as bit operations above guarantee not to overflow */
return static_cast<uint16_t>(sign | ((exp + 15) << 10) | mant);
#endif
}
/* this function was copied & adapted from RFC 7049 Appendix D */
inline
double decode_half(uint16_t half)
{
#if defined(__F16C__) && !defined(APPLE_MISSING_INTRINSICS)
return _cvtsh_ss(half);
#else
int64_t exp = (half >> 10) & 0x1f;
int64_t mant = half & 0x3ff;
double val;
if (exp == 0)
{
val = ldexp(static_cast<double>(mant), -24);
}
else if (exp != 31)
{
val = ldexp(static_cast<double>(mant) + 1024.0, static_cast<int>(exp - 25));
}
else
{
val = mant == 0 ? std::numeric_limits<double>::infinity() : std::nan("");
}
return half & 0x8000 ? -val : val;
#endif
}
// byte_swap
template<class T>
typename std::enable_if<std::is_integral<T>::value && sizeof(T) == sizeof(uint8_t),T>::type
byte_swap(T val)
{
return val;
}
template<class T>
typename std::enable_if<std::is_integral<T>::value && sizeof(T) == sizeof(uint16_t),T>::type
byte_swap(T val)
{
#if defined(JSONCONS_BYTE_SWAP_16)
return JSONCONS_BYTE_SWAP_16(val);
#else
return (static_cast<uint16_t>(val) >> 8) | (static_cast<uint16_t>(val) << 8);
#endif
}
template<class T>
typename std::enable_if<std::is_integral<T>::value && sizeof(T) == sizeof(uint32_t),T>::type
byte_swap(T val)
{
#if defined(JSONCONS_BYTE_SWAP_32)
return JSONCONS_BYTE_SWAP_32(val);
#else
uint32_t tmp = ((static_cast<uint32_t>(val) << 8) & 0xff00ff00) | ((static_cast<uint32_t>(val) >> 8) & 0xff00ff);
return (tmp << 16) | (tmp >> 16);
#endif
}
template<class T>
typename std::enable_if<std::is_integral<T>::value && sizeof(T) == sizeof(uint64_t),T>::type
byte_swap(T val)
{
#if defined(JSONCONS_BYTE_SWAP_64)
return JSONCONS_BYTE_SWAP_64(val);
#else
uint64_t tmp = ((static_cast<uint64_t>(val) & 0x00000000ffffffffull) << 32) | ((static_cast<uint64_t>(val) & 0xffffffff00000000ull) >> 32);
tmp = ((tmp & 0x0000ffff0000ffffull) << 16) | ((tmp & 0xffff0000ffff0000ull) >> 16);
return ((tmp & 0x00ff00ff00ff00ffull) << 8) | ((tmp & 0xff00ff00ff00ff00ull) >> 8);
#endif
}
template<class T>
typename std::enable_if<std::is_floating_point<T>::value && sizeof(T) == sizeof(uint32_t),T>::type
byte_swap(T val)
{
uint32_t x;
std::memcpy(&x,&val,sizeof(uint32_t));
uint32_t y = byte_swap(x);
T val2;
std::memcpy(&val2,&y,sizeof(uint32_t));
return val2;
}
template<class T>
typename std::enable_if<std::is_floating_point<T>::value && sizeof(T) == sizeof(uint64_t),T>::type
byte_swap(T val)
{
uint64_t x;
std::memcpy(&x,&val,sizeof(uint64_t));
uint64_t y = byte_swap(x);
T val2;
std::memcpy(&val2,&y,sizeof(uint64_t));
return val2;
}
template<class T>
typename std::enable_if<std::is_floating_point<T>::value && sizeof(T) == 2*sizeof(uint64_t),T>::type
byte_swap(T val)
{
uint128_holder x;
uint8_t buf[2*sizeof(uint64_t)];
std::memcpy(buf,&val,2*sizeof(uint64_t));
std::memcpy(&x.lo,buf,sizeof(uint64_t));
std::memcpy(&x.hi,buf+sizeof(uint64_t),sizeof(uint64_t));
uint128_holder y;
y.lo = byte_swap(x.hi);
y.hi = byte_swap(x.lo);
T val2;
std::memcpy(&val2,&y,2*sizeof(uint64_t));
return val2;
}
} // binary
} // jsoncons
#endif

View file

@ -0,0 +1,375 @@
// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_COMPILER_SUPPORT_HPP
#define JSONCONS_COMPILER_SUPPORT_HPP
#include <stdexcept>
#include <string>
#include <cmath>
#include <exception>
#include <ostream>
#if defined (__clang__)
#define JSONCONS_CLANG_VERSION (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__)
#endif
// Uncomment the following line to suppress deprecated names (recommended for new code)
//#define JSONCONS_NO_DEPRECATED
// The definitions below follow the definitions in compiler_support_p.h, https://github.com/01org/tinycbor
// MIT license
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54577
#if defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ < 9
#define JSONCONS_NO_VECTOR_ERASE_TAKES_CONST_ITERATOR 1
#define JSONCONS_NO_MAP_CONS_TAKES_ALLOCATOR 1
#endif
#if defined(__clang__)
# define JSONCONS_FALLTHROUGH [[clang::fallthrough]]
#elif defined(__GNUC__) && ((__GNUC__ >= 7))
# define JSONCONS_FALLTHROUGH __attribute__((fallthrough))
#elif defined (__GNUC__)
# define JSONCONS_FALLTHROUGH // FALLTHRU
#else
# define JSONCONS_FALLTHROUGH
#endif
#if defined(__GNUC__) || defined(__clang__)
#define JSONCONS_LIKELY(x) __builtin_expect(!!(x), 1)
#define JSONCONS_UNLIKELY(x) __builtin_expect(!!(x), 0)
#define JSONCONS_UNREACHABLE() __builtin_unreachable()
#elif defined(_MSC_VER)
#define JSONCONS_LIKELY(x) x
#define JSONCONS_UNLIKELY(x) x
#define JSONCONS_UNREACHABLE() __assume(0)
#else
#define JSONCONS_LIKELY(x) x
#define JSONCONS_UNLIKELY(x) x
#define JSONCONS_UNREACHABLE() do {} while (0)
#endif
// Deprecated symbols markup
#if (defined(__cplusplus) && __cplusplus >= 201402L)
#define JSONCONS_DEPRECATED_MSG(msg) [[deprecated(msg)]]
#endif
#if !defined(JSONCONS_DEPRECATED_MSG) && defined(__GNUC__) && defined(__has_extension)
#if __has_extension(attribute_deprecated_with_message)
#define JSONCONS_DEPRECATED_MSG(msg) __attribute__((deprecated(msg)))
#endif
#endif
#if !defined(JSONCONS_DEPRECATED_MSG) && defined(_MSC_VER)
#if (_MSC_VER) >= 1920
#define JSONCONS_DEPRECATED_MSG(msg) [[deprecated(msg)]]
#else
#define JSONCONS_DEPRECATED_MSG(msg) __declspec(deprecated(msg))
#endif
#endif
// Following boost/atomic/detail/config.hpp
#if !defined(JSONCONS_DEPRECATED_MSG) && (\
(defined(__GNUC__) && ((__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0)) >= 405) ||\
(defined(__SUNPRO_CC) && (__SUNPRO_CC + 0) >= 0x5130))
#define JSONCONS_DEPRECATED_MSG(msg) __attribute__((deprecated(msg)))
#endif
#if !defined(JSONCONS_DEPRECATED_MSG) && defined(__clang__) && defined(__has_extension)
#if __has_extension(attribute_deprecated_with_message)
#define JSONCONS_DEPRECATED_MSG(msg) __attribute__((deprecated(msg)))
#else
#define JSONCONS_DEPRECATED_MSG(msg) __attribute__((deprecated))
#endif
#endif
#if !defined(JSONCONS_DEPRECATED_MSG)
#define JSONCONS_DEPRECATED_MSG(msg)
#endif
#if defined(ANDROID) || defined(__ANDROID__)
#if __ANDROID_API__ >= 21
#define JSONCONS_HAS_STRTOLD_L
#else
#define JSONCONS_NO_LOCALECONV
#endif
#endif
#if defined(_MSC_VER)
#define JSONCONS_HAS_MSC_STRTOD_L
#define JSONCONS_HAS_FOPEN_S
#endif
#ifndef JSONCONS_HAS_CP14
#if defined(_MSVC_LANG)
#if _MSVC_LANG >= 201402L
#define JSONCONS_HAS_CP14
#endif
#elif __cplusplus >= 201402L
#define JSONCONS_HAS_CP14
#endif
#endif
#if defined(JSONCONS_HAS_STD_FROM_CHARS) && JSONCONS_HAS_STD_FROM_CHARS
#include <charconv>
#endif
#if !defined(JSONCONS_HAS_2017)
# if defined(__clang__)
# if (__cplusplus >= 201703)
# define JSONCONS_HAS_2017 1
# endif // (__cplusplus >= 201703)
# endif // defined(__clang__)
# if defined(__GNUC__)
# if (__GNUC__ >= 7)
# if (__cplusplus >= 201703)
# define JSONCONS_HAS_2017 1
# endif // (__cplusplus >= 201703)
# endif // (__GNUC__ >= 7)
# endif // defined(__GNUC__)
# if defined(_MSC_VER)
# if (_MSC_VER >= 1910 && _MSVC_LANG >= 201703)
# define JSONCONS_HAS_2017 1
# endif // (_MSC_VER >= 1910 && MSVC_LANG >= 201703)
# endif // defined(_MSC_VER)
#endif
#if defined(JSONCONS_HAS_2017)
#define JSONCONS_NODISCARD [[nodiscard]]
#define JSONCONS_IF_CONSTEXPR if constexpr
#else
#define JSONCONS_NODISCARD
#define JSONCONS_IF_CONSTEXPR if
#endif
#if !defined(JSONCONS_HAS_STD_STRING_VIEW)
# if (defined JSONCONS_HAS_2017)
# if defined(__clang__)
# if __has_include(<string_view>)
# define JSONCONS_HAS_STD_STRING_VIEW 1
# endif // __has_include(<string_view>)
# else
# define JSONCONS_HAS_STD_STRING_VIEW 1
# endif
# endif // defined(JSONCONS_HAS_2017)
#endif // !defined(JSONCONS_HAS_STD_STRING_VIEW)
#if !defined(JSONCONS_HAS_STD_BYTE)
# if (defined JSONCONS_HAS_2017)
# define JSONCONS_HAS_STD_BYTE 1
# endif // defined(JSONCONS_HAS_2017)
#endif // !defined(JSONCONS_HAS_STD_BYTE)
#if !defined(JSONCONS_HAS_STD_OPTIONAL)
# if (defined JSONCONS_HAS_2017)
# if defined(__clang__)
# if __has_include(<optional>)
# define JSONCONS_HAS_STD_OPTIONAL 1
# endif // __has_include(<string_view>)
# else
# define JSONCONS_HAS_STD_OPTIONAL 1
# endif
# endif // defined(JSONCONS_HAS_2017)
#endif // !defined(JSONCONS_HAS_STD_OPTIONAL)
#if !defined(JSONCONS_HAS_STD_VARIANT)
# if (defined JSONCONS_HAS_2017)
# if defined(__clang__)
# if defined(__APPLE__)
# if JSONCONS_CLANG_VERSION >= 100001
# define JSONCONS_HAS_STD_VARIANT 1
# endif
# elif __has_include(<variant>)
# define JSONCONS_HAS_STD_VARIANT 1
# endif // __has_include(<variant>)
# else
# define JSONCONS_HAS_STD_VARIANT 1
# endif
# endif // defined(JSONCONS_HAS_2017)
#endif // !defined(JSONCONS_HAS_STD_VARIANT)
#if !defined(JSONCONS_HAS_FILESYSTEM)
# if (defined JSONCONS_HAS_2017)
# if defined(__clang__)
# if __has_include(<filesystem>)
# define JSONCONS_HAS_FILESYSTEM 1
# endif // __has_include(<filesystem>)
# else
# define JSONCONS_HAS_FILESYSTEM 1
# endif
# endif // defined(JSONCONS_HAS_2017)
#endif // !defined(JSONCONS_HAS_FILESYSTEM)
#if (!defined(JSONCONS_NO_EXCEPTIONS))
// Check if exceptions are disabled.
# if defined( __cpp_exceptions) && __cpp_exceptions == 0
# define JSONCONS_NO_EXCEPTIONS 1
# endif
#endif
#if !defined(JSONCONS_NO_EXCEPTIONS)
#if defined(__GNUC__) && !__EXCEPTIONS
# define JSONCONS_NO_EXCEPTIONS 1
#elif _MSC_VER
#if defined(_HAS_EXCEPTIONS) && _HAS_EXCEPTIONS == 0
# define JSONCONS_NO_EXCEPTIONS 1
#elif !defined(_CPPUNWIND)
# define JSONCONS_NO_EXCEPTIONS 1
#endif
#endif
#endif
// allow to disable exceptions
#if !defined(JSONCONS_NO_EXCEPTIONS)
#define JSONCONS_THROW(exception) throw exception
#define JSONCONS_RETHROW throw
#define JSONCONS_TRY try
#define JSONCONS_CATCH(exception) catch(exception)
#else
#define JSONCONS_THROW(exception) std::terminate()
#define JSONCONS_RETHROW std::terminate()
#define JSONCONS_TRY if (true)
#define JSONCONS_CATCH(exception) if (false)
#endif
#if !defined(JSONCONS_HAS_STD_MAKE_UNIQUE)
#if defined(__clang__) && defined(__cplusplus)
#if defined(__APPLE__)
#if __clang_major__ >= 6 && __cplusplus >= 201402L // Xcode 6
#define JSONCONS_HAS_STD_MAKE_UNIQUE
#endif
#elif ((__clang_major__*100 +__clang_minor__) >= 340) && __cplusplus >= 201402L
#define JSONCONS_HAS_STD_MAKE_UNIQUE
#endif
#elif defined(__GNUC__)
#if (__GNUC__ * 100 + __GNUC_MINOR__) >= 409 && __cplusplus > 201103L
#define JSONCONS_HAS_STD_MAKE_UNIQUE
#endif
#elif defined(_MSC_VER)
#if _MSC_VER >= 1800
#define JSONCONS_HAS_STD_MAKE_UNIQUE
#endif
#endif
#endif // !defined(JSONCONS_HAS_STD_MAKE_UNIQUE)
#ifndef JSONCONS_HAS_CP14_CONSTEXPR
#if defined(_MSC_VER)
#if _MSC_VER >= 1910
#define JSONCONS_HAS_CP14_CONSTEXPR
#endif
#elif defined(__GNUC__)
#if (__GNUC__ * 100 + __GNUC_MINOR__) >= 600 && __cplusplus >= 201402L
#define JSONCONS_HAS_CP14_CONSTEXPR
#endif
#endif
#endif
#if defined(JSONCONS_HAS_CP14_CONSTEXPR)
# define JSONCONS_CPP14_CONSTEXPR constexpr
#else
# define JSONCONS_CPP14_CONSTEXPR
#endif
// Follows boost
// gcc and clang
#if (defined(__clang__) || defined(__GNUC__)) && defined(__cplusplus)
#if defined(__SIZEOF_INT128__) && !defined(_MSC_VER)
# define JSONCONS_HAS_INT128
#endif
#if (defined(linux) || defined(__linux) || defined(__linux__) || defined(__GNU__) || defined(__GLIBC__)) && !defined(_CRAYC)
#if (__clang_major__ >= 4) && defined(__has_include)
#if __has_include(<quadmath.h>)
# define JSONCONS_HAS_FLOAT128
#endif
#endif
#endif
#endif
#if defined(__GNUC__)
#if defined(_GLIBCXX_USE_FLOAT128)
# define JSONCONS_HAS_FLOAT128
#endif
#endif
#if defined(__clang__)
#if (defined(linux) || defined(__linux) || defined(__linux__) || defined(__GNU__) || defined(__GLIBC__)) && !defined(_CRAYC)
#if (__clang_major__ >= 4) && defined(__has_include)
#if __has_include(<quadmath.h>)
# define JSONCONS_HAS_FLOAT128
#endif
#endif
#endif
#endif
// Follows boost config/detail/suffix.hpp
#if defined(JSONCONS_HAS_INT128) && defined(__cplusplus)
namespace jsoncons{
# ifdef __GNUC__
__extension__ typedef __int128 int128_type;
__extension__ typedef unsigned __int128 uint128_type;
# else
typedef __int128 int128_type;
typedef unsigned __int128 uint128_type;
# endif
}
#endif
#if defined(JSONCONS_HAS_FLOAT128) && defined(__cplusplus)
namespace jsoncons {
# ifdef __GNUC__
__extension__ typedef __float128 float128_type;
# else
typedef __float128 float128_type;
# endif
}
#endif
#if defined(_MSC_VER) && _MSC_VER <= 1900
#define JSONCONS_COPY(first,last,d_first) std::copy(first, last, stdext::make_checked_array_iterator(d_first, static_cast<std::size_t>(std::distance(first, last))))
#else
#define JSONCONS_COPY(first,last,d_first) std::copy(first, last, d_first)
#endif
#if defined(_MSC_VER) && _MSC_VER <= 1900
#define JSONCONS_CONSTEXPR
#else
#define JSONCONS_CONSTEXPR constexpr
#endif
namespace jsoncons {
class assertion_error : public std::runtime_error
{
public:
assertion_error(const std::string& s) noexcept
: std::runtime_error(s)
{
}
const char* what() const noexcept override
{
return std::runtime_error::what();
}
};
} // namespace jsoncons
#define JSONCONS_STR2(x) #x
#define JSONCONS_STR(x) JSONCONS_STR2(x)
#ifdef _DEBUG
#define JSONCONS_ASSERT(x) if (!(x)) { \
JSONCONS_THROW(jsoncons::assertion_error("assertion '" #x "' failed at " __FILE__ ":" \
JSONCONS_STR(__LINE__))); }
#else
#define JSONCONS_ASSERT(x) if (!(x)) { \
JSONCONS_THROW(jsoncons::assertion_error("assertion '" #x "' failed at <> :" \
JSONCONS_STR( 0 ))); }
#endif // _DEBUG
#endif // JSONCONS_COMPILER_SUPPORT_HPP

View file

@ -0,0 +1,313 @@
// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_CONFIG_JSONCONS_CONFIG_HPP
#define JSONCONS_CONFIG_JSONCONS_CONFIG_HPP
#include <type_traits>
#include <limits>
#include <jsoncons/config/compiler_support.hpp>
#include <jsoncons/config/binary_config.hpp>
#if !defined(JSONCONS_HAS_STD_STRING_VIEW)
#include <jsoncons/detail/string_view.hpp>
namespace jsoncons {
using jsoncons::detail::basic_string_view;
using string_view = basic_string_view<char, std::char_traits<char>>;
using wstring_view = basic_string_view<wchar_t, std::char_traits<wchar_t>>;
}
#else
#include <string_view>
namespace jsoncons {
using std::basic_string_view;
using std::string_view;
using std::wstring_view;
}
#endif
#if !defined(JSONCONS_HAS_STD_SPAN)
#include <jsoncons/detail/span.hpp>
namespace jsoncons {
using jsoncons::detail::span;
}
#else
#include <span>
namespace jsoncons {
using std::span;
}
#endif
#if defined(JSONCONS_HAS_STD_OPTIONAL)
#include <optional>
namespace jsoncons {
using std::optional;
}
#elif defined(JSONCONS_HAS_BOOST_OPTIONAL)
#include <boost/optional.hpp>
namespace jsoncons {
using boost::optional;
}
#else
#include <jsoncons/detail/optional.hpp>
namespace jsoncons {
using jsoncons::detail::optional;
}
#endif // !defined(JSONCONS_HAS_STD_OPTIONAL)
#if !defined(JSONCONS_HAS_STD_ENDIAN)
#include <jsoncons/detail/endian.hpp>
namespace jsoncons {
using jsoncons::detail::endian;
}
#else
#include <bit>
namespace jsoncons
{
using std::endian;
}
#endif
#if !defined(JSONCONS_HAS_STD_MAKE_UNIQUE)
#include <cstddef>
#include <memory>
#include <type_traits>
#include <utility>
namespace jsoncons {
template<class T>
struct unique_if
{
using value_is_not_array = std::unique_ptr<T>;
};
template<class T>
struct unique_if<T[]>
{
typedef std::unique_ptr<T[]> value_is_array_of_unknown_bound;
};
template<class T, std::size_t N>
struct unique_if<T[N]> {
using value_is_array_of_known_bound = void;
};
template<class T, class... Args>
typename unique_if<T>::value_is_not_array
make_unique(Args&&... args)
{
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
template<class T>
typename unique_if<T>::value_is_array_of_unknown_bound
make_unique(std::size_t n)
{
using U = typename std::remove_extent<T>::type;
return std::unique_ptr<T>(new U[n]());
}
template<class T, class... Args>
typename unique_if<T>::value_is_array_of_known_bound
make_unique(Args&&...) = delete;
} // jsoncons
#else
#include <memory>
namespace jsoncons
{
using std::make_unique;
}
#endif // !defined(JSONCONS_HAS_STD_MAKE_UNIQUE)
namespace jsoncons {
namespace binary {
// native_to_big
template<typename T, class OutputIt, class Endian=endian>
typename std::enable_if<Endian::native == Endian::big,void>::type
native_to_big(T val, OutputIt d_first)
{
uint8_t buf[sizeof(T)];
std::memcpy(buf, &val, sizeof(T));
for (auto item : buf)
{
*d_first++ = item;
}
}
template<typename T, class OutputIt, class Endian=endian>
typename std::enable_if<Endian::native == Endian::little,void>::type
native_to_big(T val, OutputIt d_first)
{
T val2 = byte_swap(val);
uint8_t buf[sizeof(T)];
std::memcpy(buf, &val2, sizeof(T));
for (auto item : buf)
{
*d_first++ = item;
}
}
// native_to_little
template<typename T, class OutputIt, class Endian = endian>
typename std::enable_if<Endian::native == Endian::little,void>::type
native_to_little(T val, OutputIt d_first)
{
uint8_t buf[sizeof(T)];
std::memcpy(buf, &val, sizeof(T));
for (auto item : buf)
{
*d_first++ = item;
}
}
template<typename T, class OutputIt, class Endian=endian>
typename std::enable_if<Endian::native == Endian::big, void>::type
native_to_little(T val, OutputIt d_first)
{
T val2 = byte_swap(val);
uint8_t buf[sizeof(T)];
std::memcpy(buf, &val2, sizeof(T));
for (auto item : buf)
{
*d_first++ = item;
}
}
// big_to_native
template<class T,class Endian=endian>
typename std::enable_if<Endian::native == Endian::big,T>::type
big_to_native(const uint8_t* first, std::size_t count)
{
if (sizeof(T) > count)
{
return T{};
}
T val;
std::memcpy(&val,first,sizeof(T));
return val;
}
template<class T,class Endian=endian>
typename std::enable_if<Endian::native == Endian::little,T>::type
big_to_native(const uint8_t* first, std::size_t count)
{
if (sizeof(T) > count)
{
return T{};
}
T val;
std::memcpy(&val,first,sizeof(T));
return byte_swap(val);
}
// little_to_native
template<class T,class Endian=endian>
typename std::enable_if<Endian::native == Endian::little,T>::type
little_to_native(const uint8_t* first, std::size_t count)
{
if (sizeof(T) > count)
{
return T{};
}
T val;
std::memcpy(&val,first,sizeof(T));
return val;
}
template<class T,class Endian=endian>
typename std::enable_if<Endian::native == Endian::big,T>::type
little_to_native(const uint8_t* first, std::size_t count)
{
if (sizeof(T) > count)
{
return T{};
}
T val;
std::memcpy(&val,first,sizeof(T));
return byte_swap(val);
}
} // binary
} // jsoncons
namespace jsoncons {
template<typename CharT>
constexpr const CharT* cstring_constant_of_type(const char* c, const wchar_t* w);
template<> inline
constexpr const char* cstring_constant_of_type<char>(const char* c, const wchar_t*)
{
return c;
}
template<> inline
constexpr const wchar_t* cstring_constant_of_type<wchar_t>(const char*, const wchar_t* w)
{
return w;
}
template<typename CharT>
std::basic_string<CharT> string_constant_of_type(const char* c, const wchar_t* w);
template<> inline
std::string string_constant_of_type<char>(const char* c, const wchar_t*)
{
return std::string(c);
}
template<> inline
std::wstring string_constant_of_type<wchar_t>(const char*, const wchar_t* w)
{
return std::wstring(w);
}
template<typename CharT>
jsoncons::basic_string_view<CharT> string_view_constant_of_type(const char* c, const wchar_t* w);
template<> inline
jsoncons::string_view string_view_constant_of_type<char>(const char* c, const wchar_t*)
{
return jsoncons::string_view(c);
}
template<> inline
jsoncons::wstring_view string_view_constant_of_type<wchar_t>(const char*, const wchar_t* w)
{
return jsoncons::wstring_view(w);
}
} // jsoncons
#define JSONCONS_EXPAND(X) X
#define JSONCONS_QUOTE(Prefix, A) JSONCONS_EXPAND(Prefix ## #A)
#define JSONCONS_WIDEN(A) JSONCONS_EXPAND(L ## A)
#define JSONCONS_CSTRING_CONSTANT(CharT, Str) cstring_constant_of_type<CharT>(Str, JSONCONS_WIDEN(Str))
#define JSONCONS_STRING_CONSTANT(CharT, Str) string_constant_of_type<CharT>(Str, JSONCONS_WIDEN(Str))
#define JSONCONS_STRING_VIEW_CONSTANT(CharT, Str) string_view_constant_of_type<CharT>(Str, JSONCONS_WIDEN(Str))
#if defined(__clang__)
#define JSONCONS_HAS_STD_REGEX 1
#define JSONCONS_HAS_STATEFUL_ALLOCATOR 1
#elif (defined(__GNUC__) && (__GNUC__ == 4)) && (defined(__GNUC__) && __GNUC_MINOR__ < 9)
// GCC 4.8 has broken regex support: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53631
// gcc 4.8 basic_string doesn't satisfy C++11 allocator requirements
// and gcc doesn't support allocators with no default constructor
#else
#define JSONCONS_HAS_STD_REGEX 1
#define JSONCONS_HAS_STATEFUL_ALLOCATOR 1
#endif
#endif // JSONCONS_CONFIG_JSONCONS_CONFIG_HPP

View file

@ -0,0 +1,40 @@
// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_VERSION_HPP
#define JSONCONS_VERSION_HPP
#include <iostream>
#define JSONCONS_VERSION_MAJOR 0
#define JSONCONS_VERSION_MINOR 170
#define JSONCONS_VERSION_PATCH 2
namespace jsoncons {
struct versioning_info
{
unsigned int const major;
unsigned int const minor;
unsigned int const patch;
friend std::ostream& operator<<(std::ostream& os, const versioning_info& ver)
{
os << ver.major << '.'
<< ver.minor << '.'
<< ver.patch;
return os;
}
};
constexpr versioning_info version()
{
return versioning_info{JSONCONS_VERSION_MAJOR, JSONCONS_VERSION_MINOR, JSONCONS_VERSION_PATCH};
}
}
#endif

View file

@ -0,0 +1,218 @@
/// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_CONV_ERROR_HPP
#define JSONCONS_CONV_ERROR_HPP
#include <system_error>
#include <jsoncons/config/jsoncons_config.hpp>
namespace jsoncons {
class conv_error : public std::system_error, public virtual json_exception
{
std::size_t line_number_;
std::size_t column_number_;
mutable std::string what_;
public:
conv_error(std::error_code ec)
: std::system_error(ec), line_number_(0), column_number_(0)
{
}
conv_error(std::error_code ec, const std::string& what_arg)
: std::system_error(ec, what_arg), line_number_(0), column_number_(0)
{
}
conv_error(std::error_code ec, std::size_t position)
: std::system_error(ec), line_number_(0), column_number_(position)
{
}
conv_error(std::error_code ec, std::size_t line, std::size_t column)
: std::system_error(ec), line_number_(line), column_number_(column)
{
}
conv_error(const conv_error& other) = default;
conv_error(conv_error&& other) = default;
const char* what() const noexcept override
{
if (what_.empty())
{
JSONCONS_TRY
{
what_.append(std::system_error::what());
if (line_number_ != 0 && column_number_ != 0)
{
what_.append(" at line ");
what_.append(std::to_string(line_number_));
what_.append(" and column ");
what_.append(std::to_string(column_number_));
}
else if (column_number_ != 0)
{
what_.append(" at position ");
what_.append(std::to_string(column_number_));
}
return what_.c_str();
}
JSONCONS_CATCH(...)
{
return std::system_error::what();
}
}
else
{
return what_.c_str();
}
}
std::size_t line() const noexcept
{
return line_number_;
}
std::size_t column() const noexcept
{
return column_number_;
}
};
enum class conv_errc
{
success = 0,
conversion_failed,
not_utf8,
not_wide_char,
not_vector,
not_array,
not_map,
not_pair,
not_string,
not_string_view,
not_byte_string,
not_byte_string_view,
not_integer,
not_signed_integer,
not_unsigned_integer,
not_bigint,
not_double,
not_bool,
not_variant,
not_nullptr,
not_jsoncons_null_type,
not_bitset,
not_base64,
not_base64url,
not_base16
};
template <class InputIt>
struct decode_result
{
InputIt it;
conv_errc ec;
};
#if !defined(JSONCONS_NO_DEPRECATED)
JSONCONS_DEPRECATED_MSG("Instead, use conv_error") typedef conv_error convert_error;
#endif
} // namespace jsoncons
namespace std {
template<>
struct is_error_code_enum<jsoncons::conv_errc> : public true_type
{
};
}
namespace jsoncons {
namespace detail {
class conv_error_category_impl
: public std::error_category
{
public:
const char* name() const noexcept override
{
return "jsoncons/convert";
}
std::string message(int ev) const override
{
switch (static_cast<conv_errc>(ev))
{
case conv_errc::conversion_failed:
return "Unable to convert into the provided type";
case conv_errc::not_utf8:
return "Cannot convert string to UTF-8";
case conv_errc::not_wide_char:
return "Cannot convert string to wide characters";
case conv_errc::not_vector:
return "Cannot convert to vector";
case conv_errc::not_array:
return "Cannot convert to std::array";
case conv_errc::not_map:
return "Cannot convert to map";
case conv_errc::not_pair:
return "Cannot convert to std::pair";
case conv_errc::not_string:
return "Cannot convert to string";
case conv_errc::not_string_view:
return "Cannot convert to string_view";
case conv_errc::not_byte_string:
return "Cannot convert to byte_string";
case conv_errc::not_byte_string_view:
return "Cannot convert to byte_string_view";
case conv_errc::not_integer:
return "Cannot convert to integer";
case conv_errc::not_signed_integer:
return "Cannot convert to signed integer";
case conv_errc::not_unsigned_integer:
return "Cannot convert to unsigned integer";
case conv_errc::not_bigint:
return "Cannot convert to bigint";
case conv_errc::not_double:
return "Cannot convert to double";
case conv_errc::not_bool:
return "Cannot convert to bool";
case conv_errc::not_variant:
return "Cannot convert to std::variant";
case conv_errc::not_nullptr:
return "Cannot convert to std::nullptr_t";
case conv_errc::not_jsoncons_null_type:
return "Cannot convert to jsoncons::null_type";
case conv_errc::not_bitset:
return "Cannot convert to std::bitset";
case conv_errc::not_base64:
return "Input is not a base64 encoded string";
case conv_errc::not_base64url:
return "Input is not a base64url encoded string";
case conv_errc::not_base16:
return "Input is not a base16 encoded string";
default:
return "Unknown conversion error";
}
}
};
} // detail
extern inline
const std::error_category& conv_error_category()
{
static detail::conv_error_category_impl instance;
return instance;
}
inline
std::error_code make_error_code(conv_errc result)
{
return std::error_code(static_cast<int>(result),conv_error_category());
}
}
#endif

View file

@ -0,0 +1,209 @@
// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_DECODE_JSON_HPP
#define JSONCONS_DECODE_JSON_HPP
#include <iostream>
#include <string>
#include <tuple>
#include <memory>
#include <istream> // std::basic_istream
#include <jsoncons/decode_traits.hpp>
#include <jsoncons/json_cursor.hpp>
namespace jsoncons {
// decode_json
template <class T, class Source>
typename std::enable_if<extension_traits::is_basic_json<T>::value &&
extension_traits::is_sequence_of<Source,typename T::char_type>::value,T>::type
decode_json(const Source& s,
const basic_json_decode_options<typename Source::value_type>& options = basic_json_decode_options<typename Source::value_type>())
{
using char_type = typename Source::value_type;
jsoncons::json_decoder<T> decoder;
basic_json_reader<char_type, string_source<char_type>> reader(s, decoder, options);
reader.read();
if (!decoder.is_valid())
{
JSONCONS_THROW(ser_error(conv_errc::conversion_failed, reader.line(), reader.column()));
}
return decoder.get_result();
}
template <class T, class Source>
typename std::enable_if<!extension_traits::is_basic_json<T>::value &&
extension_traits::is_char_sequence<Source>::value,T>::type
decode_json(const Source& s,
const basic_json_decode_options<typename Source::value_type>& options = basic_json_decode_options<typename Source::value_type>())
{
using char_type = typename Source::value_type;
basic_json_cursor<char_type,string_source<char_type>> cursor(s, options, default_json_parsing());
jsoncons::json_decoder<basic_json<char_type>> decoder;
std::error_code ec;
T val = decode_traits<T,char_type>::decode(cursor, decoder, ec);
if (ec)
{
JSONCONS_THROW(ser_error(ec, cursor.context().line(), cursor.context().column()));
}
return val;
}
template <class T, class CharT>
typename std::enable_if<extension_traits::is_basic_json<T>::value,T>::type
decode_json(std::basic_istream<CharT>& is,
const basic_json_decode_options<CharT>& options = basic_json_decode_options<CharT>())
{
jsoncons::json_decoder<T> decoder;
basic_json_reader<CharT, stream_source<CharT>> reader(is, decoder, options);
reader.read();
if (!decoder.is_valid())
{
JSONCONS_THROW(ser_error(conv_errc::conversion_failed, reader.line(), reader.column()));
}
return decoder.get_result();
}
template <class T, class CharT>
typename std::enable_if<!extension_traits::is_basic_json<T>::value,T>::type
decode_json(std::basic_istream<CharT>& is,
const basic_json_decode_options<CharT>& options = basic_json_decode_options<CharT>())
{
basic_json_cursor<CharT> cursor(is, options, default_json_parsing());
json_decoder<basic_json<CharT>> decoder{};
std::error_code ec;
T val = decode_traits<T,CharT>::decode(cursor, decoder, ec);
if (ec)
{
JSONCONS_THROW(ser_error(ec, cursor.line(), cursor.column()));
}
return val;
}
template <class T, class InputIt>
typename std::enable_if<extension_traits::is_basic_json<T>::value,T>::type
decode_json(InputIt first, InputIt last,
const basic_json_decode_options<typename std::iterator_traits<InputIt>::value_type>& options =
basic_json_decode_options<typename std::iterator_traits<InputIt>::value_type>())
{
using char_type = typename std::iterator_traits<InputIt>::value_type;
jsoncons::json_decoder<T> decoder;
basic_json_reader<char_type, iterator_source<InputIt>> reader(iterator_source<InputIt>(first,last), decoder, options);
reader.read();
if (!decoder.is_valid())
{
JSONCONS_THROW(ser_error(conv_errc::conversion_failed, reader.line(), reader.column()));
}
return decoder.get_result();
}
template <class T, class InputIt>
typename std::enable_if<!extension_traits::is_basic_json<T>::value,T>::type
decode_json(InputIt first, InputIt last,
const basic_json_decode_options<typename std::iterator_traits<InputIt>::value_type>& options =
basic_json_decode_options<typename std::iterator_traits<InputIt>::value_type>())
{
using char_type = typename std::iterator_traits<InputIt>::value_type;
basic_json_cursor<char_type,iterator_source<InputIt>> cursor(iterator_source<InputIt>(first, last), options, default_json_parsing());
jsoncons::json_decoder<basic_json<char_type>> decoder;
std::error_code ec;
T val = decode_traits<T,char_type>::decode(cursor, decoder, ec);
if (ec)
{
JSONCONS_THROW(ser_error(ec, cursor.line(), cursor.column()));
}
return val;
}
// With leading allocator parameter
template <class T,class Source,class TempAllocator>
typename std::enable_if<extension_traits::is_basic_json<T>::value &&
extension_traits::is_sequence_of<Source,typename T::char_type>::value,T>::type
decode_json(temp_allocator_arg_t, const TempAllocator& temp_alloc,
const Source& s,
const basic_json_decode_options<typename Source::value_type>& options = basic_json_decode_options<typename Source::value_type>())
{
using char_type = typename Source::value_type;
json_decoder<T,TempAllocator> decoder(temp_alloc);
basic_json_reader<char_type, string_source<char_type>,TempAllocator> reader(s, decoder, options, temp_alloc);
reader.read();
if (!decoder.is_valid())
{
JSONCONS_THROW(ser_error(conv_errc::conversion_failed, reader.line(), reader.column()));
}
return decoder.get_result();
}
template <class T,class Source,class TempAllocator>
typename std::enable_if<!extension_traits::is_basic_json<T>::value &&
extension_traits::is_char_sequence<Source>::value,T>::type
decode_json(temp_allocator_arg_t, const TempAllocator& temp_alloc,
const Source& s,
const basic_json_decode_options<typename Source::value_type>& options = basic_json_decode_options<typename Source::value_type>())
{
using char_type = typename Source::value_type;
basic_json_cursor<char_type,string_source<char_type>,TempAllocator> cursor(s, options, default_json_parsing(), temp_alloc);
json_decoder<basic_json<char_type,sorted_policy,TempAllocator>,TempAllocator> decoder(result_allocator_arg, temp_alloc, temp_alloc);
std::error_code ec;
T val = decode_traits<T,char_type>::decode(cursor, decoder, ec);
if (ec)
{
JSONCONS_THROW(ser_error(ec, cursor.context().line(), cursor.context().column()));
}
return val;
}
template <class T,class CharT,class TempAllocator>
typename std::enable_if<extension_traits::is_basic_json<T>::value,T>::type
decode_json(temp_allocator_arg_t, const TempAllocator& temp_alloc,
std::basic_istream<CharT>& is,
const basic_json_decode_options<CharT>& options = basic_json_decode_options<CharT>())
{
json_decoder<T,TempAllocator> decoder(temp_alloc);
basic_json_reader<CharT, stream_source<CharT>,TempAllocator> reader(is, decoder, options, temp_alloc);
reader.read();
if (!decoder.is_valid())
{
JSONCONS_THROW(ser_error(conv_errc::conversion_failed, reader.line(), reader.column()));
}
return decoder.get_result();
}
template <class T,class CharT,class TempAllocator>
typename std::enable_if<!extension_traits::is_basic_json<T>::value,T>::type
decode_json(temp_allocator_arg_t, const TempAllocator& temp_alloc,
std::basic_istream<CharT>& is,
const basic_json_decode_options<CharT>& options = basic_json_decode_options<CharT>())
{
basic_json_cursor<CharT,stream_source<CharT>,TempAllocator> cursor(is, options, default_json_parsing(), temp_alloc);
json_decoder<basic_json<CharT,sorted_policy,TempAllocator>,TempAllocator> decoder(result_allocator_arg, temp_alloc,temp_alloc);
std::error_code ec;
T val = decode_traits<T,CharT>::decode(cursor, decoder, ec);
if (ec)
{
JSONCONS_THROW(ser_error(ec, cursor.context().line(), cursor.context().column()));
}
return val;
}
} // jsoncons
#endif

View file

@ -0,0 +1,651 @@
// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_DECODE_TRAITS_HPP
#define JSONCONS_DECODE_TRAITS_HPP
#include <string>
#include <tuple>
#include <array>
#include <memory>
#include <type_traits> // std::enable_if, std::true_type, std::false_type
#include <jsoncons/json_visitor.hpp>
#include <jsoncons/json_decoder.hpp>
#include <jsoncons/json_type_traits.hpp>
#include <jsoncons/staj_cursor.hpp>
#include <jsoncons/conv_error.hpp>
#include <jsoncons/extension_traits.hpp>
namespace jsoncons {
// decode_traits
template <class T, class CharT, class Enable = void>
struct decode_traits
{
template <class Json,class TempAllocator>
static T decode(basic_staj_cursor<CharT>& cursor,
json_decoder<Json,TempAllocator>& decoder,
std::error_code& ec)
{
decoder.reset();
cursor.read_to(decoder, ec);
if (ec)
{
JSONCONS_THROW(ser_error(ec, cursor.context().line(), cursor.context().column()));
}
else if (!decoder.is_valid())
{
JSONCONS_THROW(ser_error(conv_errc::conversion_failed, cursor.context().line(), cursor.context().column()));
}
return decoder.get_result().template as<T>();
}
};
// specializations
// primitive
template <class T, class CharT>
struct decode_traits<T,CharT,
typename std::enable_if<extension_traits::is_primitive<T>::value
>::type>
{
template <class Json,class TempAllocator>
static T decode(basic_staj_cursor<CharT>& cursor,
json_decoder<Json,TempAllocator>&,
std::error_code& ec)
{
T v = cursor.current().template get<T>(ec);
return v;
}
};
// string
template <class T, class CharT>
struct decode_traits<T,CharT,
typename std::enable_if<extension_traits::is_string<T>::value &&
std::is_same<typename T::value_type,CharT>::value
>::type>
{
template <class Json,class TempAllocator>
static T decode(basic_staj_cursor<CharT>& cursor,
json_decoder<Json,TempAllocator>&,
std::error_code& ec)
{
T v = cursor.current().template get<T>(ec);
return v;
}
};
template <class T, class CharT>
struct decode_traits<T,CharT,
typename std::enable_if<extension_traits::is_string<T>::value &&
!std::is_same<typename T::value_type,CharT>::value
>::type>
{
template <class Json,class TempAllocator>
static T decode(basic_staj_cursor<CharT>& cursor,
json_decoder<Json,TempAllocator>&,
std::error_code& ec)
{
auto val = cursor.current().template get<std::basic_string<CharT>>(ec);
T s;
if (!ec)
{
unicode_traits::convert(val.data(), val.size(), s);
}
return s;
}
};
// std::pair
template <class T1, class T2, class CharT>
struct decode_traits<std::pair<T1, T2>, CharT>
{
template <class Json, class TempAllocator>
static std::pair<T1, T2> decode(basic_staj_cursor<CharT>& cursor,
json_decoder<Json, TempAllocator>& decoder,
std::error_code& ec)
{
using value_type = std::pair<T1, T2>;
cursor.array_expected(ec);
if (ec)
{
return value_type{};
}
if (cursor.current().event_type() != staj_event_type::begin_array)
{
ec = conv_errc::not_pair;
return value_type();
}
cursor.next(ec); // skip past array
if (ec)
{
return value_type();
}
T1 v1 = decode_traits<T1,CharT>::decode(cursor, decoder, ec);
if (ec) {return value_type();}
cursor.next(ec);
if (ec) {return value_type();}
T2 v2 = decode_traits<T2, CharT>::decode(cursor, decoder, ec);
if (ec) {return value_type();}
cursor.next(ec);
if (cursor.current().event_type() != staj_event_type::end_array)
{
ec = conv_errc::not_pair;
return value_type();
}
return std::make_pair(v1, v2);
}
};
// vector like
template <class T, class CharT>
struct decode_traits<T,CharT,
typename std::enable_if<!is_json_type_traits_declared<T>::value &&
extension_traits::is_list_like<T>::value &&
extension_traits::is_back_insertable<T>::value &&
!extension_traits::is_typed_array<T>::value
>::type>
{
using value_type = typename T::value_type;
template <class Json,class TempAllocator>
static T decode(basic_staj_cursor<CharT>& cursor,
json_decoder<Json,TempAllocator>& decoder,
std::error_code& ec)
{
T v;
cursor.array_expected(ec);
if (ec)
{
return T{};
}
if (cursor.current().event_type() != staj_event_type::begin_array)
{
ec = conv_errc::not_vector;
return v;
}
cursor.next(ec);
while (cursor.current().event_type() != staj_event_type::end_array && !ec)
{
v.push_back(decode_traits<value_type,CharT>::decode(cursor, decoder, ec));
if (ec) {return T{};}
cursor.next(ec);
}
return v;
}
};
template <class T>
struct typed_array_visitor : public default_json_visitor
{
T& v_;
int level_;
public:
using value_type = typename T::value_type;
typed_array_visitor(T& v)
: default_json_visitor(false,conv_errc::not_vector), v_(v), level_(0)
{
}
private:
bool visit_begin_array(semantic_tag,
const ser_context&,
std::error_code& ec) override
{
if (++level_ != 1)
{
ec = conv_errc::not_vector;
return false;
}
return true;
}
bool visit_begin_array(std::size_t size,
semantic_tag,
const ser_context&,
std::error_code& ec) override
{
if (++level_ != 1)
{
ec = conv_errc::not_vector;
return false;
}
if (size > 0)
{
reserve_storage(typename std::integral_constant<bool, extension_traits::has_reserve<T>::value>::type(), v_, size);
}
return true;
}
bool visit_end_array(const ser_context&,
std::error_code& ec) override
{
if (level_ != 1)
{
ec = conv_errc::not_vector;
return false;
}
return false;
}
bool visit_uint64(uint64_t value,
semantic_tag,
const ser_context&,
std::error_code&) override
{
v_.push_back(static_cast<value_type>(value));
return true;
}
bool visit_int64(int64_t value,
semantic_tag,
const ser_context&,
std::error_code&) override
{
v_.push_back(static_cast<value_type>(value));
return true;
}
bool visit_half(uint16_t value,
semantic_tag,
const ser_context&,
std::error_code&) override
{
return visit_half_(typename std::integral_constant<bool, std::is_integral<value_type>::value>::type(), value);
}
bool visit_half_(std::true_type, uint16_t value)
{
v_.push_back(static_cast<value_type>(value));
return true;
}
bool visit_half_(std::false_type, uint16_t value)
{
v_.push_back(static_cast<value_type>(binary::decode_half(value)));
return true;
}
bool visit_double(double value,
semantic_tag,
const ser_context&,
std::error_code&) override
{
v_.push_back(static_cast<value_type>(value));
return true;
}
bool visit_typed_array(const jsoncons::span<const value_type>& data,
semantic_tag,
const ser_context&,
std::error_code&) override
{
v_ = std::vector<value_type>(data.begin(),data.end());
return false;
}
static
void reserve_storage(std::true_type, T& v, std::size_t new_cap)
{
v.reserve(new_cap);
}
static
void reserve_storage(std::false_type, T&, std::size_t)
{
}
};
template <class T, class CharT>
struct decode_traits<T,CharT,
typename std::enable_if<!is_json_type_traits_declared<T>::value &&
extension_traits::is_list_like<T>::value &&
extension_traits::is_back_insertable_byte_container<T>::value &&
extension_traits::is_typed_array<T>::value
>::type>
{
using value_type = typename T::value_type;
template <class Json,class TempAllocator>
static T decode(basic_staj_cursor<CharT>& cursor,
json_decoder<Json,TempAllocator>&,
std::error_code& ec)
{
cursor.array_expected(ec);
if (ec)
{
return T{};
}
switch (cursor.current().event_type())
{
case staj_event_type::byte_string_value:
{
auto bytes = cursor.current().template get<byte_string_view>(ec);
if (!ec)
{
T v;
if (cursor.current().size() > 0)
{
reserve_storage(typename std::integral_constant<bool, extension_traits::has_reserve<T>::value>::type(), v, cursor.current().size());
}
for (auto ch : bytes)
{
v.push_back(static_cast<value_type>(ch));
}
cursor.next(ec);
return v;
}
else
{
return T{};
}
}
case staj_event_type::begin_array:
{
T v;
if (cursor.current().size() > 0)
{
reserve_storage(typename std::integral_constant<bool, extension_traits::has_reserve<T>::value>::type(), v, cursor.current().size());
}
typed_array_visitor<T> visitor(v);
cursor.read_to(visitor, ec);
return v;
}
default:
{
ec = conv_errc::not_vector;
return T{};
}
}
}
static void reserve_storage(std::true_type, T& v, std::size_t new_cap)
{
v.reserve(new_cap);
}
static void reserve_storage(std::false_type, T&, std::size_t)
{
}
};
template <class T, class CharT>
struct decode_traits<T,CharT,
typename std::enable_if<!is_json_type_traits_declared<T>::value &&
extension_traits::is_list_like<T>::value &&
extension_traits::is_back_insertable<T>::value &&
!extension_traits::is_back_insertable_byte_container<T>::value &&
extension_traits::is_typed_array<T>::value
>::type>
{
using value_type = typename T::value_type;
template <class Json,class TempAllocator>
static T decode(basic_staj_cursor<CharT>& cursor,
json_decoder<Json,TempAllocator>&,
std::error_code& ec)
{
cursor.array_expected(ec);
if (ec)
{
return T{};
}
switch (cursor.current().event_type())
{
case staj_event_type::begin_array:
{
T v;
if (cursor.current().size() > 0)
{
reserve_storage(typename std::integral_constant<bool, extension_traits::has_reserve<T>::value>::type(), v, cursor.current().size());
}
typed_array_visitor<T> visitor(v);
cursor.read_to(visitor, ec);
return v;
}
default:
{
ec = conv_errc::not_vector;
return T{};
}
}
}
static void reserve_storage(std::true_type, T& v, std::size_t new_cap)
{
v.reserve(new_cap);
}
static void reserve_storage(std::false_type, T&, std::size_t)
{
}
};
// set like
template <class T, class CharT>
struct decode_traits<T,CharT,
typename std::enable_if<!is_json_type_traits_declared<T>::value &&
extension_traits::is_list_like<T>::value &&
!extension_traits::is_back_insertable<T>::value &&
extension_traits::is_insertable<T>::value
>::type>
{
using value_type = typename T::value_type;
template <class Json,class TempAllocator>
static T decode(basic_staj_cursor<CharT>& cursor,
json_decoder<Json,TempAllocator>& decoder,
std::error_code& ec)
{
T v;
cursor.array_expected(ec);
if (ec)
{
return T{};
}
if (cursor.current().event_type() != staj_event_type::begin_array)
{
ec = conv_errc::not_vector;
return v;
}
if (cursor.current().size() > 0)
{
reserve_storage(typename std::integral_constant<bool, extension_traits::has_reserve<T>::value>::type(), v, cursor.current().size());
}
cursor.next(ec);
while (cursor.current().event_type() != staj_event_type::end_array && !ec)
{
v.insert(decode_traits<value_type,CharT>::decode(cursor, decoder, ec));
if (ec) {return T{};}
cursor.next(ec);
if (ec) {return T{};}
}
return v;
}
static void reserve_storage(std::true_type, T& v, std::size_t new_cap)
{
v.reserve(new_cap);
}
static void reserve_storage(std::false_type, T&, std::size_t)
{
}
};
// std::array
template <class T, class CharT, std::size_t N>
struct decode_traits<std::array<T,N>,CharT>
{
using value_type = typename std::array<T,N>::value_type;
template <class Json,class TempAllocator>
static std::array<T, N> decode(basic_staj_cursor<CharT>& cursor,
json_decoder<Json,TempAllocator>& decoder,
std::error_code& ec)
{
std::array<T,N> v;
cursor.array_expected(ec);
if (ec)
{
v.fill(T());
return v;
}
v.fill(T{});
if (cursor.current().event_type() != staj_event_type::begin_array)
{
ec = conv_errc::not_vector;
return v;
}
cursor.next(ec);
for (std::size_t i = 0; i < N && cursor.current().event_type() != staj_event_type::end_array && !ec; ++i)
{
v[i] = decode_traits<value_type,CharT>::decode(cursor, decoder, ec);
if (ec) {return v;}
cursor.next(ec);
if (ec) {return v;}
}
return v;
}
};
// map like
template <class T, class CharT>
struct decode_traits<T,CharT,
typename std::enable_if<!is_json_type_traits_declared<T>::value &&
extension_traits::is_map_like<T>::value &&
extension_traits::is_constructible_from_const_pointer_and_size<typename T::key_type>::value
>::type>
{
using mapped_type = typename T::mapped_type;
using value_type = typename T::value_type;
using key_type = typename T::key_type;
template <class Json,class TempAllocator>
static T decode(basic_staj_cursor<CharT>& cursor,
json_decoder<Json,TempAllocator>& decoder,
std::error_code& ec)
{
T val;
if (cursor.current().event_type() != staj_event_type::begin_object)
{
ec = conv_errc::not_map;
return val;
}
if (cursor.current().size() > 0)
{
reserve_storage(typename std::integral_constant<bool, extension_traits::has_reserve<T>::value>::type(), val, cursor.current().size());
}
cursor.next(ec);
while (cursor.current().event_type() != staj_event_type::end_object && !ec)
{
if (cursor.current().event_type() != staj_event_type::key)
{
ec = json_errc::expected_key;
return val;
}
auto key = cursor.current().template get<key_type>(ec);
if (ec) return val;
cursor.next(ec);
if (ec) return val;
val.emplace(std::move(key),decode_traits<mapped_type,CharT>::decode(cursor, decoder, ec));
if (ec) {return val;}
cursor.next(ec);
if (ec) {return val;}
}
return val;
}
static void reserve_storage(std::true_type, T& v, std::size_t new_cap)
{
v.reserve(new_cap);
}
static void reserve_storage(std::false_type, T&, std::size_t)
{
}
};
template <class T, class CharT>
struct decode_traits<T,CharT,
typename std::enable_if<!is_json_type_traits_declared<T>::value &&
extension_traits::is_map_like<T>::value &&
std::is_integral<typename T::key_type>::value
>::type>
{
using mapped_type = typename T::mapped_type;
using value_type = typename T::value_type;
using key_type = typename T::key_type;
template <class Json,class TempAllocator>
static T decode(basic_staj_cursor<CharT>& cursor,
json_decoder<Json,TempAllocator>& decoder,
std::error_code& ec)
{
T val;
if (cursor.current().event_type() != staj_event_type::begin_object)
{
ec = conv_errc::not_map;
return val;
}
if (cursor.current().size() > 0)
{
reserve_storage(typename std::integral_constant<bool, extension_traits::has_reserve<T>::value>::type(), val, cursor.current().size());
}
cursor.next(ec);
while (cursor.current().event_type() != staj_event_type::end_object && !ec)
{
if (cursor.current().event_type() != staj_event_type::key)
{
ec = json_errc::expected_key;
return val;
}
auto s = cursor.current().template get<jsoncons::basic_string_view<typename Json::char_type>>(ec);
if (ec) return val;
key_type n{0};
auto r = jsoncons::detail::to_integer(s.data(), s.size(), n);
if (r.ec != jsoncons::detail::to_integer_errc())
{
ec = json_errc::invalid_number;
return val;
}
cursor.next(ec);
if (ec) return val;
val.emplace(n, decode_traits<mapped_type,CharT>::decode(cursor, decoder, ec));
if (ec) {return val;}
cursor.next(ec);
if (ec) {return val;}
}
return val;
}
static void reserve_storage(std::true_type, T& v, std::size_t new_cap)
{
v.reserve(new_cap);
}
static void reserve_storage(std::false_type, T&, std::size_t)
{
}
};
} // jsoncons
#endif

View file

@ -0,0 +1,44 @@
// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_DETAIL_ENDIAN_HPP
#define JSONCONS_DETAIL_ENDIAN_HPP
#if defined(__sun)
# include <sys/byteorder.h>
#endif
namespace jsoncons {
namespace detail {
enum class endian
{
#if defined(_MSC_VER)
// MSVC, which implies Windows, which implies little-endian
little = 0,
big = 1,
native = little
#elif defined(__ORDER_LITTLE_ENDIAN__) && defined(__ORDER_BIG_ENDIAN__) && defined(__BYTE_ORDER__)
little = __ORDER_LITTLE_ENDIAN__,
big = __ORDER_BIG_ENDIAN__,
native = __BYTE_ORDER__
#elif defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN)
little = 0,
big = 1,
native = big
#elif !defined(_BIG_ENDIAN) && defined(_LITTLE_ENDIAN)
little = 0,
big = 1,
native = little
#else
#error "Unable to determine byte order!"
#endif
};
} // namespace detail
} // namespace jsoncons
#endif

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,379 @@
// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_DETAIL_STRING_WRAPPER_HPP
#define JSONCONS_DETAIL_STRING_WRAPPER_HPP
#include <stdexcept>
#include <string>
#include <exception>
#include <ostream>
#include <cstring> // std::memcpy
#include <memory> // std::allocator
#include <jsoncons/config/compiler_support.hpp>
namespace jsoncons {
namespace detail {
template<std::size_t Len, std::size_t Align>
struct jsoncons_aligned_storage
{
struct type
{
alignas(Align) unsigned char data[Len];
};
};
// From boost 1_71
template <class T, class U>
T launder_cast(U* u)
{
#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606
return std::launder(reinterpret_cast<T>(u));
#elif defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) > 800
return __builtin_launder(reinterpret_cast<T>(u));
#else
return reinterpret_cast<T>(u);
#endif
}
// string_wrapper
template <class CharT,class Allocator>
class string_wrapper
{
public:
using char_type = CharT;
private:
struct str_base_t
{
Allocator alloc_;
Allocator& get_allocator()
{
return alloc_;
}
const Allocator& get_allocator() const
{
return alloc_;
}
str_base_t(const Allocator& alloc)
: alloc_(alloc)
{
}
~str_base_t() noexcept = default;
};
struct str_t : public str_base_t
{
typedef typename std::allocator_traits<Allocator>::template rebind_alloc<CharT> allocator_type;
using allocator_traits_type = std::allocator_traits<allocator_type>;
using pointer = typename allocator_traits_type::pointer;
pointer p_;
std::size_t length_;
~str_t() noexcept = default;
const char_type* c_str() const { return extension_traits::to_plain_pointer(p_); }
const char_type* data() const { return extension_traits::to_plain_pointer(p_); }
std::size_t length() const { return length_; }
str_t(const Allocator& alloc)
: str_base_t(alloc), p_(nullptr), length_(0)
{
}
str_t(const str_t&) = delete;
str_t& operator=(const str_t&) = delete;
};
typedef typename std::allocator_traits<Allocator>::template rebind_alloc<char> byte_allocator_type;
using byte_pointer = typename std::allocator_traits<byte_allocator_type>::pointer;
typedef typename std::allocator_traits<Allocator>::template rebind_alloc<str_t> string_allocator_type;
using string_pointer = typename std::allocator_traits<string_allocator_type>::pointer;
struct storage_t
{
str_t data;
char_type c[1];
};
typedef typename jsoncons_aligned_storage<sizeof(storage_t), alignof(storage_t)>::type json_storage_kind;
string_pointer ptr_;
public:
string_wrapper() = default;
string_wrapper(string_pointer ptr)
: ptr_(ptr)
{
}
string_wrapper(const char_type* data, std::size_t length, const Allocator& a)
{
ptr_ = create(data,length,a);
}
string_wrapper(const string_wrapper& val)
{
ptr_ = create(val.data(),val.length(),val.get_allocator());
}
string_wrapper(const string_wrapper& val, const Allocator& a)
{
ptr_ = create(val.data(),val.length(),a);
}
~string_wrapper() noexcept
{
if (ptr_ != nullptr)
{
destroy(ptr_);
}
}
void swap(string_wrapper& other) noexcept
{
std::swap(ptr_,other.ptr_);
}
const char_type* data() const
{
return ptr_->data();
}
const char_type* c_str() const
{
return ptr_->c_str();
}
std::size_t length() const
{
return ptr_->length();
}
Allocator get_allocator() const
{
return ptr_->get_allocator();
}
private:
static size_t aligned_size(std::size_t n)
{
return sizeof(json_storage_kind) + n;
}
static string_pointer create(const char_type* s, std::size_t length, const Allocator& alloc)
{
std::size_t mem_size = aligned_size(length*sizeof(char_type));
byte_allocator_type byte_alloc(alloc);
byte_pointer ptr = byte_alloc.allocate(mem_size);
char* storage = extension_traits::to_plain_pointer(ptr);
str_t* ps = new(storage)str_t(byte_alloc);
auto psa = launder_cast<storage_t*>(storage);
CharT* p = new(&psa->c)char_type[length + 1];
std::memcpy(p, s, length*sizeof(char_type));
p[length] = 0;
ps->p_ = std::pointer_traits<typename str_t::pointer>::pointer_to(*p);
ps->length_ = length;
return std::pointer_traits<string_pointer>::pointer_to(*ps);
}
static void destroy(string_pointer ptr)
{
str_t* rawp = extension_traits::to_plain_pointer(ptr);
char* p = launder_cast<char*>(rawp);
std::size_t mem_size = aligned_size(ptr->length_*sizeof(char_type));
byte_allocator_type byte_alloc(ptr->get_allocator());
byte_alloc.deallocate(p,mem_size);
}
};
// tagged_string_wrapper
template <class CharT,class Allocator>
class tagged_string_wrapper
{
public:
using char_type = CharT;
private:
struct str_base_t
{
Allocator alloc_;
Allocator& get_allocator()
{
return alloc_;
}
const Allocator& get_allocator() const
{
return alloc_;
}
str_base_t(const Allocator& alloc)
: alloc_(alloc)
{
}
~str_base_t() noexcept = default;
};
struct str_t : public str_base_t
{
typedef typename std::allocator_traits<Allocator>::template rebind_alloc<CharT> allocator_type;
using allocator_traits_type = std::allocator_traits<allocator_type>;
using pointer = typename allocator_traits_type::pointer;
pointer p_;
std::size_t length_;
uint64_t tag_;
~str_t() noexcept = default;
const char_type* c_str() const { return extension_traits::to_plain_pointer(p_); }
const char_type* data() const { return extension_traits::to_plain_pointer(p_); }
std::size_t length() const { return length_; }
uint64_t tag() const { return tag_; }
str_t(uint64_t tag, const Allocator& alloc)
: str_base_t(alloc), p_(nullptr), length_(0), tag_(tag)
{
}
str_t(const str_t&) = delete;
str_t& operator=(const str_t&) = delete;
};
typedef typename std::allocator_traits<Allocator>::template rebind_alloc<char> byte_allocator_type;
using byte_pointer = typename std::allocator_traits<byte_allocator_type>::pointer;
typedef typename std::allocator_traits<Allocator>::template rebind_alloc<str_t> string_allocator_type;
using string_pointer = typename std::allocator_traits<string_allocator_type>::pointer;
struct storage_t
{
str_t data;
char_type c[1];
};
typedef typename jsoncons_aligned_storage<sizeof(storage_t), alignof(storage_t)>::type json_storage_kind;
string_pointer ptr_;
public:
tagged_string_wrapper() = default;
tagged_string_wrapper(string_pointer ptr)
: ptr_(ptr)
{
}
tagged_string_wrapper(const char_type* data, std::size_t length, uint64_t tag, const Allocator& alloc)
{
ptr_ = create(data, length, tag, alloc);
}
tagged_string_wrapper(const tagged_string_wrapper& val)
{
ptr_ = create(val.data(), val.length(), val.tag(), val.get_allocator());
}
tagged_string_wrapper(const tagged_string_wrapper& val, const Allocator& alloc)
{
ptr_ = create(val.data(), val.length(), val.tag(), alloc);
}
~tagged_string_wrapper() noexcept
{
if (ptr_ != nullptr)
{
destroy(ptr_);
}
}
void swap(tagged_string_wrapper& other) noexcept
{
std::swap(ptr_,other.ptr_);
}
const char_type* data() const
{
return ptr_->data();
}
const char_type* c_str() const
{
return ptr_->c_str();
}
std::size_t length() const
{
return ptr_->length();
}
uint64_t tag() const
{
return ptr_->tag();
}
Allocator get_allocator() const
{
return ptr_->get_allocator();
}
private:
static size_t aligned_size(std::size_t n)
{
return sizeof(json_storage_kind) + n;
}
static string_pointer create(const char_type* s, std::size_t length, uint64_t tag, const Allocator& alloc)
{
std::size_t mem_size = aligned_size(length*sizeof(char_type));
byte_allocator_type byte_alloc(alloc);
byte_pointer ptr = byte_alloc.allocate(mem_size);
char* storage = extension_traits::to_plain_pointer(ptr);
str_t* ps = new(storage)str_t(tag, byte_alloc);
auto psa = launder_cast<storage_t*>(storage);
CharT* p = new(&psa->c)char_type[length + 1];
std::memcpy(p, s, length*sizeof(char_type));
p[length] = 0;
ps->p_ = std::pointer_traits<typename str_t::pointer>::pointer_to(*p);
ps->length_ = length;
return std::pointer_traits<string_pointer>::pointer_to(*ps);
}
static void destroy(string_pointer ptr)
{
str_t* rawp = extension_traits::to_plain_pointer(ptr);
char* p = launder_cast<char*>(rawp);
std::size_t mem_size = aligned_size(ptr->length_*sizeof(char_type));
byte_allocator_type byte_alloc(ptr->get_allocator());
byte_alloc.deallocate(p,mem_size);
}
};
} // namespace detail
} // namespace jsoncons
#endif

View file

@ -0,0 +1,483 @@
// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_DETAIL_OPTIONAL_HPP
#define JSONCONS_DETAIL_OPTIONAL_HPP
#include <new> // placement new
#include <memory>
#include <utility> // std::swap
#include <type_traits>
#include <jsoncons/config/compiler_support.hpp>
namespace jsoncons
{
namespace detail
{
template <typename T>
class optional;
template <typename T1, typename T2>
struct is_constructible_or_convertible_from_optional
: std::integral_constant<
bool, std::is_constructible<T1, optional<T2>&>::value ||
std::is_constructible<T1, optional<T2>&&>::value ||
std::is_constructible<T1, const optional<T2>&>::value ||
std::is_constructible<T1, const optional<T2>&&>::value ||
std::is_convertible<optional<T2>&, T1>::value ||
std::is_convertible<optional<T2>&&, T1>::value ||
std::is_convertible<const optional<T2>&, T1>::value ||
std::is_convertible<const optional<T2>&&, T1>::value> {};
template <typename T1, typename T2>
struct is_constructible_convertible_or_assignable_from_optional
: std::integral_constant<
bool, is_constructible_or_convertible_from_optional<T1, T2>::value ||
std::is_assignable<T1&, optional<T2>&>::value ||
std::is_assignable<T1&, optional<T2>&&>::value ||
std::is_assignable<T1&, const optional<T2>&>::value ||
std::is_assignable<T1&, const optional<T2>&&>::value> {};
template <typename T>
class optional
{
public:
using value_type = T;
private:
bool has_value_;
union {
char dummy_;
T value_;
};
public:
constexpr optional() noexcept
: has_value_(false), dummy_{}
{
}
// copy constructors
optional(const optional<T>& other)
: has_value_(false), dummy_{}
{
if (other)
{
construct(*other);
}
}
// converting
template <class U,
typename std::enable_if<!std::is_same<T,U>::value &&
std::is_constructible<T, const U&>::value &&
std::is_convertible<const U&,T>::value &&
!is_constructible_or_convertible_from_optional<T,U>::value &&
std::is_copy_constructible<typename std::decay<U>::type>::value,int>::type = 0>
optional(const optional<U>& other)
: has_value_(false), dummy_{}
{
if (other)
{
construct(*other);
}
}
template <class U,
typename std::enable_if<!std::is_same<T,U>::value &&
std::is_constructible<T, const U&>::value &&
!std::is_convertible<const U&,T>::value &&
!is_constructible_or_convertible_from_optional<T,U>::value &&
std::is_copy_constructible<typename std::decay<U>::type>::value,int>::type = 0>
explicit optional(const optional<U>& other)
: has_value_(false), dummy_{}
{
if (other)
{
construct(*other);
}
}
// move constructors
template <class T2 = T>
optional(optional<T>&& other,
typename std::enable_if<std::is_move_constructible<typename std::decay<T2>::type>::value>::type* = 0)
: has_value_(false), dummy_{}
{
if (other)
{
construct(std::move(other.value_));
}
}
// converting
template <class U>
optional(optional<U>&& value,
typename std::enable_if<!std::is_same<T,U>::value &&
std::is_constructible<T, U&&>::value &&
!is_constructible_or_convertible_from_optional<T,U>::value &&
std::is_convertible<U&&,T>::value,int>::type = 0) // (8)
: has_value_(true), value_(std::forward<U>(value))
{
}
template <class U>
explicit optional(optional<U>&& value,
typename std::enable_if<!std::is_same<T,U>::value &&
std::is_constructible<T, U&&>::value &&
!is_constructible_or_convertible_from_optional<T,U>::value &&
!std::is_convertible<U&&,T>::value,int>::type = 0) // (8)
: has_value_(true), value_(std::forward<U>(value))
{
}
// value constructors
template <class T2>
optional(T2&& value,
typename std::enable_if<!std::is_same<optional<T>,typename std::decay<T2>::type>::value &&
std::is_constructible<T, T2>::value &&
std::is_convertible<T2,T>::value,int>::type = 0) // (8)
: has_value_(true), value_(std::forward<T2>(value))
{
}
template <class T2>
explicit optional(T2&& value,
typename std::enable_if<!std::is_same<optional<T>,typename std::decay<T2>::type>::value &&
std::is_constructible<T, T2>::value &&
!std::is_convertible<T2,T>::value,int>::type = 0) // (8)
: has_value_(true), value_(std::forward<T2>(value))
{
}
~optional() noexcept
{
destroy();
}
optional& operator=(const optional& other)
{
if (other)
{
assign(*other);
}
else
{
reset();
}
return *this;
}
optional& operator=(optional&& other )
{
if (other)
{
assign(std::move(*other));
}
else
{
reset();
}
return *this;
}
template <typename U>
typename std::enable_if<!std::is_same<optional<T>, U>::value &&
std::is_constructible<T, const U&>::value &&
!is_constructible_convertible_or_assignable_from_optional<T,U>::value &&
std::is_assignable<T&, const U&>::value,
optional&>::type
operator=(const optional<U>& other)
{
if (other)
{
assign(*other);
}
else
{
destroy();
}
return *this;
}
template <typename U>
typename std::enable_if<!std::is_same<optional<T>, U>::value &&
std::is_constructible<T, U>::value &&
!is_constructible_convertible_or_assignable_from_optional<T,U>::value &&
std::is_assignable<T&, U>::value,
optional&>::type
operator=(optional<U>&& other)
{
if (other)
{
assign(std::move(*other));
}
else
{
destroy();
}
return *this;
}
// value assignment
template <typename T2>
typename std::enable_if<!std::is_same<optional<T>, typename std::decay<T2>::type>::value &&
std::is_constructible<T, T2>::value &&
std::is_assignable<T&, T2>::value &&
!(std::is_scalar<T>::value && std::is_same<T, typename std::decay<T2>::type>::value),
optional&>::type
operator=(T2&& v)
{
assign(std::forward<T2>(v));
return *this;
}
constexpr explicit operator bool() const noexcept
{
return has_value_;
}
constexpr bool has_value() const noexcept
{
return has_value_;
}
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4702)
#endif // _MSC_VER
T& value() &
{
return static_cast<bool>(*this)
? get()
: JSONCONS_THROW(std::runtime_error("Bad optional access")), get();
}
constexpr const T& value() const &
{
return static_cast<bool>(*this)
? get()
: JSONCONS_THROW(std::runtime_error("Bad optional access")), get();
}
template <typename U>
constexpr T value_or(U&& default_value) const &
{
static_assert(std::is_copy_constructible<T>::value,
"get_value_or: T must be copy constructible");
static_assert(std::is_convertible<U&&, T>::value,
"get_value_or: U must be convertible to T");
return static_cast<bool>(*this)
? **this
: static_cast<T>(std::forward<U>(default_value));
}
template <typename U>
T value_or(U&& default_value) &&
{
static_assert(std::is_move_constructible<T>::value,
"get_value_or: T must be move constructible");
static_assert(std::is_convertible<U&&, T>::value,
"get_value_or: U must be convertible to T");
return static_cast<bool>(*this) ? std::move(**this)
: static_cast<T>(std::forward<U>(default_value));
}
#ifdef _MSC_VER
#pragma warning(pop)
#endif // _MSC_VER
const T* operator->() const
{
return std::addressof(this->value_);
}
T* operator->()
{
return std::addressof(this->value_);
}
constexpr const T& operator*() const&
{
return value();
}
T& operator*() &
{
return value();
}
void reset() noexcept
{
destroy();
}
void swap(optional& other) noexcept(std::is_nothrow_move_constructible<T>::value /*&&
std::is_nothrow_swappable<T>::value*/)
{
const bool contains_a_value = has_value();
if (contains_a_value == other.has_value())
{
if (contains_a_value)
{
using std::swap;
swap(**this, *other);
}
}
else
{
optional& source = contains_a_value ? *this : other;
optional& target = contains_a_value ? other : *this;
target = optional<T>(*source);
source.reset();
}
}
private:
constexpr const T& get() const { return this->value_; }
T& get() { return this->value_; }
template <typename... Args>
void construct(Args&&... args)
{
::new (static_cast<void*>(&this->value_)) T(std::forward<Args>(args)...);
has_value_ = true;
}
void destroy() noexcept
{
if (has_value_)
{
value_.~T();
has_value_ = false;
}
}
template <typename U>
void assign(U&& u)
{
if (has_value_)
{
value_ = std::forward<U>(u);
}
else
{
construct(std::forward<U>(u));
}
}
};
template <typename T>
typename std::enable_if<std::is_nothrow_move_constructible<T>::value,void>::type
swap(optional<T>& lhs, optional<T>& rhs) noexcept
{
lhs.swap(rhs);
}
template <class T1, class T2>
constexpr bool operator==(const optional<T1>& lhs, const optional<T2>& rhs) noexcept
{
return lhs.has_value() == rhs.has_value() && (!lhs.has_value() || *lhs == *rhs);
}
template <class T1, class T2>
constexpr bool operator!=(const optional<T1>& lhs, const optional<T2>& rhs) noexcept
{
return lhs.has_value() != rhs.has_value() || (lhs.has_value() && *lhs != *rhs);
}
template <class T1, class T2>
constexpr bool operator<(const optional<T1>& lhs, const optional<T2>& rhs) noexcept
{
return rhs.has_value() && (!lhs.has_value() || *lhs < *rhs);
}
template <class T1, class T2>
constexpr bool operator>(const optional<T1>& lhs, const optional<T2>& rhs) noexcept
{
return lhs.has_value() && (!rhs.has_value() || *lhs > *rhs);
}
template <class T1, class T2>
constexpr bool operator<=(const optional<T1>& lhs, const optional<T2>& rhs) noexcept
{
return !lhs.has_value() || (rhs.has_value() && *lhs <= *rhs);
}
template <class T1, class T2>
constexpr bool operator>=(const optional<T1>& lhs, const optional<T2>& rhs) noexcept
{
return !rhs.has_value() || (lhs.has_value() && *lhs >= *rhs);
}
template <class T1, class T2>
constexpr bool operator==(const optional<T1>& lhs, const T2& rhs) noexcept
{
return lhs ? *lhs == rhs : false;
}
template <class T1, class T2>
constexpr bool operator==(const T1& lhs, const optional<T2>& rhs) noexcept
{
return rhs ? lhs == *rhs : false;
}
template <class T1, class T2>
constexpr bool operator!=(const optional<T1>& lhs, const T2& rhs) noexcept
{
return lhs ? *lhs != rhs : true;
}
template <class T1, class T2>
constexpr bool operator!=(const T1& lhs, const optional<T2>& rhs) noexcept
{
return rhs ? lhs != *rhs : true;
}
template <class T1, class T2>
constexpr bool operator<(const optional<T1>& lhs, const T2& rhs) noexcept
{
return lhs ? *lhs < rhs : true;
}
template <class T1, class T2>
constexpr bool operator<(const T1& lhs, const optional<T2>& rhs) noexcept
{
return rhs ? lhs < *rhs : false;
}
template <class T1, class T2>
constexpr bool operator<=(const optional<T1>& lhs, const T2& rhs) noexcept
{
return lhs ? *lhs <= rhs : true;
}
template <class T1, class T2>
constexpr bool operator<=(const T1& lhs, const optional<T2>& rhs) noexcept
{
return rhs ? lhs <= *rhs : false;
}
template <class T1, class T2>
constexpr bool operator>(const optional<T1>& lhs, const T2& rhs) noexcept
{
return lhs ? *lhs > rhs : false;
}
template <class T1, class T2>
constexpr bool operator>(const T1& lhs, const optional<T2>& rhs) noexcept
{
return rhs ? lhs > *rhs : true;
}
template <class T1, class T2>
constexpr bool operator>=(const optional<T1>& lhs, const T2& rhs) noexcept
{
return lhs ? *lhs >= rhs : false;
}
template <class T1, class T2>
constexpr bool operator>=(const T1& lhs, const optional<T2>& rhs) noexcept
{
return rhs ? lhs >= *rhs : true;
}
} // namespace detail
} // namespace jsoncons
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,188 @@
#ifndef JSONCONS_DETAIL_SPAN_HPP
#define JSONCONS_DETAIL_SPAN_HPP
#include <utility> // std::swap
#include <memory> // std::addressof
#include <type_traits> // std::enable_if, std::true_type, std::false_type
#include <jsoncons/config/compiler_support.hpp>
#include <jsoncons/extension_traits.hpp>
#include <iterator>
#include <limits>
namespace jsoncons
{
namespace detail
{
constexpr std::size_t dynamic_extent = (std::numeric_limits<std::size_t>::max)();
template< class T, std::size_t Extent = dynamic_extent>
class span;
template<class T>
struct is_span : std::false_type{};
template< class T>
struct is_span<span<T>> : std::true_type{};
template<
class T,
std::size_t Extent
> class span
{
public:
using element_type = T;
using value_type = typename std::remove_volatile<typename std::remove_const<T>::type>::type;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
using pointer = T*;
using const_pointer = const T*;
using reference = T&;
using const_reference = const T&;
using iterator = pointer;
using const_iterator = const_pointer;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
private:
pointer data_;
size_type size_;
public:
static constexpr std::size_t extent = Extent;
constexpr span() noexcept
: data_(nullptr), size_(0)
{
}
constexpr span(pointer data, size_type size)
: data_(data), size_(size)
{
}
template <typename C>
constexpr span(C& c,
typename std::enable_if<!is_span<C>::value && !extension_traits::is_std_array<C>::value && extension_traits::is_compatible_element<C,element_type>::value && extension_traits::has_data_and_size<C>::value>::type* = 0)
: data_(c.data()), size_(c.size())
{
}
template <std::size_t N>
span(element_type (&arr)[N]) noexcept
: data_(std::addressof(arr[0])), size_(N)
{
}
template <std::size_t N>
span(std::array<value_type, N>& arr,
typename std::enable_if<(extent == dynamic_extent || extent == N)>::type* = 0) noexcept
: data_(arr.data()), size_(arr.size())
{
}
template <std::size_t N>
span(const std::array<value_type, N>& arr,
typename std::enable_if<(extent == dynamic_extent || extent == N)>::type* = 0) noexcept
: data_(arr.data()), size_(arr.size())
{
}
template <typename C>
constexpr span(const C& c,
typename std::enable_if<!is_span<C>::value && !extension_traits::is_std_array<C>::value && extension_traits::is_compatible_element<C,element_type>::value && extension_traits::has_data_and_size<C>::value>::type* = 0)
: data_(c.data()), size_(c.size())
{
}
template <class U, std::size_t N>
constexpr span(const span<U, N>& s,
typename std::enable_if<(N == dynamic_extent || N == extent) && std::is_convertible<U(*)[], element_type(*)[]>::value>::type* = 0) noexcept
: data_(s.data()), size_(s.size())
{
}
constexpr span(const span& other) noexcept = default;
span& operator=( const span& other ) noexcept = default;
constexpr pointer data() const noexcept
{
return data_;
}
constexpr size_type size() const noexcept
{
return size_;
}
constexpr bool empty() const noexcept
{
return size_ == 0;
}
constexpr reference operator[](size_type index) const
{
return data_[index];
}
// iterator support
const_iterator begin() const noexcept
{
return data_;
}
const_iterator end() const noexcept
{
return data_ + size_;
}
const_iterator cbegin() const noexcept
{
return data_;
}
const_iterator cend() const noexcept
{
return data_ + size_;
}
const_reverse_iterator rbegin() const noexcept
{
return const_reverse_iterator(end());
}
const_reverse_iterator rend() const noexcept
{
return const_reverse_iterator(begin());
}
const_reverse_iterator crbegin() const noexcept
{
return const_reverse_iterator(end());
}
const_reverse_iterator crend() const noexcept
{
return const_reverse_iterator(begin());
}
span<element_type, dynamic_extent>
first(std::size_t count) const
{
JSONCONS_ASSERT(count <= size());
return span< element_type, dynamic_extent >( data(), count );
}
span<element_type, dynamic_extent>
last(std::size_t count) const
{
JSONCONS_ASSERT(count <= size());
return span<element_type, dynamic_extent>(data() + ( size() - count ), count);
}
span<element_type, dynamic_extent>
subspan(std::size_t offset, std::size_t count = dynamic_extent) const
{
//JSONCONS_ASSERT((offset <= size() && (count == dynamic_extent || (offset + count <= size()))));
return span<element_type, dynamic_extent>(
data() + offset, count == dynamic_extent ? size() - offset : count );
}
};
} // namespace detail
} // namespace jsoncons
#endif

View file

@ -0,0 +1,537 @@
// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_STRING_VIEW_HPP
#define JSONCONS_STRING_VIEW_HPP
#include <stdexcept>
#include <string>
#include <vector>
#include <ostream>
#include <cmath>
#include <algorithm> // std::find, std::min, std::reverse
#include <memory>
#include <iterator>
#include <exception>
#include <stdexcept>
#include <istream> // std::basic_istream
#include <jsoncons/config/compiler_support.hpp>
namespace jsoncons {
namespace detail {
template <class CharT, class Traits = std::char_traits<CharT>>
class basic_string_view
{
private:
const CharT* data_;
std::size_t length_;
public:
using value_type = CharT;
using const_reference = const CharT&;
using traits_type = Traits;
using size_type = std::size_t;
static constexpr size_type npos = size_type(-1);
using const_iterator = const CharT*;
using iterator = const CharT*;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
constexpr basic_string_view() noexcept
: data_(nullptr), length_(0)
{
}
constexpr basic_string_view(const CharT* data, std::size_t length)
: data_(data), length_(length)
{
}
basic_string_view(const CharT* data)
: data_(data), length_(Traits::length(data))
{
}
constexpr basic_string_view(const basic_string_view& other) noexcept = default;
template <class Tr, class Allocator>
JSONCONS_CPP14_CONSTEXPR basic_string_view(const std::basic_string<CharT,Tr,Allocator>& s) noexcept
: data_(s.data()), length_(s.length())
{
}
JSONCONS_CPP14_CONSTEXPR basic_string_view& operator=( const basic_string_view& view ) noexcept
{
data_ = view.data();
length_ = view.length();
return *this;
}
template <class Allocator>
explicit operator std::basic_string<CharT,Traits,Allocator>() const
{
return std::basic_string<CharT,Traits,Allocator>(data_,length_);
}
// iterator support
const_iterator begin() const noexcept
{
return data_;
}
const_iterator end() const noexcept
{
return data_ + length_;
}
const_iterator cbegin() const noexcept
{
return data_;
}
const_iterator cend() const noexcept
{
return data_ + length_;
}
const_reverse_iterator rbegin() const noexcept
{
return const_reverse_iterator(end());
}
const_reverse_iterator rend() const noexcept
{
return const_reverse_iterator(begin());
}
const_reverse_iterator crbegin() const noexcept
{
return const_reverse_iterator(end());
}
const_reverse_iterator crend() const noexcept
{
return const_reverse_iterator(begin());
}
// capacity
std::size_t size() const
{
return length_;
}
std::size_t length() const
{
return length_;
}
size_type max_size() const noexcept
{
return length_;
}
bool empty() const noexcept
{
return length_ == 0;
}
// element access
const_reference operator[](size_type pos) const
{
return data_[pos];
}
const_reference at(std::size_t pos) const
{
if (pos >= length_)
{
JSONCONS_THROW(std::out_of_range("pos exceeds length"));
}
return data_[pos];
}
const_reference front() const
{
return data_[0];
}
const_reference back() const
{
return data_[length_-1];
}
const CharT* data() const
{
return data_;
}
// string operations
basic_string_view substr(size_type pos, size_type n=npos) const
{
if (pos > length_)
{
JSONCONS_THROW(std::out_of_range("pos exceeds size"));
}
if (n == npos || pos + n > length_)
{
n = length_ - pos;
}
return basic_string_view(data_ + pos, n);
}
int compare(const basic_string_view& s) const noexcept
{
const int rc = Traits::compare(data_, s.data_, (std::min)(length_, s.length_));
return rc != 0 ? rc : (length_ == s.length_ ? 0 : length_ < s.length_ ? -1 : 1);
}
int compare(const CharT* data) const noexcept
{
const size_t length = Traits::length(data);
const int rc = Traits::compare(data_, data, (std::min)(length_, length));
return rc != 0 ? rc : (length_ == length? 0 : length_ < length? -1 : 1);
}
template <class Allocator>
int compare(const std::basic_string<CharT,Traits,Allocator>& s) const noexcept
{
const int rc = Traits::compare(data_, s.data(), (std::min)(length_, s.length()));
return rc != 0 ? rc : (length_ == s.length() ? 0 : length_ < s.length() ? -1 : 1);
}
size_type find(basic_string_view s, size_type pos = 0) const noexcept
{
if (pos > length_)
{
return npos;
}
if (s.length_ == 0)
{
return pos;
}
const_iterator it = std::search(cbegin() + pos, cend(),
s.cbegin(), s.cend(), Traits::eq);
return it == cend() ? npos : std::distance(cbegin(), it);
}
size_type find(CharT ch, size_type pos = 0) const noexcept
{
return find(basic_string_view(&ch, 1), pos);
}
size_type find(const CharT* s, size_type pos, size_type n) const noexcept
{
return find(basic_string_view(s, n), pos);
}
size_type find(const CharT* s, size_type pos = 0) const noexcept
{
return find(basic_string_view(s), pos);
}
size_type rfind(basic_string_view s, size_type pos = npos) const noexcept
{
if (length_ < s.length_)
{
return npos;
}
if (pos > length_ - s.length_)
{
pos = length_ - s.length_;
}
if (s.length_ == 0)
{
return pos;
}
for (const CharT* p = data_ + pos; true; --p)
{
if (Traits::compare(p, s.data_, s.length_) == 0)
{
return p - data_;
}
if (p == data_)
{
return npos;
}
};
}
size_type rfind(CharT ch, size_type pos = npos) const noexcept
{
return rfind(basic_string_view(&ch, 1), pos);
}
size_type rfind(const CharT* s, size_type pos, size_type n) const noexcept
{
return rfind(basic_string_view(s, n), pos);
}
size_type rfind(const CharT* s, size_type pos = npos) const noexcept
{
return rfind(basic_string_view(s), pos);
}
size_type find_first_of(basic_string_view s, size_type pos = 0) const noexcept
{
if (pos >= length_ || s.length_ == 0)
{
return npos;
}
const_iterator it = std::find_first_of
(cbegin() + pos, cend(), s.cbegin(), s.cend(), Traits::eq);
return it == cend() ? npos : std::distance (cbegin(), it);
}
size_type find_first_of(CharT ch, size_type pos = 0) const noexcept
{
return find_first_of(basic_string_view(&ch, 1), pos);
}
size_type find_first_of(const CharT* s, size_type pos, size_type n) const noexcept
{
return find_first_of(basic_string_view(s, n), pos);
}
size_type find_first_of(const CharT* s, size_type pos = 0) const noexcept
{
return find_first_of(basic_string_view(s), pos);
}
size_type find_last_of(basic_string_view s, size_type pos = npos) const noexcept
{
if (s.length_ == 0)
{
return npos;
}
if (pos >= length_)
{
pos = 0;
}
else
{
pos = length_ - (pos+1);
}
const_reverse_iterator it = std::find_first_of
(crbegin() + pos, crend(), s.cbegin(), s.cend(), Traits::eq);
return it == crend() ? npos : (length_ - 1 - std::distance(crbegin(), it));
}
size_type find_last_of(CharT ch, size_type pos = npos) const noexcept
{
return find_last_of(basic_string_view(&ch, 1), pos);
}
size_type find_last_of(const CharT* s, size_type pos, size_type n) const noexcept
{
return find_last_of(basic_string_view(s, n), pos);
}
size_type find_last_of(const CharT* s, size_type pos = npos) const noexcept
{
return find_last_of(basic_string_view(s), pos);
}
size_type find_first_not_of(basic_string_view s, size_type pos = 0) const noexcept
{
if (pos >= length_)
return npos;
if (s.length_ == 0)
return pos;
const_iterator it = cend();
for (auto p = cbegin()+pos; p != cend(); ++p)
{
if (Traits::find(s.data_, s.length_, *p) == 0)
{
it = p;
break;
}
}
return it == cend() ? npos : std::distance (cbegin(), it);
}
size_type find_first_not_of(CharT ch, size_type pos = 0) const noexcept
{
return find_first_not_of(basic_string_view(&ch, 1), pos);
}
size_type find_first_not_of(const CharT* s, size_type pos, size_type n) const noexcept
{
return find_first_not_of(basic_string_view(s, n), pos);
}
size_type find_first_not_of(const CharT* s, size_type pos = 0) const noexcept
{
return find_first_not_of(basic_string_view(s), pos);
}
size_type find_last_not_of(basic_string_view s, size_type pos = npos) const noexcept
{
if (pos >= length_)
{
pos = length_ - 1;
}
if (s.length_ == 0)
{
return pos;
}
pos = length_ - (pos+1);
const_iterator it = crend();
for (auto p = crbegin()+pos; p != crend(); ++p)
{
if (Traits::find(s.data_, s.length_, *p) == 0)
{
it = p;
break;
}
}
return it == crend() ? npos : (length_ - 1 - std::distance(crbegin(), it));
}
size_type find_last_not_of(CharT ch, size_type pos = npos) const noexcept
{
return find_last_not_of(basic_string_view(&ch, 1), pos);
}
size_type find_last_not_of(const CharT* s, size_type pos, size_type n) const noexcept
{
return find_last_not_of(basic_string_view(s, n), pos);
}
size_type find_last_not_of(const CharT* s, size_type pos = npos) const noexcept
{
return find_last_not_of(basic_string_view(s), pos);
}
friend std::basic_ostream<CharT>& operator<<(std::basic_ostream<CharT>& os, const basic_string_view& sv)
{
os.write(sv.data_,sv.length_);
return os;
}
};
// ==
template<class CharT,class Traits>
bool operator==(const basic_string_view<CharT,Traits>& lhs,
const basic_string_view<CharT,Traits>& rhs) noexcept
{
return lhs.compare(rhs) == 0;
}
template<class CharT,class Traits,class Allocator>
bool operator==(const basic_string_view<CharT,Traits>& lhs,
const std::basic_string<CharT,Traits,Allocator>& rhs) noexcept
{
return lhs.compare(rhs) == 0;
}
template<class CharT,class Traits,class Allocator>
bool operator==(const std::basic_string<CharT,Traits,Allocator>& lhs,
const basic_string_view<CharT,Traits>& rhs) noexcept
{
return rhs.compare(lhs) == 0;
}
template<class CharT,class Traits>
bool operator==(const basic_string_view<CharT,Traits>& lhs,
const CharT* rhs) noexcept
{
return lhs.compare(rhs) == 0;
}
template<class CharT,class Traits>
bool operator==(const CharT* lhs,
const basic_string_view<CharT,Traits>& rhs) noexcept
{
return rhs.compare(lhs) == 0;
}
// !=
template<class CharT,class Traits>
bool operator!=(const basic_string_view<CharT,Traits>& lhs,
const basic_string_view<CharT,Traits>& rhs) noexcept
{
return lhs.compare(rhs) != 0;
}
template<class CharT,class Traits,class Allocator>
bool operator!=(const basic_string_view<CharT,Traits>& lhs,
const std::basic_string<CharT,Traits,Allocator>& rhs) noexcept
{
return lhs.compare(rhs) != 0;
}
template<class CharT,class Traits,class Allocator>
bool operator!=(const std::basic_string<CharT,Traits,Allocator>& lhs,
const basic_string_view<CharT,Traits>& rhs) noexcept
{
return rhs.compare(lhs) != 0;
}
template<class CharT,class Traits>
bool operator!=(const basic_string_view<CharT,Traits>& lhs,
const CharT* rhs) noexcept
{
return lhs.compare(rhs) != 0;
}
template<class CharT,class Traits>
bool operator!=(const CharT* lhs,
const basic_string_view<CharT,Traits>& rhs) noexcept
{
return rhs.compare(lhs) != 0;
}
// <=
template<class CharT,class Traits>
bool operator<=(const basic_string_view<CharT,Traits>& lhs,
const basic_string_view<CharT,Traits>& rhs) noexcept
{
return lhs.compare(rhs) <= 0;
}
template<class CharT,class Traits,class Allocator>
bool operator<=(const basic_string_view<CharT,Traits>& lhs,
const std::basic_string<CharT,Traits,Allocator>& rhs) noexcept
{
return lhs.compare(rhs) <= 0;
}
template<class CharT,class Traits,class Allocator>
bool operator<=(const std::basic_string<CharT,Traits,Allocator>& lhs,
const basic_string_view<CharT,Traits>& rhs) noexcept
{
return rhs.compare(lhs) >= 0;
}
// <
template<class CharT,class Traits>
bool operator<(const basic_string_view<CharT,Traits>& lhs,
const basic_string_view<CharT,Traits>& rhs) noexcept
{
return lhs.compare(rhs) < 0;
}
template<class CharT,class Traits,class Allocator>
bool operator<(const basic_string_view<CharT,Traits>& lhs,
const std::basic_string<CharT,Traits,Allocator>& rhs) noexcept
{
return lhs.compare(rhs) < 0;
}
template<class CharT,class Traits,class Allocator>
bool operator<(const std::basic_string<CharT,Traits,Allocator>& lhs,
const basic_string_view<CharT,Traits>& rhs) noexcept
{
return rhs.compare(lhs) > 0;
}
// >=
template<class CharT,class Traits>
bool operator>=(const basic_string_view<CharT,Traits>& lhs,
const basic_string_view<CharT,Traits>& rhs) noexcept
{
return lhs.compare(rhs) >= 0;
}
template<class CharT,class Traits,class Allocator>
bool operator>=(const basic_string_view<CharT,Traits>& lhs,
const std::basic_string<CharT,Traits,Allocator>& rhs) noexcept
{
return lhs.compare(rhs) >= 0;
}
template<class CharT,class Traits,class Allocator>
bool operator>=(const std::basic_string<CharT,Traits,Allocator>& lhs,
const basic_string_view<CharT,Traits>& rhs) noexcept
{
return rhs.compare(lhs) <= 0;
}
// >
template<class CharT,class Traits>
bool operator>(const basic_string_view<CharT,Traits>& lhs,
const basic_string_view<CharT,Traits>& rhs) noexcept
{
return lhs.compare(rhs) > 0;
}
template<class CharT,class Traits,class Allocator>
bool operator>(const basic_string_view<CharT,Traits>& lhs,
const std::basic_string<CharT,Traits,Allocator>& rhs) noexcept
{
return lhs.compare(rhs) > 0;
}
template<class CharT,class Traits,class Allocator>
bool operator>(const std::basic_string<CharT,Traits,Allocator>& lhs,
const basic_string_view<CharT,Traits>& rhs) noexcept
{
return rhs.compare(lhs) < 0;
}
} // namespace detail
} // namespace jsoncons
#endif

View file

@ -0,0 +1,566 @@
// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_DETAIL_WRITE_NUMBER_HPP
#define JSONCONS_DETAIL_WRITE_NUMBER_HPP
#include <stdexcept>
#include <string>
#include <cmath>
#include <locale>
#include <limits> // std::numeric_limits
#include <exception>
#include <stdio.h> // snprintf
#include <jsoncons/config/jsoncons_config.hpp>
#include <jsoncons/json_options.hpp>
#include <jsoncons/detail/grisu3.hpp>
#include <jsoncons/detail/parse_number.hpp>
#include <jsoncons/extension_traits.hpp>
namespace jsoncons {
namespace detail {
inline
char to_hex_character(uint8_t c)
{
return (char)((c < 10) ? ('0' + c) : ('A' - 10 + c));
}
// from_integer
template<class Integer,class Result>
typename std::enable_if<extension_traits::is_integer<Integer>::value,std::size_t>::type
from_integer(Integer value, Result& result)
{
using char_type = typename Result::value_type;
char_type buf[255];
char_type *p = buf;
const char_type* last = buf+255;
bool is_negative = value < 0;
if (value < 0)
{
do
{
*p++ = static_cast<char_type>(48 - (value % 10));
}
while ((value /= 10) && (p < last));
}
else
{
do
{
*p++ = static_cast<char_type>(48 + value % 10);
}
while ((value /= 10) && (p < last));
}
JSONCONS_ASSERT(p != last);
std::size_t count = (p - buf);
if (is_negative)
{
result.push_back('-');
++count;
}
while (--p >= buf)
{
result.push_back(*p);
}
return count;
}
// integer_to_string_hex
template<class Integer,class Result>
typename std::enable_if<extension_traits::is_integer<Integer>::value,std::size_t>::type
integer_to_string_hex(Integer value, Result& result)
{
using char_type = typename Result::value_type;
char_type buf[255];
char_type *p = buf;
const char_type* last = buf+255;
bool is_negative = value < 0;
if (value < 0)
{
do
{
*p++ = to_hex_character(0-(value % 16));
}
while ((value /= 16) && (p < last));
}
else
{
do
{
*p++ = to_hex_character(value % 16);
}
while ((value /= 16) && (p < last));
}
JSONCONS_ASSERT(p != last);
std::size_t count = (p - buf);
if (is_negative)
{
result.push_back('-');
++count;
}
while (--p >= buf)
{
result.push_back(*p);
}
return count;
}
// write_double
// fast exponent
template <class Result>
void fill_exponent(int K, Result& result)
{
if (K < 0)
{
result.push_back('-');
K = -K;
}
else
{
result.push_back('+'); // compatibility with sprintf
}
if (K < 10)
{
result.push_back('0'); // compatibility with sprintf
result.push_back((char)('0' + K));
}
else if (K < 100)
{
result.push_back((char)('0' + K / 10)); K %= 10;
result.push_back((char)('0' + K));
}
else if (K < 1000)
{
result.push_back((char)('0' + K / 100)); K %= 100;
result.push_back((char)('0' + K / 10)); K %= 10;
result.push_back((char)('0' + K));
}
else
{
jsoncons::detail::from_integer(K, result);
}
}
template <class Result>
void prettify_string(const char *buffer, std::size_t length, int k, int min_exp, int max_exp, Result& result)
{
int nb_digits = (int)length;
int offset;
/* v = buffer * 10^k
kk is such that 10^(kk-1) <= v < 10^kk
this way kk gives the position of the decimal point.
*/
int kk = nb_digits + k;
if (nb_digits <= kk && kk <= max_exp)
{
/* the first digits are already in. Add some 0s and call it a day. */
/* the max_exp is a personal choice. Only 16 digits could possibly be relevant.
* Basically we want to print 12340000000 rather than 1234.0e7 or 1.234e10 */
for (int i = 0; i < nb_digits; ++i)
{
result.push_back(buffer[i]);
}
for (int i = nb_digits; i < kk; ++i)
{
result.push_back('0');
}
result.push_back('.');
result.push_back('0');
}
else if (0 < kk && kk <= max_exp)
{
/* comma number. Just insert a '.' at the correct location. */
for (int i = 0; i < kk; ++i)
{
result.push_back(buffer[i]);
}
result.push_back('.');
for (int i = kk; i < nb_digits; ++i)
{
result.push_back(buffer[i]);
}
}
else if (min_exp < kk && kk <= 0)
{
offset = 2 - kk;
result.push_back('0');
result.push_back('.');
for (int i = 2; i < offset; ++i)
result.push_back('0');
for (int i = 0; i < nb_digits; ++i)
{
result.push_back(buffer[i]);
}
}
else if (nb_digits == 1)
{
result.push_back(buffer[0]);
result.push_back('e');
fill_exponent(kk - 1, result);
}
else
{
result.push_back(buffer[0]);
result.push_back('.');
for (int i = 1; i < nb_digits; ++i)
{
result.push_back(buffer[i]);
}
result.push_back('e');
fill_exponent(kk - 1, result);
}
}
template<class Result>
void dump_buffer(const char *buffer, std::size_t length, char decimal_point, Result& result)
{
const char *sbeg = buffer;
const char *send = sbeg + length;
if (sbeg != send)
{
bool needs_dot = true;
for (const char* q = sbeg; q < send; ++q)
{
switch (*q)
{
case '-':
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '+':
result.push_back(*q);
break;
case 'e':
case 'E':
result.push_back('e');
needs_dot = false;
break;
default:
if (*q == decimal_point)
{
needs_dot = false;
result.push_back('.');
}
break;
}
}
if (needs_dot)
{
result.push_back('.');
result.push_back('0');
}
}
}
template<class Result>
bool dtoa_scientific(double val, char decimal_point, Result& result)
{
if (val == 0)
{
result.push_back('0');
result.push_back('.');
result.push_back('0');
return true;
}
jsoncons::detail::chars_to to_double_;
char buffer[100];
int precision = std::numeric_limits<double>::digits10;
int length = snprintf(buffer, sizeof(buffer), "%1.*e", precision, val);
if (length < 0)
{
return false;
}
if (to_double_(buffer, sizeof(buffer)) != val)
{
const int precision2 = std::numeric_limits<double>::max_digits10;
length = snprintf(buffer, sizeof(buffer), "%1.*e", precision2, val);
if (length < 0)
{
return false;
}
}
dump_buffer(buffer, static_cast<std::size_t>(length), decimal_point, result);
return true;
}
template<class Result>
bool dtoa_general(double val, char decimal_point, Result& result, std::false_type)
{
if (val == 0)
{
result.push_back('0');
result.push_back('.');
result.push_back('0');
return true;
}
jsoncons::detail::chars_to to_double_;
char buffer[100];
int precision = std::numeric_limits<double>::digits10;
int length = snprintf(buffer, sizeof(buffer), "%1.*g", precision, val);
if (length < 0)
{
return false;
}
if (to_double_(buffer, sizeof(buffer)) != val)
{
const int precision2 = std::numeric_limits<double>::max_digits10;
length = snprintf(buffer, sizeof(buffer), "%1.*g", precision2, val);
if (length < 0)
{
return false;
}
}
dump_buffer(buffer, length, decimal_point, result);
return true;
}
template<class Result>
bool dtoa_general(double v, char decimal_point, Result& result, std::true_type)
{
if (v == 0)
{
result.push_back('0');
result.push_back('.');
result.push_back('0');
return true;
}
int length = 0;
int k;
char buffer[100];
double u = std::signbit(v) ? -v : v;
if (jsoncons::detail::grisu3(u, buffer, &length, &k))
{
if (std::signbit(v))
{
result.push_back('-');
}
// min exp: -4 is consistent with sprintf
// max exp: std::numeric_limits<double>::max_digits10
jsoncons::detail::prettify_string(buffer, length, k, -4, std::numeric_limits<double>::max_digits10, result);
return true;
}
else
{
return dtoa_general(v, decimal_point, result, std::false_type());
}
}
template<class Result>
bool dtoa_fixed(double val, char decimal_point, Result& result, std::false_type)
{
if (val == 0)
{
result.push_back('0');
result.push_back('.');
result.push_back('0');
return true;
}
jsoncons::detail::chars_to to_double_;
char buffer[100];
int precision = std::numeric_limits<double>::digits10;
int length = snprintf(buffer, sizeof(buffer), "%1.*f", precision, val);
if (length < 0)
{
return false;
}
if (to_double_(buffer, sizeof(buffer)) != val)
{
const int precision2 = std::numeric_limits<double>::max_digits10;
length = snprintf(buffer, sizeof(buffer), "%1.*f", precision2, val);
if (length < 0)
{
return false;
}
}
dump_buffer(buffer, length, decimal_point, result);
return true;
}
template<class Result>
bool dtoa_fixed(double v, char decimal_point, Result& result, std::true_type)
{
if (v == 0)
{
result.push_back('0');
result.push_back('.');
result.push_back('0');
return true;
}
int length = 0;
int k;
char buffer[100];
double u = std::signbit(v) ? -v : v;
if (jsoncons::detail::grisu3(u, buffer, &length, &k))
{
if (std::signbit(v))
{
result.push_back('-');
}
jsoncons::detail::prettify_string(buffer, length, k, std::numeric_limits<int>::lowest(), (std::numeric_limits<int>::max)(), result);
return true;
}
else
{
return dtoa_fixed(v, decimal_point, result, std::false_type());
}
}
template<class Result>
bool dtoa_fixed(double v, char decimal_point, Result& result)
{
return dtoa_fixed(v, decimal_point, result, std::integral_constant<bool, std::numeric_limits<double>::is_iec559>());
}
template<class Result>
bool dtoa_general(double v, char decimal_point, Result& result)
{
return dtoa_general(v, decimal_point, result, std::integral_constant<bool, std::numeric_limits<double>::is_iec559>());
}
class write_double
{
private:
chars_to to_double_;
float_chars_format float_format_;
int precision_;
char decimal_point_;
public:
write_double(float_chars_format float_format, int precision)
: float_format_(float_format), precision_(precision), decimal_point_('.')
{
#if !defined(JSONCONS_NO_LOCALECONV)
struct lconv *lc = localeconv();
if (lc != nullptr && lc->decimal_point[0] != 0)
{
decimal_point_ = lc->decimal_point[0];
}
#endif
}
write_double(const write_double&) = default;
write_double& operator=(const write_double&) = default;
template<class Result>
std::size_t operator()(double val, Result& result)
{
std::size_t count = 0;
char number_buffer[200];
int length = 0;
switch (float_format_)
{
case float_chars_format::fixed:
{
if (precision_ > 0)
{
length = snprintf(number_buffer, sizeof(number_buffer), "%1.*f", precision_, val);
if (length < 0)
{
JSONCONS_THROW(json_runtime_error<std::invalid_argument>("write_double failed."));
}
dump_buffer(number_buffer, length, decimal_point_, result);
}
else
{
if (!dtoa_fixed(val, decimal_point_, result))
{
JSONCONS_THROW(json_runtime_error<std::invalid_argument>("write_double failed."));
}
}
}
break;
case float_chars_format::scientific:
{
if (precision_ > 0)
{
length = snprintf(number_buffer, sizeof(number_buffer), "%1.*e", precision_, val);
if (length < 0)
{
JSONCONS_THROW(json_runtime_error<std::invalid_argument>("write_double failed."));
}
dump_buffer(number_buffer, length, decimal_point_, result);
}
else
{
if (!dtoa_scientific(val, decimal_point_, result))
{
JSONCONS_THROW(json_runtime_error<std::invalid_argument>("write_double failed."));
}
}
}
break;
case float_chars_format::general:
{
if (precision_ > 0)
{
length = snprintf(number_buffer, sizeof(number_buffer), "%1.*g", precision_, val);
if (length < 0)
{
JSONCONS_THROW(json_runtime_error<std::invalid_argument>("write_double failed."));
}
dump_buffer(number_buffer, length, decimal_point_, result);
}
else
{
if (!dtoa_general(val, decimal_point_, result))
{
JSONCONS_THROW(json_runtime_error<std::invalid_argument>("write_double failed."));
}
}
break;
}
default:
JSONCONS_THROW(json_runtime_error<std::invalid_argument>("write_double failed."));
break;
}
return count;
}
};
} // namespace detail
} // namespace jsoncons
#endif

View file

@ -0,0 +1,315 @@
// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_ENCODE_JSON_HPP
#define JSONCONS_ENCODE_JSON_HPP
#include <iostream>
#include <string>
#include <tuple>
#include <memory>
#include <istream> // std::basic_istream
#include <jsoncons/encode_traits.hpp>
#include <jsoncons/json_cursor.hpp>
namespace jsoncons {
// to string
template <class T, class Container>
typename std::enable_if<extension_traits::is_basic_json<T>::value &&
extension_traits::is_back_insertable_char_container<Container>::value>::type
encode_json(const T& val,
Container& s,
const basic_json_encode_options<typename Container::value_type>& options =
basic_json_encode_options<typename Container::value_type>())
{
using char_type = typename Container::value_type;
basic_compact_json_encoder<char_type, jsoncons::string_sink<Container>> encoder(s, options);
val.dump(encoder);
}
template <class T, class Container>
typename std::enable_if<!extension_traits::is_basic_json<T>::value &&
extension_traits::is_back_insertable_char_container<Container>::value>::type
encode_json(const T& val,
Container& s,
const basic_json_encode_options<typename Container::value_type>& options = basic_json_encode_options<typename Container::value_type>())
{
using char_type = typename Container::value_type;
basic_compact_json_encoder<char_type, jsoncons::string_sink<Container>> encoder(s, options);
encode_json(val, encoder);
}
// to stream
template <class T, class CharT>
typename std::enable_if<extension_traits::is_basic_json<T>::value>::type
encode_json(const T& val,
std::basic_ostream<CharT>& os,
const basic_json_encode_options<CharT>& options = basic_json_encode_options<CharT>())
{
basic_compact_json_encoder<CharT> encoder(os, options);
val.dump(encoder);
}
template <class T, class CharT>
typename std::enable_if<!extension_traits::is_basic_json<T>::value>::type
encode_json(const T& val,
std::basic_ostream<CharT>& os,
const basic_json_encode_options<CharT>& options = basic_json_encode_options<CharT>())
{
basic_compact_json_encoder<CharT> encoder(os, options);
encode_json(val, encoder);
}
// encode_json_pretty
template <class T, class Container>
typename std::enable_if<extension_traits::is_basic_json<T>::value &&
extension_traits::is_back_insertable_char_container<Container>::value>::type
encode_json_pretty(const T& val,
Container& s,
const basic_json_encode_options<typename Container::value_type>& options = basic_json_encode_options<typename Container::value_type>())
{
using char_type = typename Container::value_type;
basic_json_encoder<char_type,jsoncons::string_sink<Container>> encoder(s, options);
val.dump(encoder);
}
template <class T, class Container>
typename std::enable_if<!extension_traits::is_basic_json<T>::value &&
extension_traits::is_back_insertable_char_container<Container>::value>::type
encode_json_pretty(const T& val,
Container& s,
const basic_json_encode_options<typename Container::value_type>& options = basic_json_encode_options<typename Container::value_type>())
{
using char_type = typename Container::value_type;
basic_json_encoder<char_type,jsoncons::string_sink<Container>> encoder(s, options);
encode_json(val, encoder);
}
template <class T, class CharT>
typename std::enable_if<extension_traits::is_basic_json<T>::value>::type
encode_json_pretty(const T& val,
std::basic_ostream<CharT>& os,
const basic_json_encode_options<CharT>& options = basic_json_encode_options<CharT>())
{
basic_json_encoder<CharT> encoder(os, options);
val.dump(encoder);
}
template <class T, class CharT>
typename std::enable_if<!extension_traits::is_basic_json<T>::value>::type
encode_json_pretty(const T& val,
std::basic_ostream<CharT>& os,
const basic_json_encode_options<CharT>& options = basic_json_encode_options<CharT>())
{
basic_json_encoder<CharT> encoder(os, options);
encode_json(val, encoder);
}
template <class T, class CharT>
void encode_json(const T& val, basic_json_visitor<CharT>& encoder)
{
std::error_code ec;
encode_traits<T,CharT>::encode(val, encoder, basic_json<CharT>(), ec);
if (ec)
{
JSONCONS_THROW(ser_error(ec));
}
encoder.flush();
}
template <class T, class Container, class TempAllocator>
void encode_json(temp_allocator_arg_t, const TempAllocator& temp_alloc,
const T& val,
Container& s,
indenting line_indent = indenting::no_indent)
{
encode_json(temp_allocator_arg, temp_alloc, val, s, basic_json_encode_options<typename Container::value_type>(), line_indent);
}
// legacy
template <class T, class Container>
void encode_json(const T& val, Container& s, indenting line_indent)
{
if (line_indent == indenting::indent)
{
encode_json_pretty(val,s);
}
else
{
encode_json(val,s);
}
}
template <class T, class Container>
void encode_json(const T& val,
Container& s,
const basic_json_encode_options<typename Container::value_type>& options,
indenting line_indent)
{
if (line_indent == indenting::indent)
{
encode_json_pretty(val,s,options);
}
else
{
encode_json(val,s,options);
}
}
template <class T, class CharT>
void encode_json(const T& val,
std::basic_ostream<CharT>& os,
indenting line_indent)
{
if (line_indent == indenting::indent)
{
encode_json_pretty(val, os);
}
else
{
encode_json(val, os);
}
}
template <class T, class CharT>
void encode_json(const T& val,
std::basic_ostream<CharT>& os,
const basic_json_encode_options<CharT>& options,
indenting line_indent)
{
if (line_indent == indenting::indent)
{
encode_json_pretty(val, os, options);
}
else
{
encode_json(val, os, options);
}
}
//end legacy
template <class T, class Container, class TempAllocator>
typename std::enable_if<extension_traits::is_basic_json<T>::value &&
extension_traits::is_back_insertable_char_container<Container>::value>::type
encode_json(temp_allocator_arg_t, const TempAllocator& temp_alloc,
const T& val,
Container& s,
const basic_json_encode_options<typename Container::value_type>& options,
indenting line_indent = indenting::no_indent)
{
using char_type = typename Container::value_type;
if (line_indent == indenting::indent)
{
basic_json_encoder<char_type,jsoncons::string_sink<Container>,TempAllocator> encoder(s, options, temp_alloc);
val.dump(encoder);
}
else
{
basic_compact_json_encoder<char_type, jsoncons::string_sink<Container>,TempAllocator> encoder(s, options, temp_alloc);
val.dump(encoder);
}
}
template <class T, class Container, class TempAllocator>
typename std::enable_if<!extension_traits::is_basic_json<T>::value &&
extension_traits::is_back_insertable_char_container<Container>::value>::type
encode_json(temp_allocator_arg_t, const TempAllocator& temp_alloc,
const T& val,
Container& s,
const basic_json_encode_options<typename Container::value_type>& options,
indenting line_indent)
{
using char_type = typename Container::value_type;
if (line_indent == indenting::indent)
{
basic_json_encoder<char_type,jsoncons::string_sink<Container>,TempAllocator> encoder(s, options, temp_alloc);
encode_json(temp_allocator_arg, temp_alloc, val, encoder);
}
else
{
basic_compact_json_encoder<char_type,jsoncons::string_sink<Container>,TempAllocator> encoder(s, options, temp_alloc);
encode_json(temp_allocator_arg, temp_alloc, val, encoder);
}
}
template <class T, class CharT, class TempAllocator>
void encode_json(temp_allocator_arg_t, const TempAllocator& temp_alloc,
const T& val,
std::basic_ostream<CharT>& os,
indenting line_indent = indenting::no_indent)
{
encode_json(temp_allocator_arg, temp_alloc, val, os, basic_json_encode_options<CharT>(), line_indent);
}
template <class T, class CharT, class TempAllocator>
typename std::enable_if<extension_traits::is_basic_json<T>::value>::type
encode_json(temp_allocator_arg_t, const TempAllocator& temp_alloc,
const T& val,
std::basic_ostream<CharT>& os,
const basic_json_encode_options<CharT>& options,
indenting line_indent = indenting::no_indent)
{
if (line_indent == indenting::indent)
{
basic_json_encoder<CharT,jsoncons::stream_sink<CharT>,TempAllocator> encoder(os, options, temp_alloc);
val.dump(encoder);
}
else
{
basic_compact_json_encoder<CharT,jsoncons::stream_sink<CharT>,TempAllocator> encoder(os, options, temp_alloc);
val.dump(encoder);
}
}
template <class T, class CharT, class TempAllocator>
typename std::enable_if<!extension_traits::is_basic_json<T>::value>::type
encode_json(temp_allocator_arg_t, const TempAllocator& temp_alloc,
const T& val,
std::basic_ostream<CharT>& os,
const basic_json_encode_options<CharT>& options,
indenting line_indent)
{
if (line_indent == indenting::indent)
{
basic_json_encoder<CharT> encoder(os, options);
encode_json(temp_allocator_arg, temp_alloc, val, encoder);
}
else
{
basic_compact_json_encoder<CharT> encoder(os, options);
encode_json(temp_allocator_arg, temp_alloc, val, encoder);
}
}
template <class T, class CharT, class TempAllocator>
typename std::enable_if<!extension_traits::is_basic_json<T>::value>::type
encode_json(temp_allocator_arg_t, const TempAllocator& temp_alloc,
const T& val,
basic_json_visitor<CharT>& encoder)
{
std::error_code ec;
basic_json<CharT,sorted_policy,TempAllocator> proto(temp_alloc);
encode_traits<T,CharT>::encode(val, encoder, proto, ec);
if (ec)
{
JSONCONS_THROW(ser_error(ec));
}
encoder.flush();
}
} // jsoncons
#endif

View file

@ -0,0 +1,378 @@
// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_ENCODE_TRAITS_HPP
#define JSONCONS_ENCODE_TRAITS_HPP
#include <string>
#include <tuple>
#include <array>
#include <memory>
#include <type_traits> // std::enable_if, std::true_type, std::false_type
#include <jsoncons/json_visitor.hpp>
#include <jsoncons/json_decoder.hpp>
#include <jsoncons/json_options.hpp>
#include <jsoncons/json_encoder.hpp>
#include <jsoncons/json_type_traits.hpp>
#include <jsoncons/conv_error.hpp>
namespace jsoncons {
// encode_traits
template <class T, class CharT, class Enable = void>
struct encode_traits
{
template <class Json>
static void encode(const T& val,
basic_json_visitor<CharT>& encoder,
const Json& proto,
std::error_code& ec)
{
encode(std::integral_constant<bool, extension_traits::is_stateless<typename Json::allocator_type>::value>(),
val, encoder, proto, ec);
}
private:
template <class Json>
static void encode(std::true_type,
const T& val,
basic_json_visitor<CharT>& encoder,
const Json& /*proto*/,
std::error_code& ec)
{
auto j = json_type_traits<Json,T>::to_json(val);
j.dump(encoder, ec);
}
template <class Json>
static void encode(std::false_type,
const T& val,
basic_json_visitor<CharT>& encoder,
const Json& proto,
std::error_code& ec)
{
auto j = json_type_traits<Json,T>::to_json(val, proto.get_allocator());
j.dump(encoder, ec);
}
};
// specializations
// bool
template <class T, class CharT>
struct encode_traits<T,CharT,
typename std::enable_if<extension_traits::is_bool<T>::value
>::type>
{
template <class Json>
static void encode(const T& val,
basic_json_visitor<CharT>& encoder,
const Json&,
std::error_code& ec)
{
encoder.bool_value(val,semantic_tag::none,ser_context(),ec);
}
};
// uint
template <class T, class CharT>
struct encode_traits<T,CharT,
typename std::enable_if<extension_traits::is_u8_u16_u32_or_u64<T>::value
>::type>
{
template <class Json>
static void encode(const T& val,
basic_json_visitor<CharT>& encoder,
const Json&,
std::error_code& ec)
{
encoder.uint64_value(val,semantic_tag::none,ser_context(),ec);
}
};
// int
template <class T, class CharT>
struct encode_traits<T,CharT,
typename std::enable_if<extension_traits::is_i8_i16_i32_or_i64<T>::value
>::type>
{
template <class Json>
static void encode(const T& val,
basic_json_visitor<CharT>& encoder,
const Json&,
std::error_code& ec)
{
encoder.int64_value(val,semantic_tag::none,ser_context(),ec);
}
};
// float or double
template <class T, class CharT>
struct encode_traits<T,CharT,
typename std::enable_if<extension_traits::is_float_or_double<T>::value
>::type>
{
template <class Json>
static void encode(const T& val,
basic_json_visitor<CharT>& encoder,
const Json&,
std::error_code& ec)
{
encoder.double_value(val,semantic_tag::none,ser_context(),ec);
}
};
// string
template <class T, class CharT>
struct encode_traits<T,CharT,
typename std::enable_if<extension_traits::is_string<T>::value &&
std::is_same<typename T::value_type,CharT>::value
>::type>
{
template <class Json>
static void encode(const T& val,
basic_json_visitor<CharT>& encoder,
const Json&,
std::error_code& ec)
{
encoder.string_value(val,semantic_tag::none,ser_context(),ec);
}
};
template <class T, class CharT>
struct encode_traits<T,CharT,
typename std::enable_if<extension_traits::is_string<T>::value &&
!std::is_same<typename T::value_type,CharT>::value
>::type>
{
template <class Json>
static void encode(const T& val,
basic_json_visitor<CharT>& encoder,
const Json&,
std::error_code& ec)
{
std::basic_string<CharT> s;
unicode_traits::convert(val.data(), val.size(), s);
encoder.string_value(s,semantic_tag::none,ser_context(),ec);
}
};
// std::pair
template <class T1, class T2, class CharT>
struct encode_traits<std::pair<T1, T2>, CharT>
{
using value_type = std::pair<T1, T2>;
template <class Json>
static void encode(const value_type& val,
basic_json_visitor<CharT>& encoder,
const Json& proto,
std::error_code& ec)
{
encoder.begin_array(2,semantic_tag::none,ser_context(),ec);
if (ec) return;
encode_traits<T1,CharT>::encode(val.first, encoder, proto, ec);
if (ec) return;
encode_traits<T2,CharT>::encode(val.second, encoder, proto, ec);
if (ec) return;
encoder.end_array(ser_context(),ec);
}
};
// std::tuple
namespace detail
{
template<size_t Pos, std::size_t Size, class Json, class Tuple>
struct json_serialize_tuple_helper
{
using char_type = typename Json::char_type;
using element_type = typename std::tuple_element<Size-Pos, Tuple>::type;
using next = json_serialize_tuple_helper<Pos-1, Size, Json, Tuple>;
static void encode(const Tuple& tuple,
basic_json_visitor<char_type>& encoder,
const Json& proto,
std::error_code& ec)
{
encode_traits<element_type,char_type>::encode(std::get<Size-Pos>(tuple), encoder, proto, ec);
if (ec) return;
next::encode(tuple, encoder, proto, ec);
}
};
template<size_t Size, class Json, class Tuple>
struct json_serialize_tuple_helper<0, Size, Json, Tuple>
{
using char_type = typename Json::char_type;
static void encode(const Tuple&,
basic_json_visitor<char_type>&,
const Json&,
std::error_code&)
{
}
};
} // namespace detail
template <class CharT, typename... E>
struct encode_traits<std::tuple<E...>, CharT>
{
using value_type = std::tuple<E...>;
static constexpr std::size_t size = sizeof...(E);
template <class Json>
static void encode(const value_type& val,
basic_json_visitor<CharT>& encoder,
const Json& proto,
std::error_code& ec)
{
using helper = jsoncons::detail::json_serialize_tuple_helper<size, size, Json, std::tuple<E...>>;
encoder.begin_array(size,semantic_tag::none,ser_context(),ec);
if (ec) return;
helper::encode(val, encoder, proto, ec);
if (ec) return;
encoder.end_array(ser_context(),ec);
}
};
// vector like
template <class T, class CharT>
struct encode_traits<T,CharT,
typename std::enable_if<!is_json_type_traits_declared<T>::value &&
extension_traits::is_list_like<T>::value &&
!extension_traits::is_typed_array<T>::value
>::type>
{
using value_type = typename T::value_type;
template <class Json>
static void encode(const T& val,
basic_json_visitor<CharT>& encoder,
const Json& proto,
std::error_code& ec)
{
encoder.begin_array(val.size(),semantic_tag::none,ser_context(),ec);
if (ec) return;
for (auto it = std::begin(val); it != std::end(val); ++it)
{
encode_traits<value_type,CharT>::encode(*it, encoder, proto, ec);
if (ec) return;
}
encoder.end_array(ser_context(), ec);
}
};
template <class T, class CharT>
struct encode_traits<T,CharT,
typename std::enable_if<!is_json_type_traits_declared<T>::value &&
extension_traits::is_list_like<T>::value &&
extension_traits::is_typed_array<T>::value
>::type>
{
using value_type = typename T::value_type;
template <class Json>
static void encode(const T& val,
basic_json_visitor<CharT>& encoder,
const Json&,
std::error_code& ec)
{
encoder.typed_array(jsoncons::span<const value_type>(val), semantic_tag::none, ser_context(), ec);
}
};
// std::array
template <class T, class CharT, std::size_t N>
struct encode_traits<std::array<T,N>,CharT>
{
using value_type = typename std::array<T,N>::value_type;
template <class Json>
static void encode(const std::array<T, N>& val,
basic_json_visitor<CharT>& encoder,
const Json& proto,
std::error_code& ec)
{
encoder.begin_array(val.size(),semantic_tag::none,ser_context(),ec);
if (ec) return;
for (auto it = std::begin(val); it != std::end(val); ++it)
{
encode_traits<value_type,CharT>::encode(*it, encoder, proto, ec);
if (ec) return;
}
encoder.end_array(ser_context(),ec);
}
};
// map like
template <class T, class CharT>
struct encode_traits<T,CharT,
typename std::enable_if<!is_json_type_traits_declared<T>::value &&
extension_traits::is_map_like<T>::value &&
extension_traits::is_constructible_from_const_pointer_and_size<typename T::key_type>::value
>::type>
{
using mapped_type = typename T::mapped_type;
using value_type = typename T::value_type;
using key_type = typename T::key_type;
template <class Json>
static void encode(const T& val,
basic_json_visitor<CharT>& encoder,
const Json& proto,
std::error_code& ec)
{
encoder.begin_object(val.size(), semantic_tag::none, ser_context(), ec);
if (ec) return;
for (auto it = std::begin(val); it != std::end(val); ++it)
{
encoder.key(it->first);
encode_traits<mapped_type,CharT>::encode(it->second, encoder, proto, ec);
if (ec) return;
}
encoder.end_object(ser_context(), ec);
if (ec) return;
}
};
template <class T, class CharT>
struct encode_traits<T,CharT,
typename std::enable_if<!is_json_type_traits_declared<T>::value &&
extension_traits::is_map_like<T>::value &&
std::is_integral<typename T::key_type>::value
>::type>
{
using mapped_type = typename T::mapped_type;
using value_type = typename T::value_type;
using key_type = typename T::key_type;
template <class Json>
static void encode(const T& val,
basic_json_visitor<CharT>& encoder,
const Json& proto,
std::error_code& ec)
{
encoder.begin_object(val.size(), semantic_tag::none, ser_context(), ec);
if (ec) return;
for (auto it = std::begin(val); it != std::end(val); ++it)
{
std::basic_string<typename Json::char_type> s;
jsoncons::detail::from_integer(it->first,s);
encoder.key(s);
encode_traits<mapped_type,CharT>::encode(it->second, encoder, proto, ec);
if (ec) return;
}
encoder.end_object(ser_context(), ec);
if (ec) return;
}
};
} // jsoncons
#endif

View file

@ -0,0 +1,884 @@
// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_TRAITS_EXTENSION_HPP
#define JSONCONS_TRAITS_EXTENSION_HPP
#include <stdexcept>
#include <string>
#include <cmath>
#include <type_traits> // std::enable_if, std::true_type
#include <memory>
#include <iterator> // std::iterator_traits
#include <exception>
#include <array> // std::array
#include <cstddef> // std::byte
#include <utility> // std::declval
#include <climits> // CHAR_BIT
#include <jsoncons/config/compiler_support.hpp>
namespace jsoncons {
namespace extension_traits {
// is_char8
template <typename CharT, typename Enable=void>
struct is_char8 : std::false_type {};
template <typename CharT>
struct is_char8<CharT, typename std::enable_if<std::is_integral<CharT>::value &&
!std::is_same<CharT,bool>::value &&
sizeof(uint8_t) == sizeof(CharT)>::type> : std::true_type {};
// is_char16
template <typename CharT, typename Enable=void>
struct is_char16 : std::false_type {};
template <typename CharT>
struct is_char16<CharT, typename std::enable_if<std::is_integral<CharT>::value &&
!std::is_same<CharT,bool>::value &&
(std::is_same<CharT,char16_t>::value || sizeof(uint16_t) == sizeof(CharT))>::type> : std::true_type {};
// is_char32
template <typename CharT, typename Enable=void>
struct is_char32 : std::false_type {};
template <typename CharT>
struct is_char32<CharT, typename std::enable_if<std::is_integral<CharT>::value &&
!std::is_same<CharT,bool>::value &&
(std::is_same<CharT,char32_t>::value || (!std::is_same<CharT,char16_t>::value && sizeof(uint32_t) == sizeof(CharT)))>::type> : std::true_type {};
// is_int128
template <class T, class Enable=void>
struct is_int128_type : std::false_type {};
#if defined(JSONCONS_HAS_INT128)
template <class T>
struct is_int128_type<T,typename std::enable_if<std::is_same<T,int128_type>::value>::type> : std::true_type {};
#endif
// is_unsigned_integer
template <class T, class Enable=void>
struct is_uint128_type : std::false_type {};
#if defined (JSONCONS_HAS_INT128)
template <class T>
struct is_uint128_type<T,typename std::enable_if<std::is_same<T,uint128_type>::value>::type> : std::true_type {};
#endif
template <class T, class Enable = void>
class integer_limits
{
public:
static constexpr bool is_specialized = false;
};
template <class T>
class integer_limits<T,typename std::enable_if<std::is_integral<T>::value && !std::is_same<T,bool>::value>::type>
{
public:
static constexpr bool is_specialized = true;
static constexpr bool is_signed = std::numeric_limits<T>::is_signed;
static constexpr int digits = std::numeric_limits<T>::digits;
static constexpr std::size_t buffer_size = static_cast<std::size_t>(sizeof(T)*CHAR_BIT*0.302) + 3;
static constexpr T(max)() noexcept
{
return (std::numeric_limits<T>::max)();
}
static constexpr T(min)() noexcept
{
return (std::numeric_limits<T>::min)();
}
static constexpr T lowest() noexcept
{
return std::numeric_limits<T>::lowest();
}
};
template <class T>
class integer_limits<T,typename std::enable_if<!std::is_integral<T>::value && is_int128_type<T>::value>::type>
{
public:
static constexpr bool is_specialized = true;
static constexpr bool is_signed = true;
static constexpr int digits = sizeof(T)*CHAR_BIT - 1;
static constexpr std::size_t buffer_size = (sizeof(T)*CHAR_BIT*0.302) + 3;
static constexpr T(max)() noexcept
{
return (((((T)1 << (digits - 1)) - 1) << 1) + 1);
}
static constexpr T(min)() noexcept
{
return -(max)() - 1;
}
static constexpr T lowest() noexcept
{
return (min)();
}
};
template <class T>
class integer_limits<T,typename std::enable_if<!std::is_integral<T>::value && is_uint128_type<T>::value>::type>
{
public:
static constexpr bool is_specialized = true;
static constexpr bool is_signed = false;
static constexpr int digits = sizeof(T)*CHAR_BIT;
static constexpr T(max)() noexcept
{
return T(T(~0));
}
static constexpr T(min)() noexcept
{
return 0;
}
static constexpr T lowest() noexcept
{
return std::numeric_limits<T>::lowest();
}
};
#ifndef JSONCONS_HAS_VOID_T
// follows https://en.cppreference.com/w/cpp/types/void_t
template<typename... Ts> struct make_void { typedef void type;};
template<typename... Ts> using void_t = typename make_void<Ts...>::type;
#else
using void_t = std::void_t;
#endif
// follows http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4436.pdf
// detector
// primary template handles all types not supporting the archetypal Op
template<
class Default,
class, // always void; supplied externally
template<class...> class Op,
class... Args
>
struct detector
{
constexpr static auto value = false;
using type = Default;
};
// specialization recognizes and handles only types supporting Op
template<
class Default,
template<class...> class Op,
class... Args
>
struct detector<Default, void_t<Op<Args...>>, Op, Args...>
{
constexpr static auto value = true;
using type = Op<Args...>;
};
// is_detected, is_detected_t
template< template<class...> class Op, class... Args >
using
is_detected = detector<void, void, Op, Args...>;
template< template<class...> class Op, class... Args >
using
is_detected_t = typename is_detected<Op, Args...>::type;
// detected_or, detected_or_t
template< class Default, template<class...> class Op, class... Args >
using
detected_or = detector<Default, void, Op, Args...>;
template< class Default, template<class...> class Op, class... Args >
using
detected_or_t = typename detected_or<Default, Op, Args...>::type;
// is_detected_exact
template< class Expected, template<class...> class Op, class... Args >
using
is_detected_exact = std::is_same< Expected, is_detected_t<Op, Args...> >;
// is_detected_convertible
template< class To, template<class...> class Op, class... Args >
using
is_detected_convertible = std::is_convertible< is_detected_t<Op, Args...>, To >;
template <typename T>
struct is_stateless
: public std::integral_constant<bool,
(std::is_default_constructible<T>::value &&
std::is_empty<T>::value)>
{};
// to_plain_pointer
template<class Pointer> inline
typename std::pointer_traits<Pointer>::element_type* to_plain_pointer(Pointer ptr)
{
return (std::addressof(*ptr));
}
template<class T> inline
T * to_plain_pointer(T * ptr)
{
return (ptr);
}
// is_std_byte
template <class T, class Enable=void>
struct is_std_byte : std::false_type {};
#if defined(JSONCONS_HAS_STD_BYTE)
template <class T>
struct is_std_byte<T,
typename std::enable_if<std::is_same<T,std::byte>::value
>::type> : std::true_type {};
#endif
// is_byte
template <class T, class Enable=void>
struct is_byte : std::false_type {};
template <class T>
struct is_byte<T,
typename std::enable_if<std::is_same<T,char>::value ||
std::is_same<T,signed char>::value ||
std::is_same<T,unsigned char>::value ||
is_std_byte<T>::value
>::type> : std::true_type {};
// is_character
template <class T, class Enable=void>
struct is_character : std::false_type {};
template <class T>
struct is_character<T,
typename std::enable_if<std::is_same<T,char>::value ||
std::is_same<T,wchar_t>::value
>::type> : std::true_type {};
// is_narrow_character
template <class T, class Enable=void>
struct is_narrow_character : std::false_type {};
template <class T>
struct is_narrow_character<T,
typename std::enable_if<is_character<T>::value && (sizeof(T) == sizeof(char))
>::type> : std::true_type {};
// is_wide_character
template <class T, class Enable=void>
struct is_wide_character : std::false_type {};
template <class T>
struct is_wide_character<T,
typename std::enable_if<is_character<T>::value && (sizeof(T) != sizeof(char))
>::type> : std::true_type {};
// From boost
namespace ut_detail {
template<typename T>
struct is_cstring_impl : public std::false_type {};
template<typename T>
struct is_cstring_impl<T const*> : public is_cstring_impl<T*> {};
template<typename T>
struct is_cstring_impl<T const* const> : public is_cstring_impl<T*> {};
template<>
struct is_cstring_impl<char*> : public std::true_type {};
template<>
struct is_cstring_impl<wchar_t*> : public std::true_type {};
} // namespace ut_detail
template<typename T>
struct is_cstring : public ut_detail::is_cstring_impl<typename std::decay<T>::type> {};
// is_bool
template <class T, class Enable=void>
struct is_bool : std::false_type {};
template <class T>
struct is_bool<T,
typename std::enable_if<std::is_same<T,bool>::value
>::type> : std::true_type {};
// is_u8_u16_u32_or_u64
template <class T, class Enable=void>
struct is_u8_u16_u32_or_u64 : std::false_type {};
template <class T>
struct is_u8_u16_u32_or_u64<T,
typename std::enable_if<std::is_same<T,uint8_t>::value ||
std::is_same<T,uint16_t>::value ||
std::is_same<T,uint32_t>::value ||
std::is_same<T,uint64_t>::value
>::type> : std::true_type {};
// is_int
template <class T, class Enable=void>
struct is_i8_i16_i32_or_i64 : std::false_type {};
template <class T>
struct is_i8_i16_i32_or_i64<T,
typename std::enable_if<std::is_same<T,int8_t>::value ||
std::is_same<T,int16_t>::value ||
std::is_same<T,int32_t>::value ||
std::is_same<T,int64_t>::value
>::type> : std::true_type {};
// is_float_or_double
template <class T, class Enable=void>
struct is_float_or_double : std::false_type {};
template <class T>
struct is_float_or_double<T,
typename std::enable_if<std::is_same<T,float>::value ||
std::is_same<T,double>::value
>::type> : std::true_type {};
// make_unsigned
template <class T>
struct make_unsigned_impl {using type = typename std::make_unsigned<T>::type;};
#if defined(JSONCONS_HAS_INT128)
template <>
struct make_unsigned_impl<int128_type> {using type = uint128_type;};
template <>
struct make_unsigned_impl<uint128_type> {using type = uint128_type;};
#endif
template <class T>
struct make_unsigned
: make_unsigned_impl<typename std::remove_cv<T>::type>
{};
// is_integer
template <class T, class Enable=void>
struct is_integer : std::false_type {};
template <class T>
struct is_integer<T,typename std::enable_if<integer_limits<T>::is_specialized>::type> : std::true_type {};
// is_signed_integer
template <class T, class Enable=void>
struct is_signed_integer : std::false_type {};
template <class T>
struct is_signed_integer<T, typename std::enable_if<integer_limits<T>::is_specialized &&
integer_limits<T>::is_signed>::type> : std::true_type {};
// is_unsigned_integer
template <class T, class Enable=void>
struct is_unsigned_integer : std::false_type {};
template <class T>
struct is_unsigned_integer<T,
typename std::enable_if<integer_limits<T>::is_specialized &&
!integer_limits<T>::is_signed>::type> : std::true_type {};
// is_primitive
template <class T, class Enable=void>
struct is_primitive : std::false_type {};
template <class T>
struct is_primitive<T,
typename std::enable_if<is_integer<T>::value ||
is_bool<T>::value ||
std::is_floating_point<T>::value
>::type> : std::true_type {};
// Containers
template <class Container>
using
container_npos_t = decltype(Container::npos);
template <class Container>
using
container_allocator_type_t = typename Container::allocator_type;
template <class Container>
using
container_mapped_type_t = typename Container::mapped_type;
template <class Container>
using
container_key_type_t = typename Container::key_type;
template <class Container>
using
container_value_type_t = typename std::iterator_traits<typename Container::iterator>::value_type;
template <class Container>
using
container_char_traits_t = typename Container::traits_type::char_type;
template<class Container>
using
container_push_back_t = decltype(std::declval<Container>().push_back(std::declval<typename Container::value_type>()));
template<class Container>
using
container_push_front_t = decltype(std::declval<Container>().push_front(std::declval<typename Container::value_type>()));
template<class Container>
using
container_insert_t = decltype(std::declval<Container>().insert(std::declval<typename Container::value_type>()));
template<class Container>
using
container_reserve_t = decltype(std::declval<Container>().reserve(typename Container::size_type()));
template<class Container>
using
container_data_t = decltype(std::declval<Container>().data());
template<class Container>
using
container_size_t = decltype(std::declval<Container>().size());
// has_allocator_type
template <class T, class Enable=void>
struct has_allocator_type : std::false_type {};
template <class T>
struct has_allocator_type<T,
typename std::enable_if<is_detected<container_allocator_type_t,T>::value
>::type> : std::true_type {};
// is_string_or_string_view
template <class T, class Enable=void>
struct is_string_or_string_view : std::false_type {};
template <class T>
struct is_string_or_string_view<T,
typename std::enable_if<is_character<typename T::value_type>::value &&
is_detected_exact<typename T::value_type,container_char_traits_t,T>::value &&
is_detected<container_npos_t,T>::value
>::type> : std::true_type {};
// is_string
template <class T, class Enable=void>
struct is_string : std::false_type {};
template <class T>
struct is_string<T,
typename std::enable_if<is_string_or_string_view<T>::value &&
has_allocator_type<T>::value
>::type> : std::true_type {};
// is_string_view
template <class T, class Enable=void>
struct is_string_view : std::false_type {};
template <class T>
struct is_string_view<T,
typename std::enable_if<is_string_or_string_view<T>::value &&
!is_detected<container_allocator_type_t,T>::value
>::type> : std::true_type {};
// is_map_like
template <class T, class Enable=void>
struct is_map_like : std::false_type {};
template <class T>
struct is_map_like<T,
typename std::enable_if<is_detected<container_mapped_type_t,T>::value &&
is_detected<container_allocator_type_t,T>::value &&
is_detected<container_key_type_t,T>::value &&
is_detected<container_value_type_t,T>::value
>::type>
: std::true_type {};
// is_std_array
template<class T>
struct is_std_array : std::false_type {};
template<class E, std::size_t N>
struct is_std_array<std::array<E, N>> : std::true_type {};
// is_list_like
template <class T, class Enable=void>
struct is_list_like : std::false_type {};
template <class T>
struct is_list_like<T,
typename std::enable_if<is_detected<container_value_type_t,T>::value &&
is_detected<container_allocator_type_t,T>::value &&
!is_std_array<T>::value &&
!is_detected_exact<typename T::value_type,container_char_traits_t,T>::value &&
!is_map_like<T>::value
>::type>
: std::true_type {};
// is_constructible_from_const_pointer_and_size
template <class T, class Enable=void>
struct is_constructible_from_const_pointer_and_size : std::false_type {};
template <class T>
struct is_constructible_from_const_pointer_and_size<T,
typename std::enable_if<std::is_constructible<T,typename T::const_pointer,typename T::size_type>::value
>::type>
: std::true_type {};
// has_reserve
template<class Container>
using
has_reserve = is_detected<container_reserve_t, Container>;
// is_back_insertable
template<class Container>
using
is_back_insertable = is_detected<container_push_back_t, Container>;
// is_front_insertable
template<class Container>
using
is_front_insertable = is_detected<container_push_front_t, Container>;
// is_insertable
template<class Container>
using
is_insertable = is_detected<container_insert_t, Container>;
// has_data, has_data_exact
template<class Container>
using
has_data = is_detected<container_data_t, Container>;
template<class Ret, class Container>
using
has_data_exact = is_detected_exact<Ret, container_data_t, Container>;
// has_size
template<class Container>
using
has_size = is_detected<container_size_t, Container>;
// has_data_and_size
template<class Container>
struct has_data_and_size
{
static constexpr bool value = has_data<Container>::value && has_size<Container>::value;
};
// is_byte_sequence
template <class Container, class Enable=void>
struct is_byte_sequence : std::false_type {};
template <class Container>
struct is_byte_sequence<Container,
typename std::enable_if<has_data_exact<const typename Container::value_type*,const Container>::value &&
has_size<Container>::value &&
is_byte<typename Container::value_type>::value
>::type> : std::true_type {};
// is_char_sequence
template <class Container, class Enable=void>
struct is_char_sequence : std::false_type {};
template <class Container>
struct is_char_sequence<Container,
typename std::enable_if<has_data_exact<const typename Container::value_type*,const Container>::value &&
has_size<Container>::value &&
is_character<typename Container::value_type>::value
>::type> : std::true_type {};
// is_sequence_of
template <class Container, class ValueT, class Enable=void>
struct is_sequence_of : std::false_type {};
template <class Container, class ValueT>
struct is_sequence_of<Container,ValueT,
typename std::enable_if<has_data_exact<const typename Container::value_type*,const Container>::value &&
has_size<Container>::value &&
std::is_same<typename Container::value_type,ValueT>::value
>::type> : std::true_type {};
// is_back_insertable_byte_container
template <class Container, class Enable=void>
struct is_back_insertable_byte_container : std::false_type {};
template <class Container>
struct is_back_insertable_byte_container<Container,
typename std::enable_if<is_back_insertable<Container>::value &&
is_byte<typename Container::value_type>::value
>::type> : std::true_type {};
// is_back_insertable_char_container
template <class Container, class Enable=void>
struct is_back_insertable_char_container : std::false_type {};
template <class Container>
struct is_back_insertable_char_container<Container,
typename std::enable_if<is_back_insertable<Container>::value &&
is_character<typename Container::value_type>::value
>::type> : std::true_type {};
// is_back_insertable_container_of
template <class Container, class ValueT, class Enable=void>
struct is_back_insertable_container_of : std::false_type {};
template <class Container, class ValueT>
struct is_back_insertable_container_of<Container, ValueT,
typename std::enable_if<is_back_insertable<Container>::value &&
std::is_same<typename Container::value_type,ValueT>::value
>::type> : std::true_type {};
// is_c_array
template<class T>
struct is_c_array : std::false_type {};
template<class T>
struct is_c_array<T[]> : std::true_type {};
template<class T, std::size_t N>
struct is_c_array<T[N]> : std::true_type {};
namespace impl {
template<class C, class Enable=void>
struct is_typed_array : std::false_type {};
template<class T>
struct is_typed_array
<
T,
typename std::enable_if<is_list_like<T>::value &&
(std::is_same<typename std::decay<typename T::value_type>::type,uint8_t>::value ||
std::is_same<typename std::decay<typename T::value_type>::type,uint16_t>::value ||
std::is_same<typename std::decay<typename T::value_type>::type,uint32_t>::value ||
std::is_same<typename std::decay<typename T::value_type>::type,uint64_t>::value ||
std::is_same<typename std::decay<typename T::value_type>::type,int8_t>::value ||
std::is_same<typename std::decay<typename T::value_type>::type,int16_t>::value ||
std::is_same<typename std::decay<typename T::value_type>::type,int32_t>::value ||
std::is_same<typename std::decay<typename T::value_type>::type,int64_t>::value ||
std::is_same<typename std::decay<typename T::value_type>::type,float_t>::value ||
std::is_same<typename std::decay<typename T::value_type>::type,double_t>::value)>::type
> : std::true_type{};
} // namespace impl
template <typename T>
using is_typed_array = impl::is_typed_array<typename std::decay<T>::type>;
// is_compatible_element
template<class Container, class Element, class Enable=void>
struct is_compatible_element : std::false_type {};
template<class Container, class Element>
struct is_compatible_element
<
Container, Element,
typename std::enable_if<has_data<Container>::value>::type>
: std::is_convertible< typename std::remove_pointer<decltype(std::declval<Container>().data() )>::type(*)[], Element(*)[]>
{};
template<typename T>
using
construct_from_string_t = decltype(T(std::string{}));
template<class T>
using
is_constructible_from_string = is_detected<construct_from_string_t,T>;
template<typename T, typename Data, typename Size>
using
construct_from_data_size_t = decltype(T(static_cast<Data>(nullptr),Size{}));
template<class T, typename Data, typename Size>
using
is_constructible_from_data_size = is_detected<construct_from_data_size_t,T,Data,Size>;
// is_unary_function_object
// is_unary_function_object_exact
template<class FunctionObject, class Arg>
using
unary_function_object_t = decltype(std::declval<FunctionObject>()(std::declval<Arg>()));
template<class FunctionObject, class Arg>
using
is_unary_function_object = is_detected<unary_function_object_t, FunctionObject, Arg>;
template<class FunctionObject, class T, class Arg>
using
is_unary_function_object_exact = is_detected_exact<T,unary_function_object_t, FunctionObject, Arg>;
// is_binary_function_object
// is_binary_function_object_exact
template<class FunctionObject, class Arg1, class Arg2>
using
binary_function_object_t = decltype(std::declval<FunctionObject>()(std::declval<Arg1>(),std::declval<Arg2>()));
template<class FunctionObject, class Arg1, class Arg2>
using
is_binary_function_object = is_detected<binary_function_object_t, FunctionObject, Arg1, Arg2>;
template<class FunctionObject, class T, class Arg1, class Arg2>
using
is_binary_function_object_exact = is_detected_exact<T,binary_function_object_t, FunctionObject, Arg1, Arg2>;
template <class Source, class Enable=void>
struct is_convertible_to_string_view : std::false_type {};
template <class Source>
struct is_convertible_to_string_view<Source,typename std::enable_if<is_string_or_string_view<Source>::value ||
is_cstring<Source>::value
>::type> : std::true_type {};
#if defined(JSONCONS_HAS_2017)
template <typename T>
using is_nothrow_swappable = std::is_nothrow_swappable<T>;
#else
template <typename T>
struct is_nothrow_swappable {
static const bool value = noexcept(swap(std::declval<T&>(), std::declval<T&>()));
};
#endif
#if defined(JSONCONS_HAS_2014)
template <class T>
using alignment_of = std::alignment_of<T>;
template< class T, T... Ints >
using integer_sequence = std::integer_sequence<T,Ints...>;
template <T ... Inds>
using index_sequence = std::index_sequence<Inds...>;
template <class T, T N>
using make_integer_sequence = std::make_integer_sequence<T,N>;
template <std::size_t N>
using make_index_sequence = std::make_index_sequence<N>;
template<class... T>
using index_sequence_for = std::index_sequence_for<T...>;
#else
template <class T>
struct alignment_of
: std::integral_constant<std::size_t, alignof(typename std::remove_all_extents<T>::type)> {};
template <class T, T... Ints>
class integer_sequence
{
public:
using value_type = T;
static_assert(std::is_integral<value_type>::value, "not integral type");
static constexpr std::size_t size() noexcept
{
return sizeof...(Ints);
}
};
template <std::size_t... Inds>
using index_sequence = integer_sequence<std::size_t, Inds...>;
namespace detail_ {
template <class T, T Begin, T End, bool>
struct IntSeqImpl {
using TValue = T;
static_assert(std::is_integral<TValue>::value, "not integral type");
static_assert(Begin >= 0 && Begin < End, "unexpected argument (Begin<0 || Begin<=End)");
template <class, class>
struct IntSeqCombiner;
template <TValue... Inds0, TValue... Inds1>
struct IntSeqCombiner<integer_sequence<TValue, Inds0...>, integer_sequence<TValue, Inds1...>> {
using TResult = integer_sequence<TValue, Inds0..., Inds1...>;
};
using TResult =
typename IntSeqCombiner<typename IntSeqImpl<TValue, Begin, Begin + (End - Begin) / 2,
(End - Begin) / 2 == 1>::TResult,
typename IntSeqImpl<TValue, Begin + (End - Begin) / 2, End,
(End - Begin + 1) / 2 == 1>::TResult>::TResult;
};
template <class T, T Begin>
struct IntSeqImpl<T, Begin, Begin, false> {
using TValue = T;
static_assert(std::is_integral<TValue>::value, "not integral type");
static_assert(Begin >= 0, "unexpected argument (Begin<0)");
using TResult = integer_sequence<TValue>;
};
template <class T, T Begin, T End>
struct IntSeqImpl<T, Begin, End, true> {
using TValue = T;
static_assert(std::is_integral<TValue>::value, "not integral type");
static_assert(Begin >= 0, "unexpected argument (Begin<0)");
using TResult = integer_sequence<TValue, Begin>;
};
} // namespace detail_
template <class T, T N>
using make_integer_sequence = typename detail_::IntSeqImpl<T, 0, N, (N - 0) == 1>::TResult;
template <std::size_t N>
using make_index_sequence = make_integer_sequence<std::size_t, N>;
template <class... T>
using index_sequence_for = make_index_sequence<sizeof...(T)>;
#endif
} // extension_traits
} // jsoncons
#endif

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,18 @@
// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_JSON_HPP
#define JSONCONS_JSON_HPP
#include <jsoncons/basic_json.hpp>
#include <jsoncons/encode_json.hpp>
#include <jsoncons/decode_json.hpp>
#include <jsoncons/json_traits_macros.hpp>
#include <jsoncons/json_traits_macros_deprecated.hpp>
#include <jsoncons/staj_iterator.hpp>
#endif

View file

@ -0,0 +1,324 @@
// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_JSON_ARRAY_HPP
#define JSONCONS_JSON_ARRAY_HPP
#include <string>
#include <vector>
#include <exception>
#include <cstring>
#include <algorithm> // std::sort, std::stable_sort, std::lower_bound, std::unique
#include <utility>
#include <initializer_list>
#include <iterator> // std::iterator_traits
#include <memory> // std::allocator
#include <utility> // std::move
#include <cassert> // assert
#include <type_traits> // std::enable_if
#include <jsoncons/json_exception.hpp>
#include <jsoncons/allocator_holder.hpp>
namespace jsoncons {
// json_array
template <class Json,template<typename,typename> class SequenceContainer = std::vector>
class json_array : public allocator_holder<typename Json::allocator_type>
{
public:
using allocator_type = typename Json::allocator_type;
using value_type = Json;
private:
using value_allocator_type = typename std::allocator_traits<allocator_type>:: template rebind_alloc<value_type>;
using value_container_type = SequenceContainer<value_type,value_allocator_type>;
value_container_type elements_;
public:
using iterator = typename value_container_type::iterator;
using const_iterator = typename value_container_type::const_iterator;
using reference = typename std::iterator_traits<iterator>::reference;
using const_reference = typename std::iterator_traits<const_iterator>::reference;
using allocator_holder<allocator_type>::get_allocator;
json_array()
{
}
explicit json_array(const allocator_type& alloc)
: allocator_holder<allocator_type>(alloc),
elements_(value_allocator_type(alloc))
{
}
explicit json_array(std::size_t n,
const allocator_type& alloc = allocator_type())
: allocator_holder<allocator_type>(alloc),
elements_(n,Json(),value_allocator_type(alloc))
{
}
explicit json_array(std::size_t n,
const Json& value,
const allocator_type& alloc = allocator_type())
: allocator_holder<allocator_type>(alloc),
elements_(n,value,value_allocator_type(alloc))
{
}
template <class InputIterator>
json_array(InputIterator begin, InputIterator end, const allocator_type& alloc = allocator_type())
: allocator_holder<allocator_type>(alloc),
elements_(begin,end,value_allocator_type(alloc))
{
}
json_array(const json_array& val)
: allocator_holder<allocator_type>(val.get_allocator()),
elements_(val.elements_)
{
}
json_array(const json_array& val, const allocator_type& alloc)
: allocator_holder<allocator_type>(alloc),
elements_(val.elements_,value_allocator_type(alloc))
{
}
json_array(json_array&& val) noexcept
: allocator_holder<allocator_type>(val.get_allocator()),
elements_(std::move(val.elements_))
{
}
json_array(json_array&& val, const allocator_type& alloc)
: allocator_holder<allocator_type>(alloc),
elements_(std::move(val.elements_),value_allocator_type(alloc))
{
}
json_array(const std::initializer_list<Json>& init,
const allocator_type& alloc = allocator_type())
: allocator_holder<allocator_type>(alloc),
elements_(init,value_allocator_type(alloc))
{
}
~json_array() noexcept
{
flatten_and_destroy();
}
reference back()
{
return elements_.back();
}
const_reference back() const
{
return elements_.back();
}
void pop_back()
{
elements_.pop_back();
}
bool empty() const
{
return elements_.empty();
}
void swap(json_array& val) noexcept
{
elements_.swap(val.elements_);
}
std::size_t size() const {return elements_.size();}
std::size_t capacity() const {return elements_.capacity();}
void clear() {elements_.clear();}
void shrink_to_fit()
{
for (std::size_t i = 0; i < elements_.size(); ++i)
{
elements_[i].shrink_to_fit();
}
elements_.shrink_to_fit();
}
void reserve(std::size_t n) {elements_.reserve(n);}
void resize(std::size_t n) {elements_.resize(n);}
void resize(std::size_t n, const Json& val) {elements_.resize(n,val);}
#if !defined(JSONCONS_NO_DEPRECATED)
JSONCONS_DEPRECATED_MSG("Instead, use erase(const_iterator, const_iterator)")
void remove_range(std::size_t from_index, std::size_t to_index)
{
JSONCONS_ASSERT(from_index <= to_index);
JSONCONS_ASSERT(to_index <= elements_.size());
elements_.erase(elements_.cbegin()+from_index,elements_.cbegin()+to_index);
}
#endif
iterator erase(const_iterator pos)
{
#if defined(JSONCONS_NO_VECTOR_ERASE_TAKES_CONST_ITERATOR)
iterator it = elements_.begin() + (pos - elements_.begin());
return elements_.erase(it);
#else
return elements_.erase(pos);
#endif
}
iterator erase(const_iterator first, const_iterator last)
{
#if defined(JSONCONS_NO_VECTOR_ERASE_TAKES_CONST_ITERATOR)
iterator it1 = elements_.begin() + (first - elements_.begin());
iterator it2 = elements_.begin() + (last - elements_.begin());
return elements_.erase(it1,it2);
#else
return elements_.erase(first,last);
#endif
}
Json& operator[](std::size_t i) {return elements_[i];}
const Json& operator[](std::size_t i) const {return elements_[i];}
// push_back
template <class T, class A=allocator_type>
typename std::enable_if<extension_traits::is_stateless<A>::value,void>::type
push_back(T&& value)
{
elements_.emplace_back(std::forward<T>(value));
}
template <class T, class A=allocator_type>
typename std::enable_if<!extension_traits::is_stateless<A>::value,void>::type
push_back(T&& value)
{
elements_.emplace_back(std::forward<T>(value),get_allocator());
}
template <class T, class A=allocator_type>
typename std::enable_if<extension_traits::is_stateless<A>::value,iterator>::type
insert(const_iterator pos, T&& value)
{
#if defined(JSONCONS_NO_VECTOR_ERASE_TAKES_CONST_ITERATOR)
iterator it = elements_.begin() + (pos - elements_.begin());
return elements_.emplace(it, std::forward<T>(value));
#else
return elements_.emplace(pos, std::forward<T>(value));
#endif
}
template <class T, class A=allocator_type>
typename std::enable_if<!extension_traits::is_stateless<A>::value,iterator>::type
insert(const_iterator pos, T&& value)
{
#if defined(JSONCONS_NO_VECTOR_ERASE_TAKES_CONST_ITERATOR)
iterator it = elements_.begin() + (pos - elements_.begin());
return elements_.emplace(it, std::forward<T>(value), get_allocator());
#else
return elements_.emplace(pos, std::forward<T>(value), get_allocator());
#endif
}
template <class InputIt>
iterator insert(const_iterator pos, InputIt first, InputIt last)
{
#if defined(JSONCONS_NO_VECTOR_ERASE_TAKES_CONST_ITERATOR)
iterator it = elements_.begin() + (pos - elements_.begin());
elements_.insert(it, first, last);
return first == last ? it : it + 1;
#else
return elements_.insert(pos, first, last);
#endif
}
template <class A=allocator_type, class... Args>
typename std::enable_if<extension_traits::is_stateless<A>::value,iterator>::type
emplace(const_iterator pos, Args&&... args)
{
#if defined(JSONCONS_NO_VECTOR_ERASE_TAKES_CONST_ITERATOR)
iterator it = elements_.begin() + (pos - elements_.begin());
return elements_.emplace(it, std::forward<Args>(args)...);
#else
return elements_.emplace(pos, std::forward<Args>(args)...);
#endif
}
template <class... Args>
Json& emplace_back(Args&&... args)
{
elements_.emplace_back(std::forward<Args>(args)...);
return elements_.back();
}
iterator begin() {return elements_.begin();}
iterator end() {return elements_.end();}
const_iterator begin() const {return elements_.begin();}
const_iterator end() const {return elements_.end();}
bool operator==(const json_array& rhs) const noexcept
{
return elements_ == rhs.elements_;
}
bool operator<(const json_array& rhs) const noexcept
{
return elements_ < rhs.elements_;
}
private:
json_array& operator=(const json_array&) = delete;
void flatten_and_destroy() noexcept
{
while (!elements_.empty())
{
value_type current = std::move(elements_.back());
elements_.pop_back();
switch (current.storage_kind())
{
case json_storage_kind::array_value:
{
for (auto&& item : current.array_range())
{
if (item.size() > 0) // non-empty object or array
{
elements_.push_back(std::move(item));
}
}
current.clear();
break;
}
case json_storage_kind::object_value:
{
for (auto&& kv : current.object_range())
{
if (kv.value().size() > 0) // non-empty object or array
{
elements_.push_back(std::move(kv.value()));
}
}
current.clear();
break;
}
default:
break;
}
}
}
};
} // namespace jsoncons
#endif

View file

@ -0,0 +1,12 @@
// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_JSON_CONTENT_HANDLER_HPP
#define JSONCONS_JSON_CONTENT_HANDLER_HPP
#include <jsoncons/json_visitor.hpp>
#endif

View file

@ -0,0 +1,461 @@
// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_JSON_CURSOR_HPP
#define JSONCONS_JSON_CURSOR_HPP
#include <memory> // std::allocator
#include <string>
#include <vector>
#include <stdexcept>
#include <system_error>
#include <ios>
#include <istream> // std::basic_istream
#include <jsoncons/byte_string.hpp>
#include <jsoncons/config/jsoncons_config.hpp>
#include <jsoncons/json_visitor.hpp>
#include <jsoncons/json_exception.hpp>
#include <jsoncons/json_parser.hpp>
#include <jsoncons/staj_cursor.hpp>
#include <jsoncons/source.hpp>
#include <jsoncons/source_adaptor.hpp>
namespace jsoncons {
template<class CharT,class Source=jsoncons::stream_source<CharT>,class Allocator=std::allocator<char>>
class basic_json_cursor : public basic_staj_cursor<CharT>, private virtual ser_context
{
public:
using source_type = Source;
using char_type = CharT;
using allocator_type = Allocator;
using string_view_type = jsoncons::basic_string_view<CharT>;
private:
typedef typename std::allocator_traits<allocator_type>:: template rebind_alloc<CharT> char_allocator_type;
static constexpr size_t default_max_buffer_size = 16384;
json_source_adaptor<Source> source_;
basic_json_parser<CharT,Allocator> parser_;
basic_staj_visitor<CharT> cursor_visitor_;
bool done_;
// Noncopyable and nonmoveable
basic_json_cursor(const basic_json_cursor&) = delete;
basic_json_cursor& operator=(const basic_json_cursor&) = delete;
public:
// Constructors that throw parse exceptions
template <class Sourceable>
basic_json_cursor(Sourceable&& source,
const basic_json_decode_options<CharT>& options = basic_json_decode_options<CharT>(),
std::function<bool(json_errc,const ser_context&)> err_handler = default_json_parsing(),
const Allocator& alloc = Allocator(),
typename std::enable_if<!std::is_constructible<jsoncons::basic_string_view<CharT>,Sourceable>::value>::type* = 0)
: source_(std::forward<Sourceable>(source)),
parser_(options,err_handler,alloc),
cursor_visitor_(accept_all),
done_(false)
{
if (!done())
{
next();
}
}
template <class Sourceable>
basic_json_cursor(Sourceable&& source,
const basic_json_decode_options<CharT>& options = basic_json_decode_options<CharT>(),
std::function<bool(json_errc,const ser_context&)> err_handler = default_json_parsing(),
const Allocator& alloc = Allocator(),
typename std::enable_if<std::is_constructible<jsoncons::basic_string_view<CharT>,Sourceable>::value>::type* = 0)
: source_(),
parser_(options, err_handler, alloc),
cursor_visitor_(accept_all),
done_(false)
{
initialize_with_string_view(std::forward<Sourceable>(source));
}
// Constructors that set parse error codes
template <class Sourceable>
basic_json_cursor(Sourceable&& source,
std::error_code& ec)
: basic_json_cursor(std::allocator_arg, Allocator(),
std::forward<Sourceable>(source),
basic_json_decode_options<CharT>(),
default_json_parsing(),
ec)
{
}
template <class Sourceable>
basic_json_cursor(Sourceable&& source,
const basic_json_decode_options<CharT>& options,
std::error_code& ec)
: basic_json_cursor(std::allocator_arg, Allocator(),
std::forward<Sourceable>(source),
options,
default_json_parsing(),
ec)
{
}
template <class Sourceable>
basic_json_cursor(Sourceable&& source,
const basic_json_decode_options<CharT>& options,
std::function<bool(json_errc,const ser_context&)> err_handler,
std::error_code& ec)
: basic_json_cursor(std::allocator_arg, Allocator(),
std::forward<Sourceable>(source),
options,
err_handler,
ec)
{
}
template <class Sourceable>
basic_json_cursor(std::allocator_arg_t, const Allocator& alloc,
Sourceable&& source,
const basic_json_decode_options<CharT>& options,
std::function<bool(json_errc,const ser_context&)> err_handler,
std::error_code& ec,
typename std::enable_if<!std::is_constructible<jsoncons::basic_string_view<CharT>,Sourceable>::value>::type* = 0)
: source_(std::forward<Sourceable>(source)),
parser_(options,err_handler,alloc),
cursor_visitor_(accept_all),
done_(false)
{
if (!done())
{
next(ec);
}
}
template <class Sourceable>
basic_json_cursor(std::allocator_arg_t, const Allocator& alloc,
Sourceable&& source,
const basic_json_decode_options<CharT>& options,
std::function<bool(json_errc,const ser_context&)> err_handler,
std::error_code& ec,
typename std::enable_if<std::is_constructible<jsoncons::basic_string_view<CharT>,Sourceable>::value>::type* = 0)
: source_(),
parser_(options, err_handler, alloc),
cursor_visitor_(accept_all),
done_(false)
{
initialize_with_string_view(std::forward<Sourceable>(source), ec);
}
void reset()
{
parser_.reset();
cursor_visitor_.reset();
done_ = false;
if (!done())
{
next();
}
}
template <class Sourceable>
typename std::enable_if<!std::is_constructible<jsoncons::basic_string_view<CharT>,Sourceable>::value>::type
reset(Sourceable&& source)
{
source_ = std::forward<Sourceable>(source);
parser_.reinitialize();
cursor_visitor_.reset();
done_ = false;
if (!done())
{
next();
}
}
template <class Sourceable>
typename std::enable_if<std::is_constructible<jsoncons::basic_string_view<CharT>,Sourceable>::value>::type
reset(Sourceable&& source)
{
source_ = {};
parser_.reinitialize();
cursor_visitor_.reset();
done_ = false;
initialize_with_string_view(std::forward<Sourceable>(source));
}
void reset(std::error_code& ec)
{
parser_.reset();
cursor_visitor_.reset();
done_ = false;
if (!done())
{
next(ec);
}
}
template <class Sourceable>
typename std::enable_if<!std::is_constructible<jsoncons::basic_string_view<CharT>,Sourceable>::value>::type
reset(Sourceable&& source, std::error_code& ec)
{
source_ = std::forward<Sourceable>(source);
parser_.reinitialize();
cursor_visitor_.reset();
done_ = false;
if (!done())
{
next(ec);
}
}
template <class Sourceable>
typename std::enable_if<std::is_constructible<jsoncons::basic_string_view<CharT>,Sourceable>::value>::type
reset(Sourceable&& source, std::error_code& ec)
{
source_ = {};
parser_.reinitialize();
done_ = false;
initialize_with_string_view(std::forward<Sourceable>(source), ec);
}
bool done() const override
{
return parser_.done() || done_;
}
const basic_staj_event<CharT>& current() const override
{
return cursor_visitor_.event();
}
void read_to(basic_json_visitor<CharT>& visitor) override
{
std::error_code ec;
read_to(visitor, ec);
if (ec)
{
JSONCONS_THROW(ser_error(ec,parser_.line(),parser_.column()));
}
}
void read_to(basic_json_visitor<CharT>& visitor,
std::error_code& ec) override
{
if (send_json_event(cursor_visitor_.event(), visitor, *this, ec))
{
read_next(visitor, ec);
}
}
void next() override
{
std::error_code ec;
next(ec);
if (ec)
{
JSONCONS_THROW(ser_error(ec,parser_.line(),parser_.column()));
}
}
void next(std::error_code& ec) override
{
read_next(ec);
}
void check_done()
{
std::error_code ec;
check_done(ec);
if (ec)
{
JSONCONS_THROW(ser_error(ec,parser_.line(),parser_.column()));
}
}
const ser_context& context() const override
{
return *this;
}
void check_done(std::error_code& ec)
{
if (source_.is_error())
{
ec = json_errc::source_error;
return;
}
if (source_.eof())
{
parser_.check_done(ec);
if (ec) return;
}
else
{
do
{
if (parser_.source_exhausted())
{
auto s = source_.read_buffer(ec);
if (ec) return;
if (s.size() > 0)
{
parser_.update(s.data(),s.size());
}
}
if (!parser_.source_exhausted())
{
parser_.check_done(ec);
if (ec) return;
}
}
while (!eof());
}
}
bool eof() const
{
return parser_.source_exhausted() && source_.eof();
}
std::size_t line() const override
{
return parser_.line();
}
std::size_t column() const override
{
return parser_.column();
}
friend
basic_staj_filter_view<CharT> operator|(basic_json_cursor& cursor,
std::function<bool(const basic_staj_event<CharT>&, const ser_context&)> pred)
{
return basic_staj_filter_view<CharT>(cursor, pred);
}
private:
static bool accept_all(const basic_staj_event<CharT>&, const ser_context&)
{
return true;
}
void initialize_with_string_view(string_view_type sv)
{
auto r = unicode_traits::detect_json_encoding(sv.data(), sv.size());
if (!(r.encoding == unicode_traits::encoding_kind::utf8 || r.encoding == unicode_traits::encoding_kind::undetected))
{
JSONCONS_THROW(ser_error(json_errc::illegal_unicode_character,parser_.line(),parser_.column()));
}
std::size_t offset = (r.ptr - sv.data());
parser_.update(sv.data()+offset,sv.size()-offset);
bool is_done = parser_.done() || done_;
if (!is_done)
{
read_next();
}
}
void initialize_with_string_view(string_view_type sv, std::error_code& ec)
{
auto r = unicode_traits::detect_json_encoding(sv.data(), sv.size());
if (!(r.encoding == unicode_traits::encoding_kind::utf8 || r.encoding == unicode_traits::encoding_kind::undetected))
{
ec = json_errc::illegal_unicode_character;
return;
}
std::size_t offset = (r.ptr - sv.data());
parser_.update(sv.data()+offset,sv.size()-offset);
bool is_done = parser_.done() || done_;
if (!is_done)
{
read_next(ec);
}
}
void read_next()
{
std::error_code ec;
read_next(cursor_visitor_, ec);
if (ec)
{
JSONCONS_THROW(ser_error(ec,parser_.line(),parser_.column()));
}
}
void read_next(std::error_code& ec)
{
read_next(cursor_visitor_, ec);
}
void read_next(basic_json_visitor<CharT>& visitor, std::error_code& ec)
{
parser_.restart();
while (!parser_.stopped())
{
if (parser_.source_exhausted())
{
auto s = source_.read_buffer(ec);
if (ec) return;
if (s.size() > 0)
{
parser_.update(s.data(),s.size());
if (ec) return;
}
}
bool eof = parser_.source_exhausted() && source_.eof();
parser_.parse_some(visitor, ec);
if (ec) return;
if (eof)
{
if (parser_.enter())
{
done_ = true;
break;
}
else if (!parser_.accept())
{
ec = json_errc::unexpected_eof;
return;
}
}
}
}
};
using json_stream_cursor = basic_json_cursor<char,jsoncons::stream_source<char>>;
using json_string_cursor = basic_json_cursor<char,jsoncons::string_source<char>>;
using wjson_stream_cursor = basic_json_cursor<wchar_t,jsoncons::stream_source<wchar_t>>;
using wjson_string_cursor = basic_json_cursor<wchar_t,jsoncons::string_source<wchar_t>>;
using json_cursor = basic_json_cursor<char>;
using wjson_cursor = basic_json_cursor<wchar_t>;
#if !defined(JSONCONS_NO_DEPRECATED)
template<class CharT,class Source,class Allocator=std::allocator<CharT>>
using basic_json_pull_reader = basic_json_cursor<CharT,Source,Allocator>;
JSONCONS_DEPRECATED_MSG("Instead, use json_stream_cursor") typedef json_cursor json_pull_reader;
JSONCONS_DEPRECATED_MSG("Instead, use wjson_stream_cursor") typedef wjson_cursor wjson_pull_reader;
template<class CharT,class Source,class Allocator=std::allocator<CharT>>
using basic_json_stream_reader = basic_json_cursor<CharT,Source,Allocator>;
template<class CharT,class Source,class Allocator=std::allocator<CharT>>
using basic_json_staj_cursor = basic_json_cursor<CharT,Source,Allocator>;
JSONCONS_DEPRECATED_MSG("Instead, use json_cursor") typedef json_cursor json_staj_cursor;
JSONCONS_DEPRECATED_MSG("Instead, use wjson_cursor") typedef wjson_cursor wjson_staj_cursor;
#endif
}
#endif

View file

@ -0,0 +1,410 @@
// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_JSON_DECODER_HPP
#define JSONCONS_JSON_DECODER_HPP
#include <string>
#include <vector>
#include <type_traits> // std::true_type
#include <memory> // std::allocator
#include <iterator> // std::make_move_iterator
#include <utility> // std::move
#include <jsoncons/json_exception.hpp>
#include <jsoncons/json_visitor.hpp>
namespace jsoncons {
template <class Json,class TempAllocator=std::allocator<char>>
class json_decoder final : public basic_json_visitor<typename Json::char_type>
{
public:
using char_type = typename Json::char_type;
using typename basic_json_visitor<char_type>::string_view_type;
using key_value_type = typename Json::key_value_type;
using key_type = typename Json::key_type;
using array = typename Json::array;
using object = typename Json::object;
using result_allocator_type = typename Json::allocator_type;
using json_string_allocator = typename key_type::allocator_type;
using json_array_allocator = typename array::allocator_type;
using json_object_allocator = typename object::allocator_type;
typedef typename std::allocator_traits<result_allocator_type>:: template rebind_alloc<uint8_t> json_byte_allocator_type;
private:
enum class structure_type {root_t, array_t, object_t};
struct structure_info
{
structure_type type_;
std::size_t container_index_;
structure_info(structure_type type, std::size_t offset) noexcept
: type_(type), container_index_(offset)
{
}
};
using temp_allocator_type = TempAllocator;
typedef typename std::allocator_traits<temp_allocator_type>:: template rebind_alloc<key_index_value<Json>> stack_item_allocator_type;
typedef typename std::allocator_traits<temp_allocator_type>:: template rebind_alloc<structure_info> structure_info_allocator_type;
result_allocator_type result_allocator_;
temp_allocator_type temp_allocator_;
Json result_;
std::size_t index_;
key_type name_;
std::vector<key_index_value<Json>,stack_item_allocator_type> item_stack_;
std::vector<structure_info,structure_info_allocator_type> structure_stack_;
bool is_valid_;
public:
json_decoder(const temp_allocator_type& temp_alloc = temp_allocator_type())
: result_allocator_(result_allocator_type()),
temp_allocator_(temp_alloc),
result_(),
index_(0),
name_(result_allocator_),
item_stack_(temp_allocator_),
structure_stack_(temp_allocator_),
is_valid_(false)
{
item_stack_.reserve(1000);
structure_stack_.reserve(100);
structure_stack_.emplace_back(structure_type::root_t, 0);
}
json_decoder(result_allocator_arg_t,
const result_allocator_type& result_alloc)
: result_allocator_(result_alloc),
temp_allocator_(),
result_(),
index_(0),
name_(result_allocator_),
item_stack_(),
structure_stack_(),
is_valid_(false)
{
item_stack_.reserve(1000);
structure_stack_.reserve(100);
structure_stack_.emplace_back(structure_type::root_t, 0);
}
json_decoder(result_allocator_arg_t,
const result_allocator_type& result_alloc,
const temp_allocator_type& temp_alloc)
: result_allocator_(result_alloc),
temp_allocator_(temp_alloc),
result_(),
index_(0),
name_(result_allocator_),
item_stack_(temp_allocator_),
structure_stack_(temp_allocator_),
is_valid_(false)
{
item_stack_.reserve(1000);
structure_stack_.reserve(100);
structure_stack_.emplace_back(structure_type::root_t, 0);
}
void reset()
{
is_valid_ = false;
index_ = 0;
item_stack_.clear();
structure_stack_.clear();
structure_stack_.emplace_back(structure_type::root_t, 0);
}
bool is_valid() const
{
return is_valid_;
}
Json get_result()
{
JSONCONS_ASSERT(is_valid_);
is_valid_ = false;
return std::move(result_);
}
#if !defined(JSONCONS_NO_DEPRECATED)
JSONCONS_DEPRECATED_MSG("Instead, use get_result()")
Json& root()
{
return result_;
}
#endif
private:
void visit_flush() override
{
}
bool visit_begin_object(semantic_tag tag, const ser_context&, std::error_code&) override
{
if (structure_stack_.back().type_ == structure_type::root_t)
{
index_ = 0;
item_stack_.clear();
is_valid_ = false;
}
item_stack_.emplace_back(std::forward<key_type>(name_), index_++, json_object_arg, tag, result_allocator_);
structure_stack_.emplace_back(structure_type::object_t, item_stack_.size()-1);
return true;
}
bool visit_end_object(const ser_context&, std::error_code&) override
{
JSONCONS_ASSERT(structure_stack_.size() > 0);
JSONCONS_ASSERT(structure_stack_.back().type_ == structure_type::object_t);
const size_t structure_index = structure_stack_.back().container_index_;
JSONCONS_ASSERT(item_stack_.size() > structure_index);
const size_t count = item_stack_.size() - (structure_index + 1);
auto first = item_stack_.begin() + (structure_index+1);
if (count > 0)
{
item_stack_[structure_index].value.object_value().init(&item_stack_[structure_index+1], count);
}
item_stack_.erase(first, item_stack_.end());
structure_stack_.pop_back();
if (structure_stack_.back().type_ == structure_type::root_t)
{
result_.swap(item_stack_.front().value);
item_stack_.pop_back();
is_valid_ = true;
return false;
}
return true;
}
bool visit_begin_array(semantic_tag tag, const ser_context&, std::error_code&) override
{
if (structure_stack_.back().type_ == structure_type::root_t)
{
index_ = 0;
item_stack_.clear();
is_valid_ = false;
}
item_stack_.emplace_back(std::forward<key_type>(name_), index_++, json_array_arg, tag, result_allocator_);
structure_stack_.emplace_back(structure_type::array_t, item_stack_.size()-1);
return true;
}
bool visit_end_array(const ser_context&, std::error_code&) override
{
JSONCONS_ASSERT(structure_stack_.size() > 1);
JSONCONS_ASSERT(structure_stack_.back().type_ == structure_type::array_t);
const size_t container_index = structure_stack_.back().container_index_;
JSONCONS_ASSERT(item_stack_.size() > container_index);
auto& container = item_stack_[container_index].value;
const size_t size = item_stack_.size() - (container_index + 1);
//std::cout << "size on item stack: " << size << "\n";
if (size > 0)
{
container.reserve(size);
auto first = item_stack_.begin() + (container_index+1);
auto last = first + size;
for (auto it = first; it != last; ++it)
{
container.push_back(std::move(it->value));
}
item_stack_.erase(first, item_stack_.end());
}
structure_stack_.pop_back();
if (structure_stack_.back().type_ == structure_type::root_t)
{
result_.swap(item_stack_.front().value);
item_stack_.pop_back();
is_valid_ = true;
return false;
}
return true;
}
bool visit_key(const string_view_type& name, const ser_context&, std::error_code&) override
{
name_ = key_type(name.data(),name.length(),result_allocator_);
return true;
}
bool visit_string(const string_view_type& sv, semantic_tag tag, const ser_context&, std::error_code&) override
{
switch (structure_stack_.back().type_)
{
case structure_type::object_t:
case structure_type::array_t:
item_stack_.emplace_back(std::forward<key_type>(name_), index_++, sv, tag, result_allocator_);
break;
case structure_type::root_t:
result_ = Json(sv, tag, result_allocator_);
is_valid_ = true;
return false;
}
return true;
}
bool visit_byte_string(const byte_string_view& b,
semantic_tag tag,
const ser_context&,
std::error_code&) override
{
switch (structure_stack_.back().type_)
{
case structure_type::object_t:
case structure_type::array_t:
item_stack_.emplace_back(std::forward<key_type>(name_), index_++, byte_string_arg, b, tag, result_allocator_);
break;
case structure_type::root_t:
result_ = Json(byte_string_arg, b, tag, result_allocator_);
is_valid_ = true;
return false;
}
return true;
}
bool visit_byte_string(const byte_string_view& b,
uint64_t ext_tag,
const ser_context&,
std::error_code&) override
{
switch (structure_stack_.back().type_)
{
case structure_type::object_t:
case structure_type::array_t:
item_stack_.emplace_back(std::forward<key_type>(name_), index_++, byte_string_arg, b, ext_tag, result_allocator_);
break;
case structure_type::root_t:
result_ = Json(byte_string_arg, b, ext_tag, result_allocator_);
is_valid_ = true;
return false;
}
return true;
}
bool visit_int64(int64_t value,
semantic_tag tag,
const ser_context&,
std::error_code&) override
{
switch (structure_stack_.back().type_)
{
case structure_type::object_t:
case structure_type::array_t:
item_stack_.emplace_back(std::forward<key_type>(name_), index_++, value, tag);
break;
case structure_type::root_t:
result_ = Json(value,tag);
is_valid_ = true;
return false;
}
return true;
}
bool visit_uint64(uint64_t value,
semantic_tag tag,
const ser_context&,
std::error_code&) override
{
switch (structure_stack_.back().type_)
{
case structure_type::object_t:
case structure_type::array_t:
item_stack_.emplace_back(std::forward<key_type>(name_), index_++, value, tag);
break;
case structure_type::root_t:
result_ = Json(value,tag);
is_valid_ = true;
return false;
}
return true;
}
bool visit_half(uint16_t value,
semantic_tag tag,
const ser_context&,
std::error_code&) override
{
switch (structure_stack_.back().type_)
{
case structure_type::object_t:
case structure_type::array_t:
item_stack_.emplace_back(std::forward<key_type>(name_), index_++, half_arg, value, tag);
break;
case structure_type::root_t:
result_ = Json(half_arg, value, tag);
is_valid_ = true;
return false;
}
return true;
}
bool visit_double(double value,
semantic_tag tag,
const ser_context&,
std::error_code&) override
{
switch (structure_stack_.back().type_)
{
case structure_type::object_t:
case structure_type::array_t:
item_stack_.emplace_back(std::forward<key_type>(name_), index_++, value, tag);
break;
case structure_type::root_t:
result_ = Json(value, tag);
is_valid_ = true;
return false;
}
return true;
}
bool visit_bool(bool value, semantic_tag tag, const ser_context&, std::error_code&) override
{
switch (structure_stack_.back().type_)
{
case structure_type::object_t:
case structure_type::array_t:
item_stack_.emplace_back(std::forward<key_type>(name_), index_++, value, tag);
break;
case structure_type::root_t:
result_ = Json(value, tag);
is_valid_ = true;
return false;
}
return true;
}
bool visit_null(semantic_tag tag, const ser_context&, std::error_code&) override
{
switch (structure_stack_.back().type_)
{
case structure_type::object_t:
case structure_type::array_t:
item_stack_.emplace_back(std::forward<key_type>(name_), index_++, null_type(), tag);
break;
case structure_type::root_t:
result_ = Json(null_type(), tag);
is_valid_ = true;
return false;
}
return true;
}
};
} // namespace jsoncons
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,156 @@
/// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_JSON_ERROR_HPP
#define JSONCONS_JSON_ERROR_HPP
#include <system_error>
#include <jsoncons/config/jsoncons_config.hpp>
namespace jsoncons {
enum class json_errc
{
success = 0,
unexpected_eof = 1,
source_error,
syntax_error,
extra_character,
max_nesting_depth_exceeded,
single_quote,
illegal_character_in_string,
extra_comma,
expected_key,
expected_value,
invalid_value,
expected_colon,
illegal_control_character,
illegal_escaped_character,
expected_codepoint_surrogate_pair,
invalid_hex_escape_sequence,
invalid_unicode_escape_sequence,
leading_zero,
invalid_number,
expected_comma_or_rbrace,
expected_comma_or_rbracket,
unexpected_rbracket,
unexpected_rbrace,
illegal_comment,
expected_continuation_byte,
over_long_utf8_sequence,
illegal_codepoint,
illegal_surrogate_value,
unpaired_high_surrogate,
illegal_unicode_character
};
class json_error_category_impl
: public std::error_category
{
public:
const char* name() const noexcept override
{
return "jsoncons/json";
}
std::string message(int ev) const override
{
switch (static_cast<json_errc>(ev))
{
case json_errc::unexpected_eof:
return "Unexpected end of file";
case json_errc::source_error:
return "Source error";
case json_errc::syntax_error:
return "JSON syntax_error";
case json_errc::extra_character:
return "Unexpected non-whitespace character after JSON text";
case json_errc::max_nesting_depth_exceeded:
return "Data item nesting exceeds limit in options";
case json_errc::single_quote:
return "JSON strings cannot be quoted with single quotes";
case json_errc::illegal_character_in_string:
return "Illegal character in string";
case json_errc::extra_comma:
return "Extra comma";
case json_errc::expected_key:
return "Expected object member key";
case json_errc::expected_value:
return "Expected value";
case json_errc::invalid_value:
return "Invalid value";
case json_errc::expected_colon:
return "Expected name separator ':'";
case json_errc::illegal_control_character:
return "Illegal control character in string";
case json_errc::illegal_escaped_character:
return "Illegal escaped character in string";
case json_errc::expected_codepoint_surrogate_pair:
return "Invalid codepoint, expected another \\u token to begin the second half of a codepoint surrogate pair.";
case json_errc::invalid_hex_escape_sequence:
return "Invalid codepoint, expected hexadecimal digit.";
case json_errc::invalid_unicode_escape_sequence:
return "Invalid codepoint, expected four hexadecimal digits.";
case json_errc::leading_zero:
return "A number cannot have a leading zero";
case json_errc::invalid_number:
return "Invalid number";
case json_errc::expected_comma_or_rbrace:
return "Expected comma or right brace '}'";
case json_errc::expected_comma_or_rbracket:
return "Expected comma or right bracket ']'";
case json_errc::unexpected_rbrace:
return "Unexpected right brace '}'";
case json_errc::unexpected_rbracket:
return "Unexpected right bracket ']'";
case json_errc::illegal_comment:
return "Illegal comment";
case json_errc::expected_continuation_byte:
return "Expected continuation byte";
case json_errc::over_long_utf8_sequence:
return "Over long UTF-8 sequence";
case json_errc::illegal_codepoint:
return "Illegal codepoint (>= 0xd800 && <= 0xdfff)";
case json_errc::illegal_surrogate_value:
return "UTF-16 surrogate values are illegal in UTF-32";
case json_errc::unpaired_high_surrogate:
return "Expected low surrogate following the high surrogate";
case json_errc::illegal_unicode_character:
return "Illegal unicode character";
default:
return "Unknown JSON parser error";
}
}
};
inline
const std::error_category& json_error_category()
{
static json_error_category_impl instance;
return instance;
}
inline
std::error_code make_error_code(json_errc result)
{
return std::error_code(static_cast<int>(result),json_error_category());
}
#if !defined(JSONCONS_NO_DEPRECATED)
JSONCONS_DEPRECATED_MSG("Instead, use json_errc") typedef json_errc json_parser_errc;
JSONCONS_DEPRECATED_MSG("Instead, use json_errc") typedef json_errc json_parse_errc;
#endif
} // jsoncons
namespace std {
template<>
struct is_error_code_enum<jsoncons::json_errc> : public true_type
{
};
}
#endif

View file

@ -0,0 +1,241 @@
// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSON_EXCEPTION_HPP
#define JSON_EXCEPTION_HPP
#include <string> // std::string
#include <sstream> // std::ostringstream
#include <system_error> // std::error_code
#include <jsoncons/unicode_traits.hpp> // unicode_traits::convert
#include <jsoncons/config/jsoncons_config.hpp>
#include <jsoncons/extension_traits.hpp>
namespace jsoncons {
// json_exception
class json_exception
{
public:
virtual ~json_exception() noexcept = default;
virtual const char* what() const noexcept = 0;
};
// json_runtime_error
template <class Base, class Enable = void>
class json_runtime_error
{
};
template <class Base>
class json_runtime_error<Base,
typename std::enable_if<std::is_convertible<Base*,std::exception*>::value &&
extension_traits::is_constructible_from_string<Base>::value>::type>
: public Base, public virtual json_exception
{
public:
json_runtime_error(const std::string& s) noexcept
: Base(s)
{
}
~json_runtime_error() noexcept
{
}
const char* what() const noexcept override
{
return Base::what();
}
};
class key_not_found : public std::out_of_range, public virtual json_exception
{
std::string name_;
mutable std::string what_;
public:
template <class CharT>
explicit key_not_found(const CharT* key, std::size_t length) noexcept
: std::out_of_range("Key not found")
{
JSONCONS_TRY
{
unicode_traits::convert(key, length, name_,
unicode_traits::conv_flags::strict);
}
JSONCONS_CATCH(...)
{
}
}
virtual ~key_not_found() noexcept
{
}
const char* what() const noexcept override
{
if (what_.empty())
{
JSONCONS_TRY
{
what_.append(std::out_of_range::what());
what_.append(": '");
what_.append(name_);
what_.append("'");
return what_.c_str();
}
JSONCONS_CATCH(...)
{
return std::out_of_range::what();
}
}
else
{
return what_.c_str();
}
}
};
class not_an_object : public std::runtime_error, public virtual json_exception
{
std::string name_;
mutable std::string what_;
public:
template <class CharT>
explicit not_an_object(const CharT* key, std::size_t length) noexcept
: std::runtime_error("Attempting to access a member of a value that is not an object")
{
JSONCONS_TRY
{
unicode_traits::convert(key, length, name_,
unicode_traits::conv_flags::strict);
}
JSONCONS_CATCH(...)
{
}
}
virtual ~not_an_object() noexcept
{
}
const char* what() const noexcept override
{
if (what_.empty())
{
JSONCONS_TRY
{
what_.append(std::runtime_error::what());
what_.append(": '");
what_.append(name_);
what_.append("'");
return what_.c_str();
}
JSONCONS_CATCH(...)
{
return std::runtime_error::what();
}
}
else
{
return what_.c_str();
}
}
};
class ser_error : public std::system_error, public virtual json_exception
{
std::size_t line_number_;
std::size_t column_number_;
mutable std::string what_;
public:
ser_error(std::error_code ec)
: std::system_error(ec), line_number_(0), column_number_(0)
{
}
ser_error(std::error_code ec, const std::string& what_arg)
: std::system_error(ec, what_arg), line_number_(0), column_number_(0)
{
}
ser_error(std::error_code ec, std::size_t position)
: std::system_error(ec), line_number_(0), column_number_(position)
{
}
ser_error(std::error_code ec, std::size_t line, std::size_t column)
: std::system_error(ec), line_number_(line), column_number_(column)
{
}
ser_error(const ser_error& other) = default;
ser_error(ser_error&& other) = default;
const char* what() const noexcept override
{
if (what_.empty())
{
JSONCONS_TRY
{
what_.append(std::system_error::what());
if (line_number_ != 0 && column_number_ != 0)
{
what_.append(" at line ");
what_.append(std::to_string(line_number_));
what_.append(" and column ");
what_.append(std::to_string(column_number_));
}
else if (column_number_ != 0)
{
what_.append(" at position ");
what_.append(std::to_string(column_number_));
}
return what_.c_str();
}
JSONCONS_CATCH(...)
{
return std::system_error::what();
}
}
else
{
return what_.c_str();
}
}
std::size_t line() const noexcept
{
return line_number_;
}
std::size_t column() const noexcept
{
return column_number_;
}
#if !defined(JSONCONS_NO_DEPRECATED)
JSONCONS_DEPRECATED_MSG("Instead, use line()")
std::size_t line_number() const noexcept
{
return line();
}
JSONCONS_DEPRECATED_MSG("Instead, use column()")
std::size_t column_number() const noexcept
{
return column();
}
#endif
};
#if !defined(JSONCONS_NO_DEPRECATED)
JSONCONS_DEPRECATED_MSG("Instead, use ser_error") typedef ser_error serialization_error;
JSONCONS_DEPRECATED_MSG("Instead, use ser_error") typedef ser_error json_parse_exception;
JSONCONS_DEPRECATED_MSG("Instead, use ser_error") typedef ser_error parse_exception;
JSONCONS_DEPRECATED_MSG("Instead, use ser_error") typedef ser_error parse_error;
typedef ser_error codec_error;
#endif
} // namespace jsoncons
#endif

View file

@ -0,0 +1,653 @@
// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_JSON_FILTER_HPP
#define JSONCONS_JSON_FILTER_HPP
#include <string>
#include <jsoncons/json_visitor.hpp>
namespace jsoncons {
template <class CharT>
class basic_json_filter : public basic_json_visitor<CharT>
{
public:
using typename basic_json_visitor<CharT>::char_type;
using typename basic_json_visitor<CharT>::string_view_type;
private:
basic_json_visitor<char_type>* destination_;
// noncopyable
basic_json_filter(const basic_json_filter&) = delete;
basic_json_filter& operator=(const basic_json_filter&) = delete;
public:
basic_json_filter(basic_json_visitor<char_type>& visitor)
: destination_(std::addressof(visitor))
{
}
// moveable
basic_json_filter(basic_json_filter&&) = default;
basic_json_filter& operator=(basic_json_filter&&) = default;
basic_json_visitor<char_type>& destination()
{
return *destination_;
}
#if !defined(JSONCONS_NO_DEPRECATED)
JSONCONS_DEPRECATED_MSG("Instead, use destination()")
basic_json_visitor<char_type>& to_handler()
{
return destination_;
}
JSONCONS_DEPRECATED_MSG("Instead, use destination")
basic_json_visitor<char_type>& input_handler()
{
return destination_;
}
JSONCONS_DEPRECATED_MSG("Instead, use destination")
basic_json_visitor<char_type>& downstream_handler()
{
return destination_;
}
JSONCONS_DEPRECATED_MSG("Instead, use destination")
basic_json_visitor<char_type>& destination_handler()
{
return destination_;
}
#endif
private:
void visit_flush() override
{
destination_->flush();
}
bool visit_begin_object(semantic_tag tag, const ser_context& context, std::error_code& ec) override
{
return destination_->begin_object(tag, context, ec);
}
bool visit_begin_object(std::size_t length, semantic_tag tag, const ser_context& context, std::error_code& ec) override
{
return destination_->begin_object(length, tag, context, ec);
}
bool visit_end_object(const ser_context& context, std::error_code& ec) override
{
return destination_->end_object(context, ec);
}
bool visit_begin_array(semantic_tag tag, const ser_context& context, std::error_code& ec) override
{
return destination_->begin_array(tag, context, ec);
}
bool visit_begin_array(std::size_t length, semantic_tag tag, const ser_context& context, std::error_code& ec) override
{
return destination_->begin_array(length, tag, context, ec);
}
bool visit_end_array(const ser_context& context, std::error_code& ec) override
{
return destination_->end_array(context, ec);
}
bool visit_key(const string_view_type& name,
const ser_context& context,
std::error_code& ec) override
{
return destination_->key(name, context, ec);
}
bool visit_string(const string_view_type& value,
semantic_tag tag,
const ser_context& context,
std::error_code& ec) override
{
return destination_->string_value(value, tag, context, ec);
}
bool visit_byte_string(const byte_string_view& b,
semantic_tag tag,
const ser_context& context,
std::error_code& ec) override
{
return destination_->byte_string_value(b, tag, context, ec);
}
bool visit_byte_string(const byte_string_view& b,
uint64_t ext_tag,
const ser_context& context,
std::error_code& ec) override
{
return destination_->byte_string_value(b, ext_tag, context, ec);
}
bool visit_uint64(uint64_t value, semantic_tag tag, const ser_context& context, std::error_code& ec) override
{
return destination_->uint64_value(value, tag, context, ec);
}
bool visit_int64(int64_t value, semantic_tag tag, const ser_context& context, std::error_code& ec) override
{
return destination_->int64_value(value, tag, context, ec);
}
bool visit_half(uint16_t value, semantic_tag tag, const ser_context& context, std::error_code& ec) override
{
return destination_->half_value(value, tag, context, ec);
}
bool visit_double(double value, semantic_tag tag, const ser_context& context, std::error_code& ec) override
{
return destination_->double_value(value, tag, context, ec);
}
bool visit_bool(bool value, semantic_tag tag, const ser_context& context, std::error_code& ec) override
{
return destination_->bool_value(value, tag, context, ec);
}
bool visit_null(semantic_tag tag, const ser_context& context, std::error_code& ec) override
{
return destination_->null_value(tag, context, ec);
}
bool visit_typed_array(const jsoncons::span<const uint8_t>& s,
semantic_tag tag,
const ser_context& context,
std::error_code& ec) override
{
return destination_->typed_array(s, tag, context, ec);
}
bool visit_typed_array(const jsoncons::span<const uint16_t>& s,
semantic_tag tag,
const ser_context& context,
std::error_code& ec) override
{
return destination_->typed_array(s, tag, context, ec);
}
bool visit_typed_array(const jsoncons::span<const uint32_t>& s,
semantic_tag tag,
const ser_context& context,
std::error_code& ec) override
{
return destination_->typed_array(s, tag, context, ec);
}
bool visit_typed_array(const jsoncons::span<const uint64_t>& s,
semantic_tag tag,
const ser_context& context,
std::error_code& ec) override
{
return destination_->typed_array(s, tag, context, ec);
}
bool visit_typed_array(const jsoncons::span<const int8_t>& s,
semantic_tag tag,
const ser_context& context,
std::error_code& ec) override
{
return destination_->typed_array(s, tag, context, ec);
}
bool visit_typed_array(const jsoncons::span<const int16_t>& s,
semantic_tag tag,
const ser_context& context,
std::error_code& ec) override
{
return destination_->typed_array(s, tag, context, ec);
}
bool visit_typed_array(const jsoncons::span<const int32_t>& s,
semantic_tag tag,
const ser_context& context,
std::error_code& ec) override
{
return destination_->typed_array(s, tag, context, ec);
}
bool visit_typed_array(const jsoncons::span<const int64_t>& s,
semantic_tag tag,
const ser_context& context,
std::error_code& ec) override
{
return destination_->typed_array(s, tag, context, ec);
}
bool visit_typed_array(half_arg_t,
const jsoncons::span<const uint16_t>& s,
semantic_tag tag,
const ser_context& context,
std::error_code& ec) override
{
return destination_->typed_array(half_arg, s, tag, context, ec);
}
bool visit_typed_array(const jsoncons::span<const float>& s,
semantic_tag tag,
const ser_context& context,
std::error_code& ec) override
{
return destination_->typed_array(s, tag, context, ec);
}
bool visit_typed_array(const jsoncons::span<const double>& s,
semantic_tag tag,
const ser_context& context,
std::error_code& ec) override
{
return destination_->typed_array(s, tag, context, ec);
}
bool visit_begin_multi_dim(const jsoncons::span<const size_t>& shape,
semantic_tag tag,
const ser_context& context,
std::error_code& ec) override
{
return destination_->begin_multi_dim(shape, tag, context, ec);
}
bool visit_end_multi_dim(const ser_context& context,
std::error_code& ec) override
{
return destination_->end_multi_dim(context, ec);
}
};
template <class CharT>
class basic_rename_object_key_filter : public basic_json_filter<CharT>
{
public:
using typename basic_json_filter<CharT>::string_view_type;
private:
std::basic_string<CharT> name_;
std::basic_string<CharT> new_name_;
public:
basic_rename_object_key_filter(const std::basic_string<CharT>& name,
const std::basic_string<CharT>& new_name,
basic_json_visitor<CharT>& visitor)
: basic_json_filter<CharT>(visitor),
name_(name), new_name_(new_name)
{
}
private:
bool visit_key(const string_view_type& name,
const ser_context& context,
std::error_code& ec) override
{
if (name == name_)
{
return this->destination().key(new_name_,context, ec);
}
else
{
return this->destination().key(name,context,ec);
}
}
};
template <class From,class To>
class json_visitor_adaptor_base : public From
{
public:
using typename From::string_view_type;
private:
To* destination_;
// noncopyable
json_visitor_adaptor_base(const json_visitor_adaptor_base&) = delete;
json_visitor_adaptor_base& operator=(const json_visitor_adaptor_base&) = delete;
public:
json_visitor_adaptor_base(To& visitor)
: destination_(std::addressof(visitor))
{
}
// moveable
json_visitor_adaptor_base(json_visitor_adaptor_base&&) = default;
json_visitor_adaptor_base& operator=(json_visitor_adaptor_base&&) = default;
To& destination()
{
return *destination_;
}
private:
void visit_flush() override
{
destination_->flush();
}
bool visit_begin_object(semantic_tag tag,
const ser_context& context,
std::error_code& ec) override
{
return destination_->begin_object(tag, context, ec);
}
bool visit_begin_object(std::size_t length,
semantic_tag tag,
const ser_context& context,
std::error_code& ec) override
{
return destination_->begin_object(length, tag, context, ec);
}
bool visit_end_object(const ser_context& context, std::error_code& ec) override
{
return destination_->end_object(context, ec);
}
bool visit_begin_array(semantic_tag tag,
const ser_context& context,
std::error_code& ec) override
{
return destination_->begin_array(tag, context, ec);
}
bool visit_begin_array(std::size_t length,
semantic_tag tag,
const ser_context& context,
std::error_code& ec) override
{
return destination_->begin_array(length, tag, context, ec);
}
bool visit_end_array(const ser_context& context, std::error_code& ec) override
{
return destination_->end_array(context, ec);
}
bool visit_byte_string(const byte_string_view& b,
semantic_tag tag,
const ser_context& context,
std::error_code& ec) override
{
return destination_->byte_string_value(b, tag, context, ec);
}
bool visit_byte_string(const byte_string_view& b,
uint64_t ext_tag,
const ser_context& context,
std::error_code& ec) override
{
return destination_->byte_string_value(b, ext_tag, context, ec);
}
bool visit_half(uint16_t value, semantic_tag tag, const ser_context& context, std::error_code& ec) override
{
return destination_->half_value(value, tag, context, ec);
}
bool visit_double(double value, semantic_tag tag, const ser_context& context, std::error_code& ec) override
{
return destination_->double_value(value, tag, context, ec);
}
bool visit_int64(int64_t value, semantic_tag tag, const ser_context& context, std::error_code& ec) override
{
return destination_->int64_value(value, tag, context, ec);
}
bool visit_uint64(uint64_t value, semantic_tag tag, const ser_context& context, std::error_code& ec) override
{
return destination_->uint64_value(value, tag, context, ec);
}
bool visit_bool(bool value, semantic_tag tag, const ser_context& context, std::error_code& ec) override
{
return destination_->bool_value(value, tag, context, ec);
}
bool visit_null(semantic_tag tag, const ser_context& context, std::error_code& ec) override
{
return destination_->null_value(tag, context, ec);
}
bool visit_typed_array(const jsoncons::span<const uint8_t>& s,
semantic_tag tag,
const ser_context& context,
std::error_code& ec) override
{
return destination_->typed_array(s, tag, context, ec);
}
bool visit_typed_array(const jsoncons::span<const uint16_t>& s,
semantic_tag tag,
const ser_context& context,
std::error_code& ec) override
{
return destination_->typed_array(s, tag, context, ec);
}
bool visit_typed_array(const jsoncons::span<const uint32_t>& s,
semantic_tag tag,
const ser_context& context,
std::error_code& ec) override
{
return destination_->typed_array(s, tag, context, ec);
}
bool visit_typed_array(const jsoncons::span<const uint64_t>& s,
semantic_tag tag,
const ser_context& context,
std::error_code& ec) override
{
return destination_->typed_array(s, tag, context, ec);
}
bool visit_typed_array(const jsoncons::span<const int8_t>& s,
semantic_tag tag,
const ser_context& context,
std::error_code& ec) override
{
return destination_->typed_array(s, tag, context, ec);
}
bool visit_typed_array(const jsoncons::span<const int16_t>& s,
semantic_tag tag,
const ser_context& context,
std::error_code& ec) override
{
return destination_->typed_array(s, tag, context, ec);
}
bool visit_typed_array(const jsoncons::span<const int32_t>& s,
semantic_tag tag,
const ser_context& context,
std::error_code& ec) override
{
return destination_->typed_array(s, tag, context, ec);
}
bool visit_typed_array(const jsoncons::span<const int64_t>& s,
semantic_tag tag,
const ser_context& context,
std::error_code& ec) override
{
return destination_->typed_array(s, tag, context, ec);
}
bool visit_typed_array(half_arg_t,
const jsoncons::span<const uint16_t>& s,
semantic_tag tag,
const ser_context& context,
std::error_code& ec) override
{
return destination_->typed_array(half_arg, s, tag, context, ec);
}
bool visit_typed_array(const jsoncons::span<const float>& s,
semantic_tag tag,
const ser_context& context,
std::error_code& ec) override
{
return destination_->typed_array(s, tag, context, ec);
}
bool visit_typed_array(const jsoncons::span<const double>& s,
semantic_tag tag,
const ser_context& context,
std::error_code& ec) override
{
return destination_->typed_array(s, tag, context, ec);
}
bool visit_begin_multi_dim(const jsoncons::span<const size_t>& shape,
semantic_tag tag,
const ser_context& context,
std::error_code& ec) override
{
return destination_->begin_multi_dim(shape, tag, context, ec);
}
bool visit_end_multi_dim(const ser_context& context,
std::error_code& ec) override
{
return destination_->end_multi_dim(context, ec);
}
};
template <class From,class To,class Enable=void>
class json_visitor_adaptor
{
};
template <class From,class To>
class json_visitor_adaptor<From,To,typename std::enable_if<extension_traits::is_narrow_character<typename From::char_type>::value &&
extension_traits::is_narrow_character<typename To::char_type>::value>::type> : public json_visitor_adaptor_base<From,To>
{
using supertype = json_visitor_adaptor_base<From,To>;
using to_char_type = typename To::char_type;
using from_char_type = typename From::char_type;
public:
using typename From::string_view_type;
using supertype::destination;
private:
// noncopyable
json_visitor_adaptor(const json_visitor_adaptor&) = delete;
json_visitor_adaptor& operator=(const json_visitor_adaptor&) = delete;
public:
json_visitor_adaptor(To& visitor)
: supertype(visitor)
{
}
// moveable
json_visitor_adaptor(json_visitor_adaptor&&) = default;
json_visitor_adaptor& operator=(json_visitor_adaptor&&) = default;
private:
bool visit_key(const string_view_type& key,
const ser_context& context,
std::error_code& ec) override
{
return destination().key(string_view_type(reinterpret_cast<const to_char_type*>(key.data()),key.size()), context, ec);
}
bool visit_string(const string_view_type& value,
semantic_tag tag,
const ser_context& context,
std::error_code& ec) override
{
return destination().string_value(string_view_type(reinterpret_cast<const to_char_type*>(value.data()),value.size()), tag, context, ec);
}
};
template <class From,class To>
class json_visitor_adaptor<From,To,typename std::enable_if<!(extension_traits::is_narrow_character<typename From::char_type>::value &&
extension_traits::is_narrow_character<typename To::char_type>::value)>::type> : public json_visitor_adaptor_base<From,To>
{
using supertype = json_visitor_adaptor_base<From,To>;
public:
using typename From::string_view_type;
using supertype::destination;
private:
// noncopyable
json_visitor_adaptor(const json_visitor_adaptor&) = delete;
json_visitor_adaptor& operator=(const json_visitor_adaptor&) = delete;
public:
json_visitor_adaptor(To& visitor)
: supertype(visitor)
{
}
// moveable
json_visitor_adaptor(json_visitor_adaptor&&) = default;
json_visitor_adaptor& operator=(json_visitor_adaptor&&) = default;
private:
bool visit_key(const string_view_type& name,
const ser_context& context,
std::error_code& ec) override
{
std::basic_string<typename To::char_type> target;
auto result = unicode_traits::convert(name.data(), name.size(), target, unicode_traits::conv_flags::strict);
if (result.ec != unicode_traits::conv_errc())
{
ec = result.ec;
}
return destination().key(target, context, ec);
}
bool visit_string(const string_view_type& value,
semantic_tag tag,
const ser_context& context,
std::error_code& ec) override
{
std::basic_string<typename To::char_type> target;
auto result = unicode_traits::convert(value.data(), value.size(),
target,unicode_traits::conv_flags::strict);
if (result.ec != unicode_traits::conv_errc())
{
JSONCONS_THROW(ser_error(result.ec));
}
return destination().string_value(target, tag, context, ec);
}
};
template <class From,class To>
json_visitor_adaptor<From,To> make_json_visitor_adaptor(To& to)
{
return json_visitor_adaptor<From, To>(to);
}
using json_filter = basic_json_filter<char>;
using wjson_filter = basic_json_filter<wchar_t>;
using rename_object_key_filter = basic_rename_object_key_filter<char>;
using wrename_object_key_filter = basic_rename_object_key_filter<wchar_t>;
#if !defined(JSONCONS_NO_DEPRECATED)
template <class CharT>
using basic_json_content_filter = basic_json_filter<CharT>;
JSONCONS_DEPRECATED_MSG("Instead, use json_filter") typedef basic_json_filter<char> json_content_filter;
JSONCONS_DEPRECATED_MSG("Instead, use wjson_filter") typedef basic_json_filter<wchar_t> wjson_content_filter;
JSONCONS_DEPRECATED_MSG("Instead, use rename_object_key_filter") typedef basic_rename_object_key_filter<char> rename_name_filter;
JSONCONS_DEPRECATED_MSG("Instead, use wrename_object_key_filter") typedef basic_rename_object_key_filter<wchar_t> wrename_name_filter;
JSONCONS_DEPRECATED_MSG("Instead, use rename_object_key_filter") typedef basic_rename_object_key_filter<char> rename_object_member_filter;
JSONCONS_DEPRECATED_MSG("Instead, use wrename_object_key_filter") typedef basic_rename_object_key_filter<wchar_t> wrename_object_member_filter;
#endif
}
#endif

View file

@ -0,0 +1,23 @@
// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_JSON_FWD_HPP
#define JSONCONS_JSON_FWD_HPP
#include <memory> // std::allocator
namespace jsoncons {
struct sorted_policy;
template <class CharT,
class ImplementationPolicy = sorted_policy,
class Allocator = std::allocator<CharT>>
class basic_json;
}
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,860 @@
// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_JSON_OPTIONS_HPP
#define JSONCONS_JSON_OPTIONS_HPP
#include <string>
#include <limits> // std::numeric_limits
#include <cwchar>
#include <jsoncons/json_exception.hpp>
#include <jsoncons/extension_traits.hpp>
namespace jsoncons {
enum class float_chars_format : uint8_t {general,fixed,scientific,hex};
#if !defined(JSONCONS_NO_DEPRECATED)
JSONCONS_DEPRECATED_MSG("Instead, use float_chars_format") typedef float_chars_format chars_format;
#endif
enum class indenting : uint8_t {no_indent = 0, indent = 1};
enum class line_split_kind : uint8_t {same_line,new_line,multi_line};
enum class bigint_chars_format : uint8_t {number, base10, base64, base64url
#if !defined(JSONCONS_NO_DEPRECATED)
,integer = number
#endif
};
#if !defined(JSONCONS_NO_DEPRECATED)
JSONCONS_DEPRECATED_MSG("Instead, use bigint_chars_format") typedef bigint_chars_format bignum_chars_format;
JSONCONS_DEPRECATED_MSG("Instead, use bigint_chars_format") typedef bigint_chars_format big_integer_chars_format;
#endif
enum class byte_string_chars_format : uint8_t {none=0,base16,base64,base64url};
enum class spaces_option : uint8_t {no_spaces=0,space_after,space_before,space_before_and_after};
template <class CharT>
class basic_json_options;
template <class CharT>
class basic_json_options_common
{
friend class basic_json_options<CharT>;
public:
using char_type = CharT;
using string_type = std::basic_string<CharT>;
private:
#if !defined(JSONCONS_NO_DEPRECATED)
bool can_read_nan_replacement_;
bool can_read_pos_inf_replacement_;
bool can_read_neg_inf_replacement_;
string_type nan_replacement_;
string_type pos_inf_replacement_;
string_type neg_inf_replacement_;
#endif
bool enable_nan_to_num_:1;
bool enable_inf_to_num_:1;
bool enable_neginf_to_num_:1;
bool enable_nan_to_str_:1;
bool enable_inf_to_str_:1;
bool enable_neginf_to_str_:1;
bool enable_str_to_nan_:1;
bool enable_str_to_inf_:1;
bool enable_str_to_neginf_:1;
string_type nan_to_num_;
string_type inf_to_num_;
string_type neginf_to_num_;
string_type nan_to_str_;
string_type inf_to_str_;
string_type neginf_to_str_;
int max_nesting_depth_;
protected:
basic_json_options_common()
:
#if !defined(JSONCONS_NO_DEPRECATED)
can_read_nan_replacement_(false),
can_read_pos_inf_replacement_(false),
can_read_neg_inf_replacement_(false),
#endif
enable_nan_to_num_(false),
enable_inf_to_num_(false),
enable_neginf_to_num_(false),
enable_nan_to_str_(false),
enable_inf_to_str_(false),
enable_neginf_to_str_(false),
enable_str_to_nan_(false),
enable_str_to_inf_(false),
enable_str_to_neginf_(false),
max_nesting_depth_(1024)
{}
virtual ~basic_json_options_common() noexcept = default;
basic_json_options_common(const basic_json_options_common&) = default;
basic_json_options_common& operator=(const basic_json_options_common&) = default;
basic_json_options_common(basic_json_options_common&&) = default;
basic_json_options_common& operator=(basic_json_options_common&&) = default;
public:
bool enable_nan_to_num() const
{
return enable_nan_to_num_;
}
bool enable_inf_to_num() const
{
return enable_inf_to_num_;
}
bool enable_neginf_to_num() const
{
return enable_neginf_to_num_ || enable_inf_to_num_;
}
bool enable_nan_to_str() const
{
return enable_nan_to_str_;
}
bool enable_str_to_nan() const
{
return enable_str_to_nan_;
}
bool enable_inf_to_str() const
{
return enable_inf_to_str_;
}
bool enable_str_to_inf() const
{
return enable_str_to_inf_;
}
bool enable_neginf_to_str() const
{
return enable_neginf_to_str_ || enable_inf_to_str_;
}
bool enable_str_to_neginf() const
{
return enable_str_to_neginf_ || enable_str_to_inf_;
}
string_type nan_to_num() const
{
if (enable_nan_to_num_)
{
return nan_to_num_;
}
#if !defined(JSONCONS_NO_DEPRECATED)
else if (!can_read_nan_replacement_) // not string
{
return nan_replacement_;
}
#endif
else
{
return nan_to_num_; // empty string
}
}
string_type inf_to_num() const
{
if (enable_inf_to_num_)
{
return inf_to_num_;
}
#if !defined(JSONCONS_NO_DEPRECATED)
else if (!can_read_pos_inf_replacement_) // not string
{
return pos_inf_replacement_;
}
#endif
else
{
return inf_to_num_; // empty string
}
}
string_type neginf_to_num() const
{
if (enable_neginf_to_num_)
{
return neginf_to_num_;
}
else if (enable_inf_to_num_)
{
string_type s;
s.push_back('-');
s.append(inf_to_num_);
return s;
}
#if !defined(JSONCONS_NO_DEPRECATED)
else if (!can_read_neg_inf_replacement_) // not string
{
return neg_inf_replacement_;
}
#endif
else
{
return neginf_to_num_; // empty string
}
}
string_type nan_to_str() const
{
if (enable_nan_to_str_)
{
return nan_to_str_;
}
#if !defined(JSONCONS_NO_DEPRECATED)
else if (can_read_nan_replacement_ && nan_replacement_.size() >= 2) // string
{
return nan_replacement_.substr(1, nan_replacement_.size() - 2); // Remove quotes
}
#endif
else
{
return nan_to_str_; // empty string
}
}
string_type inf_to_str() const
{
if (enable_inf_to_str_)
{
return inf_to_str_;
}
#if !defined(JSONCONS_NO_DEPRECATED)
else if (can_read_pos_inf_replacement_ && pos_inf_replacement_.size() >= 2) // string
{
return pos_inf_replacement_.substr(1, pos_inf_replacement_.size() - 2); // Strip quotes
}
#endif
else
{
return inf_to_str_; // empty string
}
}
string_type neginf_to_str() const
{
if (enable_neginf_to_str_)
{
return neginf_to_str_;
}
else if (enable_inf_to_str_)
{
string_type s;
s.push_back('-');
s.append(inf_to_str_);
return s;
}
#if !defined(JSONCONS_NO_DEPRECATED)
else if (can_read_neg_inf_replacement_ && neg_inf_replacement_.size() >= 2) // string
{
return neg_inf_replacement_.substr(1, neg_inf_replacement_.size() - 2); // Strip quotes
}
#endif
else
{
return neginf_to_str_; // empty string
}
}
int max_nesting_depth() const
{
return max_nesting_depth_;
}
#if !defined(JSONCONS_NO_DEPRECATED)
JSONCONS_DEPRECATED_MSG("Instead, use enable_nan_to_num() or enable_nan_to_str()")
bool can_read_nan_replacement() const { return can_read_nan_replacement_; }
JSONCONS_DEPRECATED_MSG("Instead, use enable_inf_to_num() or enable_inf_to_str()")
bool can_read_pos_inf_replacement() const { return can_read_pos_inf_replacement_; }
JSONCONS_DEPRECATED_MSG("Instead, use enable_neginf_to_num() or enable_neginf_to_str()")
bool can_read_neg_inf_replacement() const { return can_read_neg_inf_replacement_; }
bool can_write_nan_replacement() const { return !nan_replacement_.empty(); }
bool can_write_pos_inf_replacement() const { return !pos_inf_replacement_.empty(); }
bool can_write_neg_inf_replacement() const { return !neg_inf_replacement_.empty(); }
JSONCONS_DEPRECATED_MSG("Instead, use nan_to_num() or nan_to_str()")
const string_type& nan_replacement() const
{
return nan_replacement_;
}
JSONCONS_DEPRECATED_MSG("Instead, use inf_to_num() or inf_to_str()")
const string_type& pos_inf_replacement() const
{
return pos_inf_replacement_;
}
JSONCONS_DEPRECATED_MSG("Instead, use neginf_to_num() or neginf_to_str()")
const string_type& neg_inf_replacement() const
{
return neg_inf_replacement_;
}
#endif
};
template <class CharT>
class basic_json_decode_options : public virtual basic_json_options_common<CharT>
{
friend class basic_json_options<CharT>;
using super_type = basic_json_options_common<CharT>;
public:
using typename super_type::char_type;
using typename super_type::string_type;
private:
bool lossless_number_:1;
public:
basic_json_decode_options()
: lossless_number_(false)
{
}
basic_json_decode_options(const basic_json_decode_options&) = default;
basic_json_decode_options(basic_json_decode_options&& other)
: super_type(std::forward<basic_json_decode_options>(other)),
lossless_number_(other.lossless_number_)
{
}
basic_json_decode_options& operator=(const basic_json_decode_options&) = default;
bool lossless_number() const
{
return lossless_number_;
}
#if !defined(JSONCONS_NO_DEPRECATED)
JSONCONS_DEPRECATED_MSG("Instead, use lossless_number()")
bool dec_to_str() const
{
return lossless_number_;
}
#endif
};
template <class CharT>
class basic_json_encode_options : public virtual basic_json_options_common<CharT>
{
friend class basic_json_options<CharT>;
using super_type = basic_json_options_common<CharT>;
public:
using typename super_type::char_type;
using typename super_type::string_type;
static constexpr uint8_t indent_size_default = 4;
static constexpr size_t line_length_limit_default = 120;
private:
bool escape_all_non_ascii_:1;
bool escape_solidus_:1;
bool pad_inside_object_braces_:1;
bool pad_inside_array_brackets_:1;
float_chars_format float_format_;
byte_string_chars_format byte_string_format_;
bigint_chars_format bigint_format_;
line_split_kind object_object_line_splits_;
line_split_kind object_array_line_splits_;
line_split_kind array_array_line_splits_;
line_split_kind array_object_line_splits_;
spaces_option spaces_around_colon_;
spaces_option spaces_around_comma_;
int8_t precision_;
uint8_t indent_size_;
std::size_t line_length_limit_;
string_type new_line_chars_;
public:
basic_json_encode_options()
: escape_all_non_ascii_(false),
escape_solidus_(false),
pad_inside_object_braces_(false),
pad_inside_array_brackets_(false),
float_format_(float_chars_format::general),
byte_string_format_(byte_string_chars_format::none),
bigint_format_(bigint_chars_format::base10),
object_object_line_splits_(line_split_kind::multi_line),
object_array_line_splits_(line_split_kind::same_line),
array_array_line_splits_(line_split_kind::new_line),
array_object_line_splits_(line_split_kind::multi_line),
spaces_around_colon_(spaces_option::space_after),
spaces_around_comma_(spaces_option::space_after),
precision_(0),
indent_size_(indent_size_default),
line_length_limit_(line_length_limit_default)
{
new_line_chars_.push_back('\n');
}
basic_json_encode_options(const basic_json_encode_options&) = default;
basic_json_encode_options(basic_json_encode_options&& other)
: super_type(std::forward<basic_json_encode_options>(other)),
escape_all_non_ascii_(other.escape_all_non_ascii_),
escape_solidus_(other.escape_solidus_),
pad_inside_object_braces_(other.pad_inside_object_braces_),
pad_inside_array_brackets_(other.pad_inside_array_brackets_),
float_format_(other.float_format_),
byte_string_format_(other.byte_string_format_),
bigint_format_(other.bigint_format_),
object_object_line_splits_(other.object_object_line_splits_),
object_array_line_splits_(other.object_array_line_splits_),
array_array_line_splits_(other.array_array_line_splits_),
array_object_line_splits_(other.array_object_line_splits_),
spaces_around_colon_(other.spaces_around_colon_),
spaces_around_comma_(other.spaces_around_comma_),
precision_(other.precision_),
indent_size_(other.indent_size_),
line_length_limit_(other.line_length_limit_),
new_line_chars_(std::move(other.new_line_chars_))
{
}
basic_json_encode_options& operator=(const basic_json_encode_options&) = default;
byte_string_chars_format byte_string_format() const {return byte_string_format_;}
bigint_chars_format bigint_format() const {return bigint_format_;}
line_split_kind object_object_line_splits() const {return object_object_line_splits_;}
line_split_kind array_object_line_splits() const {return array_object_line_splits_;}
line_split_kind object_array_line_splits() const {return object_array_line_splits_;}
line_split_kind array_array_line_splits() const {return array_array_line_splits_;}
uint8_t indent_size() const
{
return indent_size_;
}
spaces_option spaces_around_colon() const
{
return spaces_around_colon_;
}
spaces_option spaces_around_comma() const
{
return spaces_around_comma_;
}
bool pad_inside_object_braces() const
{
return pad_inside_object_braces_;
}
bool pad_inside_array_brackets() const
{
return pad_inside_array_brackets_;
}
string_type new_line_chars() const
{
return new_line_chars_;
}
std::size_t line_length_limit() const
{
return line_length_limit_;
}
float_chars_format float_format() const
{
return float_format_;
}
int8_t precision() const
{
return precision_;
}
bool escape_all_non_ascii() const
{
return escape_all_non_ascii_;
}
bool escape_solidus() const
{
return escape_solidus_;
}
#if !defined(JSONCONS_NO_DEPRECATED)
JSONCONS_DEPRECATED_MSG("Instead, use bigint_format()")
bigint_chars_format bignum_format() const {return bigint_format_;}
JSONCONS_DEPRECATED_MSG("Instead, use indent_size()")
uint8_t indent() const
{
return indent_size();
}
JSONCONS_DEPRECATED_MSG("Instead, use object_object_line_splits()")
line_split_kind object_object_split_lines() const {return object_object_line_splits_;}
JSONCONS_DEPRECATED_MSG("Instead, use array_object_line_splits()")
line_split_kind array_object_split_lines() const {return array_object_line_splits_;}
JSONCONS_DEPRECATED_MSG("Instead, use object_array_line_splits()")
line_split_kind object_array_split_lines() const {return object_array_line_splits_;}
JSONCONS_DEPRECATED_MSG("Instead, use array_array_line_splits()")
line_split_kind array_array_split_lines() const {return array_array_line_splits_;}
#endif
};
template <class CharT>
class basic_json_options final: public basic_json_decode_options<CharT>,
public basic_json_encode_options<CharT>
{
public:
using char_type = CharT;
using string_type = std::basic_string<CharT>;
using basic_json_options_common<CharT>::max_nesting_depth;
using basic_json_decode_options<CharT>::enable_str_to_nan;
using basic_json_decode_options<CharT>::enable_str_to_inf;
using basic_json_decode_options<CharT>::enable_str_to_neginf;
using basic_json_decode_options<CharT>::nan_to_str;
using basic_json_decode_options<CharT>::inf_to_str;
using basic_json_decode_options<CharT>::neginf_to_str;
using basic_json_decode_options<CharT>::nan_to_num;
using basic_json_decode_options<CharT>::inf_to_num;
using basic_json_decode_options<CharT>::neginf_to_num;
using basic_json_decode_options<CharT>::lossless_number;
using basic_json_encode_options<CharT>::byte_string_format;
using basic_json_encode_options<CharT>::bigint_format;
using basic_json_encode_options<CharT>::object_object_line_splits;
using basic_json_encode_options<CharT>::array_object_line_splits;
using basic_json_encode_options<CharT>::object_array_line_splits;
using basic_json_encode_options<CharT>::array_array_line_splits;
using basic_json_encode_options<CharT>::indent_size;
using basic_json_encode_options<CharT>::spaces_around_colon;
using basic_json_encode_options<CharT>::spaces_around_comma;
using basic_json_encode_options<CharT>::pad_inside_object_braces;
using basic_json_encode_options<CharT>::pad_inside_array_brackets;
using basic_json_encode_options<CharT>::new_line_chars;
using basic_json_encode_options<CharT>::line_length_limit;
using basic_json_encode_options<CharT>::float_format;
using basic_json_encode_options<CharT>::precision;
using basic_json_encode_options<CharT>::escape_all_non_ascii;
using basic_json_encode_options<CharT>::escape_solidus;
public:
// Constructors
basic_json_options() = default;
basic_json_options(const basic_json_options&) = default;
basic_json_options(basic_json_options&&) = default;
basic_json_options& operator=(const basic_json_options&) = default;
basic_json_options& operator=(basic_json_options&&) = default;
basic_json_options& nan_to_num(const string_type& value)
{
this->enable_nan_to_num_ = true;
this->nan_to_str_.clear();
this->nan_to_num_ = value;
return *this;
}
basic_json_options& inf_to_num(const string_type& value)
{
this->enable_inf_to_num_ = true;
this->inf_to_str_.clear();
this->inf_to_num_ = value;
return *this;
}
basic_json_options& neginf_to_num(const string_type& value)
{
this->enable_neginf_to_num_ = true;
this->neginf_to_str_.clear();
this->neginf_to_num_ = value;
return *this;
}
basic_json_options& nan_to_str(const string_type& value, bool enable_inverse = true)
{
this->enable_nan_to_str_ = true;
this->enable_str_to_nan_ = enable_inverse;
this->nan_to_num_.clear();
this->nan_to_str_ = value;
return *this;
}
basic_json_options& inf_to_str(const string_type& value, bool enable_inverse = true)
{
this->enable_inf_to_str_ = true;
this->enable_str_to_inf_ = enable_inverse;
this->inf_to_num_.clear();
this->inf_to_str_ = value;
return *this;
}
basic_json_options& neginf_to_str(const string_type& value, bool enable_inverse = true)
{
this->enable_neginf_to_str_ = true;
this->enable_str_to_neginf_ = enable_inverse;
this->neginf_to_num_.clear();
this->neginf_to_str_ = value;
return *this;
}
JSONCONS_DEPRECATED_MSG("Instead, use inf_to_num(const string_type&) or inf_to_str(const string_type&)")
basic_json_options& replace_inf(bool replace)
{
this->can_read_pos_inf_replacement_ = replace;
this->can_read_neg_inf_replacement_ = replace;
return *this;
}
JSONCONS_DEPRECATED_MSG("Instead, use inf_to_num(const string_type&) or inf_to_str(const string_type&)")
basic_json_options& replace_pos_inf(bool replace)
{
this->can_read_pos_inf_replacement_ = replace;
return *this;
}
JSONCONS_DEPRECATED_MSG("Instead, use neginf_to_num(const string_type&) or neginf_to_str(const string_type&)")
basic_json_options& replace_neg_inf(bool replace)
{
this->can_read_neg_inf_replacement_ = replace;
return *this;
}
JSONCONS_DEPRECATED_MSG("Instead, use nan_to_num(const string_type&) or nan_to_str(const string_type&)")
basic_json_options& nan_replacement(const string_type& value)
{
this->nan_replacement_ = value;
this->can_read_nan_replacement_ = is_string(value);
return *this;
}
JSONCONS_DEPRECATED_MSG("Instead, use inf_to_num(const string_type&) or inf_to_str(const string_type&)")
basic_json_options& pos_inf_replacement(const string_type& value)
{
this->pos_inf_replacement_ = value;
this->can_read_pos_inf_replacement_ = is_string(value);
return *this;
}
JSONCONS_DEPRECATED_MSG("Instead, use neginf_to_num(const string_type&) or neginf_to_str(const string_type&)")
basic_json_options& neg_inf_replacement(const string_type& value)
{
this->neg_inf_replacement_ = value;
this->can_read_neg_inf_replacement_ = is_string(value);
return *this;
}
basic_json_options& byte_string_format(byte_string_chars_format value) {this->byte_string_format_ = value; return *this;}
basic_json_options& bigint_format(bigint_chars_format value) {this->bigint_format_ = value; return *this;}
basic_json_options& object_object_line_splits(line_split_kind value) {this->object_object_line_splits_ = value; return *this;}
basic_json_options& array_object_line_splits(line_split_kind value) {this->array_object_line_splits_ = value; return *this;}
basic_json_options& object_array_line_splits(line_split_kind value) {this->object_array_line_splits_ = value; return *this;}
basic_json_options& array_array_line_splits(line_split_kind value) {this->array_array_line_splits_ = value; return *this;}
basic_json_options& indent_size(uint8_t value)
{
this->indent_size_ = value;
return *this;
}
basic_json_options& spaces_around_colon(spaces_option value)
{
this->spaces_around_colon_ = value;
return *this;
}
basic_json_options& spaces_around_comma(spaces_option value)
{
this->spaces_around_comma_ = value;
return *this;
}
basic_json_options& pad_inside_object_braces(bool value)
{
this->pad_inside_object_braces_ = value;
return *this;
}
basic_json_options& pad_inside_array_brackets(bool value)
{
this->pad_inside_array_brackets_ = value;
return *this;
}
basic_json_options& new_line_chars(const string_type& value)
{
this->new_line_chars_ = value;
return *this;
}
basic_json_options& lossless_number(bool value)
{
this->lossless_number_ = value;
return *this;
}
basic_json_options& line_length_limit(std::size_t value)
{
this->line_length_limit_ = value;
return *this;
}
basic_json_options& float_format(float_chars_format value)
{
this->float_format_ = value;
return *this;
}
basic_json_options& precision(int8_t value)
{
this->precision_ = value;
return *this;
}
basic_json_options& escape_all_non_ascii(bool value)
{
this->escape_all_non_ascii_ = value;
return *this;
}
basic_json_options& escape_solidus(bool value)
{
this->escape_solidus_ = value;
return *this;
}
basic_json_options& max_nesting_depth(int value)
{
this->max_nesting_depth_ = value;
return *this;
}
#if !defined(JSONCONS_NO_DEPRECATED)
JSONCONS_DEPRECATED_MSG("Instead, use bigint_format(bigint_chars_format)")
basic_json_options& big_integer_format(bigint_chars_format value) {this->bigint_format_ = value; return *this;}
JSONCONS_DEPRECATED_MSG("Instead, use bigint_format(bigint_chars_format)")
basic_json_options& bignum_format(bigint_chars_format value) {this->bigint_format_ = value; return *this;}
JSONCONS_DEPRECATED_MSG("Instead, use float_format(float_chars_format)")
basic_json_options& floating_point_format(float_chars_format value)
{
this->float_format_ = value;
return *this;
}
JSONCONS_DEPRECATED_MSG("Instead, use lossless_number(bool)")
basic_json_options& dec_to_str(bool value)
{
this->lossless_number_ = value;
return *this;
}
JSONCONS_DEPRECATED_MSG("Instead, use indent_size(uint8_t_t)")
basic_json_options& indent(uint8_t value)
{
return indent_size(value);
}
JSONCONS_DEPRECATED_MSG("Instead, use object_object_line_splits(line_split_kind)")
basic_json_options& object_object_split_lines(line_split_kind value) {this->object_object_line_splits_ = value; return *this;}
JSONCONS_DEPRECATED_MSG("Instead, use array_object_line_splits(line_split_kind)")
basic_json_options& array_object_split_lines(line_split_kind value) {this->array_object_line_splits_ = value; return *this;}
JSONCONS_DEPRECATED_MSG("Instead, use object_array_line_splits(line_split_kind)")
basic_json_options& object_array_split_lines(line_split_kind value) {this->object_array_line_splits_ = value; return *this;}
JSONCONS_DEPRECATED_MSG("Instead, use array_array_line_splits(line_split_kind)")
basic_json_options& array_array_split_lines(line_split_kind value) {this->array_array_line_splits_ = value; return *this;}
#endif
private:
enum class input_state {initial,begin_quote,character,end_quote,escape,error};
bool is_string(const string_type& s) const
{
input_state state = input_state::initial;
for (char_type c : s)
{
switch (c)
{
case '\t': case ' ': case '\n': case'\r':
break;
case '\\':
state = input_state::escape;
break;
case '\"':
switch (state)
{
case input_state::initial:
state = input_state::begin_quote;
break;
case input_state::begin_quote:
case input_state::character:
state = input_state::end_quote;
break;
case input_state::end_quote:
state = input_state::error;
break;
case input_state::escape:
state = input_state::character;
break;
default:
state = input_state::character;
break;
}
break;
default:
break;
}
}
return state == input_state::end_quote;
}
};
using json_options = basic_json_options<char>;
using wjson_options = basic_json_options<wchar_t>;
#if !defined(JSONCONS_NO_DEPRECATED)
JSONCONS_DEPRECATED_MSG("json_options") typedef json_options output_format;
JSONCONS_DEPRECATED_MSG("wjson_options") typedef wjson_options woutput_format;
JSONCONS_DEPRECATED_MSG("json_options") typedef json_options serialization_options;
JSONCONS_DEPRECATED_MSG("wjson_options") typedef wjson_options wserialization_options;
JSONCONS_DEPRECATED_MSG("json_options") typedef json_options json_serializing_options;
JSONCONS_DEPRECATED_MSG("wjson_options") typedef wjson_options wjson_serializing_options;
#endif
}
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,731 @@
// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_JSON_READER_HPP
#define JSONCONS_JSON_READER_HPP
#include <memory> // std::allocator
#include <string>
#include <vector>
#include <stdexcept>
#include <system_error>
#include <ios>
#include <utility> // std::move
#include <jsoncons/source.hpp>
#include <jsoncons/json_exception.hpp>
#include <jsoncons/json_visitor.hpp>
#include <jsoncons/json_parser.hpp>
#include <jsoncons/source_adaptor.hpp>
namespace jsoncons {
// utf8_other_json_input_adapter
template <class CharT>
class json_utf8_to_other_visitor_adaptor : public json_visitor
{
public:
using json_visitor::string_view_type;
private:
basic_default_json_visitor<CharT> default_visitor_;
basic_json_visitor<CharT>& other_visitor_;
//std::function<bool(json_errc,const ser_context&)> err_handler_;
// noncopyable and nonmoveable
json_utf8_to_other_visitor_adaptor(const json_utf8_to_other_visitor_adaptor<CharT>&) = delete;
json_utf8_to_other_visitor_adaptor<CharT>& operator=(const json_utf8_to_other_visitor_adaptor<CharT>&) = delete;
public:
json_utf8_to_other_visitor_adaptor()
: other_visitor_(default_visitor_)
{
}
json_utf8_to_other_visitor_adaptor(basic_json_visitor<CharT>& other_visitor/*,
std::function<bool(json_errc,const ser_context&)> err_handler*/)
: other_visitor_(other_visitor)/*,
err_handler_(err_handler)*/
{
}
private:
void visit_flush() override
{
other_visitor_.flush();
}
bool visit_begin_object(semantic_tag tag, const ser_context& context, std::error_code& ec) override
{
return other_visitor_.begin_object(tag, context, ec);
}
bool visit_end_object(const ser_context& context, std::error_code& ec) override
{
return other_visitor_.end_object(context, ec);
}
bool visit_begin_array(semantic_tag tag, const ser_context& context, std::error_code& ec) override
{
return other_visitor_.begin_array(tag, context, ec);
}
bool visit_end_array(const ser_context& context, std::error_code& ec) override
{
return other_visitor_.end_array(context, ec);
}
bool visit_key(const string_view_type& name, const ser_context& context, std::error_code& ec) override
{
std::basic_string<CharT> target;
auto result = unicode_traits::convert(
name.data(), name.size(), target,
unicode_traits::conv_flags::strict);
if (result.ec != unicode_traits::conv_errc())
{
JSONCONS_THROW(ser_error(result.ec,context.line(),context.column()));
}
return other_visitor_.key(target, context, ec);
}
bool visit_string(const string_view_type& value, semantic_tag tag, const ser_context& context, std::error_code& ec) override
{
std::basic_string<CharT> target;
auto result = unicode_traits::convert(
value.data(), value.size(), target,
unicode_traits::conv_flags::strict);
if (result.ec != unicode_traits::conv_errc())
{
ec = result.ec;
return false;
}
return other_visitor_.string_value(target, tag, context, ec);
}
bool visit_int64(int64_t value,
semantic_tag tag,
const ser_context& context,
std::error_code& ec) override
{
return other_visitor_.int64_value(value, tag, context, ec);
}
bool visit_uint64(uint64_t value,
semantic_tag tag,
const ser_context& context,
std::error_code& ec) override
{
return other_visitor_.uint64_value(value, tag, context, ec);
}
bool visit_half(uint16_t value,
semantic_tag tag,
const ser_context& context,
std::error_code& ec) override
{
return other_visitor_.half_value(value, tag, context, ec);
}
bool visit_double(double value,
semantic_tag tag,
const ser_context& context,
std::error_code& ec) override
{
return other_visitor_.double_value(value, tag, context, ec);
}
bool visit_bool(bool value, semantic_tag tag, const ser_context& context, std::error_code& ec) override
{
return other_visitor_.bool_value(value, tag, context, ec);
}
bool visit_null(semantic_tag tag, const ser_context& context, std::error_code& ec) override
{
return other_visitor_.null_value(tag, context, ec);
}
};
template<class CharT,class Source=jsoncons::stream_source<CharT>,class Allocator=std::allocator<char>>
class basic_json_reader
{
public:
using char_type = CharT;
using source_type = Source;
using string_view_type = jsoncons::basic_string_view<CharT>;
private:
typedef typename std::allocator_traits<Allocator>:: template rebind_alloc<CharT> char_allocator_type;
static constexpr size_t default_max_buffer_size = 16384;
json_source_adaptor<Source> source_;
basic_default_json_visitor<CharT> default_visitor_;
basic_json_visitor<CharT>& visitor_;
basic_json_parser<CharT,Allocator> parser_;
// Noncopyable and nonmoveable
basic_json_reader(const basic_json_reader&) = delete;
basic_json_reader& operator=(const basic_json_reader&) = delete;
public:
template <class Sourceable>
explicit basic_json_reader(Sourceable&& source, const Allocator& alloc = Allocator())
: basic_json_reader(std::forward<Sourceable>(source),
default_visitor_,
basic_json_decode_options<CharT>(),
default_json_parsing(),
alloc)
{
}
template <class Sourceable>
basic_json_reader(Sourceable&& source,
const basic_json_decode_options<CharT>& options,
const Allocator& alloc = Allocator())
: basic_json_reader(std::forward<Sourceable>(source),
default_visitor_,
options,
default_json_parsing(),
alloc)
{
}
template <class Sourceable>
basic_json_reader(Sourceable&& source,
std::function<bool(json_errc,const ser_context&)> err_handler,
const Allocator& alloc = Allocator())
: basic_json_reader(std::forward<Sourceable>(source),
default_visitor_,
basic_json_decode_options<CharT>(),
err_handler,
alloc)
{
}
template <class Sourceable>
basic_json_reader(Sourceable&& source,
const basic_json_decode_options<CharT>& options,
std::function<bool(json_errc,const ser_context&)> err_handler,
const Allocator& alloc = Allocator())
: basic_json_reader(std::forward<Sourceable>(source),
default_visitor_,
options,
err_handler,
alloc)
{
}
template <class Sourceable>
basic_json_reader(Sourceable&& source,
basic_json_visitor<CharT>& visitor,
const Allocator& alloc = Allocator())
: basic_json_reader(std::forward<Sourceable>(source),
visitor,
basic_json_decode_options<CharT>(),
default_json_parsing(),
alloc)
{
}
template <class Sourceable>
basic_json_reader(Sourceable&& source,
basic_json_visitor<CharT>& visitor,
const basic_json_decode_options<CharT>& options,
const Allocator& alloc = Allocator())
: basic_json_reader(std::forward<Sourceable>(source),
visitor,
options,
default_json_parsing(),
alloc)
{
}
template <class Sourceable>
basic_json_reader(Sourceable&& source,
basic_json_visitor<CharT>& visitor,
std::function<bool(json_errc,const ser_context&)> err_handler,
const Allocator& alloc = Allocator())
: basic_json_reader(std::forward<Sourceable>(source),
visitor,
basic_json_decode_options<CharT>(),
err_handler,
alloc)
{
}
template <class Sourceable>
basic_json_reader(Sourceable&& source,
basic_json_visitor<CharT>& visitor,
const basic_json_decode_options<CharT>& options,
std::function<bool(json_errc,const ser_context&)> err_handler,
const Allocator& alloc = Allocator())
: source_(std::forward<Sourceable>(source)),
visitor_(visitor),
parser_(options,err_handler,alloc)
{
}
#if !defined(JSONCONS_NO_DEPRECATED)
JSONCONS_DEPRECATED_MSG("Instead, use max_nesting_depth() on options")
int max_nesting_depth() const
{
return parser_.max_nesting_depth();
}
JSONCONS_DEPRECATED_MSG("Instead, use max_nesting_depth(int) on options")
void max_nesting_depth(int depth)
{
parser_.max_nesting_depth(depth);
}
#endif
void read_next()
{
std::error_code ec;
read_next(ec);
if (ec)
{
JSONCONS_THROW(ser_error(ec,parser_.line(),parser_.column()));
}
}
void read_next(std::error_code& ec)
{
if (source_.is_error())
{
ec = json_errc::source_error;
return;
}
parser_.reset();
while (!parser_.stopped())
{
if (parser_.source_exhausted())
{
auto s = source_.read_buffer(ec);
if (ec) return;
if (s.size() > 0)
{
parser_.update(s.data(),s.size());
}
}
bool eof = parser_.source_exhausted();
parser_.parse_some(visitor_, ec);
if (ec) return;
if (eof)
{
if (parser_.enter())
{
break;
}
else if (!parser_.accept())
{
ec = json_errc::unexpected_eof;
return;
}
}
}
while (!source_.eof())
{
parser_.skip_whitespace();
if (parser_.source_exhausted())
{
auto s = source_.read_buffer(ec);
if (ec) return;
if (s.size() > 0)
{
parser_.update(s.data(),s.size());
}
}
else
{
break;
}
}
}
void check_done()
{
std::error_code ec;
check_done(ec);
if (ec)
{
JSONCONS_THROW(ser_error(ec,parser_.line(),parser_.column()));
}
}
std::size_t line() const
{
return parser_.line();
}
std::size_t column() const
{
return parser_.column();
}
void check_done(std::error_code& ec)
{
if (source_.is_error())
{
ec = json_errc::source_error;
return;
}
if (source_.eof())
{
parser_.check_done(ec);
if (ec) return;
}
else
{
do
{
if (parser_.source_exhausted())
{
auto s = source_.read_buffer(ec);
if (ec) return;
if (s.size() > 0)
{
parser_.update(s.data(),s.size());
}
}
if (!parser_.source_exhausted())
{
parser_.check_done(ec);
if (ec) return;
}
}
while (!eof());
}
}
bool eof() const
{
return parser_.source_exhausted() && source_.eof();
}
void read()
{
read_next();
check_done();
}
void read(std::error_code& ec)
{
read_next(ec);
if (!ec)
{
check_done(ec);
}
}
};
template<class CharT,class Source=jsoncons::stream_source<CharT>,class Allocator=std::allocator<char>>
class legacy_basic_json_reader
{
public:
using char_type = CharT;
using source_type = Source;
using string_view_type = jsoncons::basic_string_view<CharT>;
private:
typedef typename std::allocator_traits<Allocator>:: template rebind_alloc<CharT> char_allocator_type;
static constexpr size_t default_max_buffer_size = 16384;
json_source_adaptor<Source> source_;
basic_default_json_visitor<CharT> default_visitor_;
basic_json_visitor<CharT>& visitor_;
basic_json_parser<CharT,Allocator> parser_;
// Noncopyable and nonmoveable
legacy_basic_json_reader(const legacy_basic_json_reader&) = delete;
legacy_basic_json_reader& operator=(const legacy_basic_json_reader&) = delete;
public:
template <class Sourceable>
explicit legacy_basic_json_reader(Sourceable&& source, const Allocator& alloc = Allocator())
: legacy_basic_json_reader(std::forward<Sourceable>(source),
default_visitor_,
basic_json_decode_options<CharT>(),
default_json_parsing(),
alloc)
{
}
template <class Sourceable>
legacy_basic_json_reader(Sourceable&& source,
const basic_json_decode_options<CharT>& options,
const Allocator& alloc = Allocator())
: legacy_basic_json_reader(std::forward<Sourceable>(source),
default_visitor_,
options,
default_json_parsing(),
alloc)
{
}
template <class Sourceable>
legacy_basic_json_reader(Sourceable&& source,
std::function<bool(json_errc,const ser_context&)> err_handler,
const Allocator& alloc = Allocator())
: legacy_basic_json_reader(std::forward<Sourceable>(source),
default_visitor_,
basic_json_decode_options<CharT>(),
err_handler,
alloc)
{
}
template <class Sourceable>
legacy_basic_json_reader(Sourceable&& source,
const basic_json_decode_options<CharT>& options,
std::function<bool(json_errc,const ser_context&)> err_handler,
const Allocator& alloc = Allocator())
: legacy_basic_json_reader(std::forward<Sourceable>(source),
default_visitor_,
options,
err_handler,
alloc)
{
}
template <class Sourceable>
legacy_basic_json_reader(Sourceable&& source,
basic_json_visitor<CharT>& visitor,
const Allocator& alloc = Allocator())
: legacy_basic_json_reader(std::forward<Sourceable>(source),
visitor,
basic_json_decode_options<CharT>(),
default_json_parsing(),
alloc)
{
}
template <class Sourceable>
legacy_basic_json_reader(Sourceable&& source,
basic_json_visitor<CharT>& visitor,
const basic_json_decode_options<CharT>& options,
const Allocator& alloc = Allocator())
: legacy_basic_json_reader(std::forward<Sourceable>(source),
visitor,
options,
default_json_parsing(),
alloc)
{
}
template <class Sourceable>
legacy_basic_json_reader(Sourceable&& source,
basic_json_visitor<CharT>& visitor,
std::function<bool(json_errc,const ser_context&)> err_handler,
const Allocator& alloc = Allocator())
: legacy_basic_json_reader(std::forward<Sourceable>(source),
visitor,
basic_json_decode_options<CharT>(),
err_handler,
alloc)
{
}
template <class Sourceable>
legacy_basic_json_reader(Sourceable&& source,
basic_json_visitor<CharT>& visitor,
const basic_json_decode_options<CharT>& options,
std::function<bool(json_errc,const ser_context&)> err_handler,
const Allocator& alloc = Allocator(),
typename std::enable_if<!std::is_constructible<jsoncons::basic_string_view<CharT>,Sourceable>::value>::type* = 0)
: source_(std::forward<Sourceable>(source)),
visitor_(visitor),
parser_(options,err_handler,alloc)
{
}
template <class Sourceable>
legacy_basic_json_reader(Sourceable&& source,
basic_json_visitor<CharT>& visitor,
const basic_json_decode_options<CharT>& options,
std::function<bool(json_errc,const ser_context&)> err_handler,
const Allocator& alloc = Allocator(),
typename std::enable_if<std::is_constructible<jsoncons::basic_string_view<CharT>,Sourceable>::value>::type* = 0)
: source_(),
visitor_(visitor),
parser_(options,err_handler,alloc)
{
jsoncons::basic_string_view<CharT> sv(std::forward<Sourceable>(source));
auto r = unicode_traits::detect_json_encoding(sv.data(), sv.size());
if (!(r.encoding == unicode_traits::encoding_kind::utf8 || r.encoding == unicode_traits::encoding_kind::undetected))
{
JSONCONS_THROW(ser_error(json_errc::illegal_unicode_character,parser_.line(),parser_.column()));
}
std::size_t offset = (r.ptr - sv.data());
parser_.update(sv.data()+offset,sv.size()-offset);
}
#if !defined(JSONCONS_NO_DEPRECATED)
JSONCONS_DEPRECATED_MSG("Instead, use max_nesting_depth() on options")
int max_nesting_depth() const
{
return parser_.max_nesting_depth();
}
JSONCONS_DEPRECATED_MSG("Instead, use max_nesting_depth(int) on options")
void max_nesting_depth(int depth)
{
parser_.max_nesting_depth(depth);
}
#endif
void read_next()
{
std::error_code ec;
read_next(ec);
if (ec)
{
JSONCONS_THROW(ser_error(ec,parser_.line(),parser_.column()));
}
}
void read_next(std::error_code& ec)
{
if (source_.is_error())
{
ec = json_errc::source_error;
return;
}
parser_.reset();
while (!parser_.stopped())
{
if (parser_.source_exhausted())
{
auto s = source_.read_buffer(ec);
if (ec) return;
if (s.size() > 0)
{
parser_.update(s.data(),s.size());
}
}
bool eof = parser_.source_exhausted();
parser_.parse_some(visitor_, ec);
if (ec) return;
if (eof)
{
if (parser_.enter())
{
break;
}
else if (!parser_.accept())
{
ec = json_errc::unexpected_eof;
return;
}
}
}
while (!source_.eof())
{
parser_.skip_whitespace();
if (parser_.source_exhausted())
{
auto s = source_.read_buffer(ec);
if (ec) return;
if (s.size() > 0)
{
parser_.update(s.data(),s.size());
}
}
else
{
break;
}
}
}
void check_done()
{
std::error_code ec;
check_done(ec);
if (ec)
{
JSONCONS_THROW(ser_error(ec,parser_.line(),parser_.column()));
}
}
std::size_t line() const
{
return parser_.line();
}
std::size_t column() const
{
return parser_.column();
}
void check_done(std::error_code& ec)
{
if (source_.is_error())
{
ec = json_errc::source_error;
return;
}
if (source_.eof())
{
parser_.check_done(ec);
if (ec) return;
}
else
{
do
{
if (parser_.source_exhausted())
{
auto s = source_.read_buffer(ec);
if (ec) return;
if (s.size() > 0)
{
parser_.update(s.data(),s.size());
}
}
if (!parser_.source_exhausted())
{
parser_.check_done(ec);
if (ec) return;
}
}
while (!eof());
}
}
bool eof() const
{
return parser_.source_exhausted() && source_.eof();
}
void read()
{
read_next();
check_done();
}
void read(std::error_code& ec)
{
read_next(ec);
if (!ec)
{
check_done(ec);
}
}
};
#if !defined(JSONCONS_NO_DEPRECATED)
using json_reader = legacy_basic_json_reader<char>;
using wjson_reader = legacy_basic_json_reader<wchar_t>;
#endif
using json_string_reader = basic_json_reader<char,string_source<char>>;
using wjson_string_reader = basic_json_reader<wchar_t,string_source<wchar_t>>;
using json_stream_reader = basic_json_reader<char,stream_source<char>>;
using wjson_stream_reader = basic_json_reader<wchar_t,stream_source<wchar_t>>;
}
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,144 @@
// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_JSON_TRAITS_MACROS_DEPRECATED_HPP
#define JSONCONS_JSON_TRAITS_MACROS_DEPRECATED_HPP
#include <jsoncons/json_traits_macros.hpp>
#if !defined(JSONCONS_NO_DEPRECATED)
#define JSONCONS_MEMBER_TRAITS_DECL(ValueType, ...) \
JSONCONS_MEMBER_TRAITS_BASE(JSONCONS_AS,JSONCONS_TO_JSON,0, ValueType, JSONCONS_NARGS(__VA_ARGS__), 0, __VA_ARGS__) \
/**/
#define JSONCONS_TPL_MEMBER_TRAITS_DECL(NumTemplateParams, ValueType, ...) \
JSONCONS_MEMBER_TRAITS_BASE(JSONCONS_AS,JSONCONS_TO_JSON,NumTemplateParams, ValueType, JSONCONS_NARGS(__VA_ARGS__), 0, __VA_ARGS__) \
/**/
#define JSONCONS_MEMBER_NAMED_TRAITS_DECL(ValueType, ...) \
JSONCONS_MEMBER_NAME_TRAITS_BASE(JSONCONS_NAME_AS, JSONCONS_NAME_TO_JSON, 0, ValueType, JSONCONS_NARGS(__VA_ARGS__), 0, __VA_ARGS__) \
/**/
#define JSONCONS_TPL_MEMBER_NAMED_TRAITS_DECL(NumTemplateParams, ValueType, ...) \
JSONCONS_MEMBER_NAME_TRAITS_BASE(JSONCONS_NAME_AS, JSONCONS_NAME_TO_JSON, NumTemplateParams, ValueType, JSONCONS_NARGS(__VA_ARGS__), 0, __VA_ARGS__) \
/**/
#define JSONCONS_GETTER_SETTER_TRAITS_DECL(ValueType,GetPrefix,SetPrefix, ...) \
JSONCONS_GETTER_SETTER_TRAITS_BASE(JSONCONS_GETTER_SETTER_AS, JSONCONS_GETTER_SETTER_TO_JSON,0, ValueType,GetPrefix,SetPrefix, JSONCONS_NARGS(__VA_ARGS__), 0, __VA_ARGS__) \
/**/
#define JSONCONS_TPL_GETTER_SETTER_TRAITS_DECL(NumTemplateParams, ValueType,GetPrefix,SetPrefix, ...) \
JSONCONS_GETTER_SETTER_TRAITS_BASE(JSONCONS_GETTER_SETTER_AS, JSONCONS_GETTER_SETTER_TO_JSON,NumTemplateParams, ValueType,GetPrefix,SetPrefix, JSONCONS_NARGS(__VA_ARGS__), 0, __VA_ARGS__) \
/**/
#define JSONCONS_GETTER_SETTER_NAMED_TRAITS_DECL(ValueType, ...) \
JSONCONS_GETTER_SETTER_NAME_TRAITS_BASE(JSONCONS_GETTER_SETTER_NAME_AS,JSONCONS_GETTER_SETTER_NAME_TO_JSON, 0, ValueType, JSONCONS_NARGS(__VA_ARGS__), 0, __VA_ARGS__) \
/**/
#define JSONCONS_TPL_GETTER_SETTER_NAMED_TRAITS_DECL(NumTemplateParams, ValueType, ...) \
JSONCONS_GETTER_SETTER_NAME_TRAITS_BASE(JSONCONS_GETTER_SETTER_NAME_AS,JSONCONS_GETTER_SETTER_NAME_TO_JSON, NumTemplateParams, ValueType, JSONCONS_NARGS(__VA_ARGS__), 0, __VA_ARGS__) \
/**/
#define JSONCONS_ALL_GETTER_CTOR_TRAITS JSONCONS_ALL_CTOR_GETTER_TRAITS
#define JSONCONS_N_GETTER_CTOR_TRAITS JSONCONS_N_CTOR_GETTER_TRAITS
#define JSONCONS_TPL_ALL_GETTER_CTOR_TRAITS JSONCONS_TPL_ALL_CTOR_GETTER_TRAITS
#define JSONCONS_TPL_N_GETTER_CTOR_TRAITS JSONCONS_TPL_N_CTOR_GETTER_TRAITS
#define JSONCONS_ALL_GETTER_CTOR_NAME_TRAITS JSONCONS_ALL_CTOR_GETTER_NAME_TRAITS
#define JSONCONS_N_GETTER_CTOR_NAME_TRAITS JSONCONS_N_CTOR_GETTER_NAME_TRAITS
#define JSONCONS_TPL_ALL_GETTER_CTOR_NAME_TRAITS JSONCONS_TPL_ALL_CTOR_GETTER_NAME_TRAITS
#define JSONCONS_TPL_N_GETTER_CTOR_NAME_TRAITS JSONCONS_TPL_N_CTOR_GETTER_NAME_TRAITS
#define JSONCONS_PROPERTY_TRAITS_DECL JSONCONS_GETTER_SETTER_TRAITS_DECL
#define JSONCONS_TPL_PROPERTY_TRAITS_DECL JSONCONS_TPL_GETTER_SETTER_TRAITS_DECL
#define JSONCONS_TYPE_TRAITS_DECL JSONCONS_MEMBER_TRAITS_DECL
#define JSONCONS_MEMBER_TRAITS_NAMED_DECL JSONCONS_MEMBER_NAMED_TRAITS_DECL
#define JSONCONS_TEMPLATE_MEMBER_TRAITS_NAMED_DECL JSONCONS_TPL_MEMBER_NAMED_TRAITS_DECL
#define JSONCONS_TEMPLATE_GETTER_SETTER_TRAITS_NAMED_DECL JSONCONS_TPL_GETTER_SETTER_NAMED_TRAITS_DECL
#define JSONCONS_TEMPLATE_MEMBER_TRAITS_DECL JSONCONS_TPL_MEMBER_TRAITS_DECL
#define JSONCONS_N_MEMBER_NAMED_TRAITS JSONCONS_N_MEMBER_NAME_TRAITS
#define JSONCONS_TPL_N_MEMBER_NAMED_TRAITS JSONCONS_TPL_N_MEMBER_NAME_TRAITS
#define JSONCONS_ALL_MEMBER_NAMED_TRAITS JSONCONS_ALL_MEMBER_NAME_TRAITS
#define JSONCONS_TPL_ALL_MEMBER_NAMED_TRAITS JSONCONS_TPL_ALL_MEMBER_NAME_TRAITS
#define JSONCONS_ALL_GETTER_CTOR_NAMED_TRAITS JSONCONS_ALL_GETTER_CTOR_NAME_TRAITS
#define JSONCONS_TPL_ALL_GETTER_CTOR_NAMED_TRAITS JSONCONS_TPL_ALL_GETTER_CTOR_NAME_TRAITS
#define JSONCONS_N_GETTER_CTOR_NAMED_TRAITS JSONCONS_N_GETTER_CTOR_NAME_TRAITS
#define JSONCONS_TPL_N_GETTER_CTOR_NAMED_TRAITS JSONCONS_TPL_N_GETTER_CTOR_NAME_TRAITS
#define JSONCONS_ENUM_NAMED_TRAITS JSONCONS_ENUM_NAME_TRAITS
#define JSONCONS_N_GETTER_SETTER_NAMED_TRAITS JSONCONS_N_GETTER_SETTER_NAME_TRAITS
#define JSONCONS_TPL_N_GETTER_SETTER_NAMED_TRAITS JSONCONS_TPL_N_GETTER_SETTER_NAME_TRAITS
#define JSONCONS_ALL_GETTER_SETTER_NAMED_TRAITS JSONCONS_ALL_GETTER_SETTER_NAME_TRAITS
#define JSONCONS_TPL_ALL_GETTER_SETTER_NAMED_TRAITS JSONCONS_TPL_ALL_GETTER_SETTER_NAME_TRAITS
#define JSONCONS_N_MEMBER_TRAITS_DECL JSONCONS_N_MEMBER_TRAITS
#define JSONCONS_TPL_N_MEMBER_TRAITS_DECL JSONCONS_TPL_N_MEMBER_TRAITS
#define JSONCONS_ALL_MEMBER_TRAITS_DECL JSONCONS_ALL_MEMBER_TRAITS
#define JSONCONS_TPL_ALL_MEMBER_TRAITS_DECL JSONCONS_TPL_ALL_MEMBER_TRAITS
#define JSONCONS_N_MEMBER_NAMED_TRAITS_DECL JSONCONS_N_MEMBER_NAMED_TRAITS
#define JSONCONS_TPL_N_MEMBER_NAMED_TRAITS_DECL JSONCONS_TPL_N_MEMBER_NAMED_TRAITS
#define JSONCONS_ALL_MEMBER_NAMED_TRAITS_DECL JSONCONS_ALL_MEMBER_NAMED_TRAITS
#define JSONCONS_TPL_ALL_MEMBER_NAMED_TRAITS_DECL JSONCONS_TPL_ALL_MEMBER_NAMED_TRAITS
#define JSONCONS_ALL_GETTER_CTOR_TRAITS_DECL JSONCONS_ALL_GETTER_CTOR_TRAITS
#define JSONCONS_TPL_ALL_GETTER_CTOR_TRAITS_DECL JSONCONS_TPL_ALL_GETTER_CTOR_TRAITS
#define JSONCONS_N_GETTER_CTOR_TRAITS_DECL JSONCONS_N_GETTER_CTOR_TRAITS
#define JSONCONS_N_ALL_GETTER_CTOR_TRAITS_DECL JSONCONS_N_ALL_GETTER_CTOR_TRAITS
#define JSONCONS_ALL_GETTER_CTOR_NAMED_TRAITS_DECL JSONCONS_ALL_GETTER_CTOR_NAMED_TRAITS
#define JSONCONS_TPL_ALL_GETTER_CTOR_NAMED_TRAITS_DECL JSONCONS_TPL_ALL_GETTER_CTOR_NAMED_TRAITS
#define JSONCONS_N_GETTER_CTOR_NAMED_TRAITS_DECL JSONCONS_N_GETTER_CTOR_NAMED_TRAITS
#define JSONCONS_TPL_N_GETTER_CTOR_NAMED_TRAITS_DECL JSONCONS_TPL_N_GETTER_CTOR_NAMED_TRAITS
#define JSONCONS_ENUM_TRAITS_DECL JSONCONS_ENUM_TRAITS
#define JSONCONS_ENUM_NAMED_TRAITS_DECL JSONCONS_ENUM_NAMED_TRAITS
#define JSONCONS_N_GETTER_SETTER_TRAITS_DECL JSONCONS_N_GETTER_SETTER_TRAITS
#define JSONCONS_TPL_N_GETTER_SETTER_TRAITS_DECL JSONCONS_TPL_N_GETTER_SETTER_TRAITS
#define JSONCONS_ALL_GETTER_SETTER_TRAITS_DECL JSONCONS_ALL_GETTER_SETTER_TRAITS
#define JSONCONS_TPL_ALL_GETTER_SETTER_TRAITS_DECL JSONCONS_TPL_ALL_GETTER_SETTER_TRAITS
#define JSONCONS_N_GETTER_SETTER_NAMED_TRAITS_DECL JSONCONS_N_GETTER_SETTER_NAMED_TRAITS
#define JSONCONS_TPL_N_GETTER_SETTER_NAMED_TRAITS_DECL JSONCONS_TPL_N_GETTER_SETTER_NAMED_TRAITS
#define JSONCONS_ALL_GETTER_SETTER_NAMED_TRAITS_DECL JSONCONS_ALL_GETTER_SETTER_NAMED_TRAITS
#define JSONCONS_TPL_ALL_GETTER_SETTER_NAMED_TRAITS_DECL JSONCONS_TPL_ALL_GETTER_SETTER_NAMED_TRAITS
#define JSONCONS_POLYMORPHIC_TRAITS_DECL JSONCONS_POLYMORPHIC_TRAITS
#define JSONCONS_NONDEFAULT_MEMBER_TRAITS_DECL JSONCONS_ALL_MEMBER_TRAITS
#define JSONCONS_TEMPLATE_STRICT_MEMBER_TRAITS_DECL JSONCONS_TPL_ALL_MEMBER_TRAITS
#define JSONCONS_STRICT_MEMBER_TRAITS_NAMED_DECL JSONCONS_ALL_MEMBER_NAME_TRAITS
#define JSONCONS_STRICT_TEMPLATE_MEMBER_TRAITS_DECL JSONCONS_TPL_ALL_MEMBER_TRAITS
#define JSONCONS_STRICT_TEMPLATE_MEMBER_TRAITS_NAMED_DECL JSONCONS_TPL_ALL_MEMBER_NAME_TRAITS
#define JSONCONS_ENUM_TRAITS_NAMED_DECL JSONCONS_ENUM_NAME_TRAITS
#define JSONCONS_GETTER_CTOR_TRAITS_NAMED_DECL JSONCONS_ALL_GETTER_CTOR_NAME_TRAITS
#define JSONCONS_TEMPLATE_GETTER_CTOR_TRAITS_DECL JSONCONS_TPL_ALL_GETTER_CTOR_TRAITS
#define JSONCONS_TEMPLATE_GETTER_CTOR_TRAITS_NAMED_DECL JSONCONS_TPL_ALL_GETTER_CTOR_NAME_TRAITS
#define JSONCONS_GETTER_SETTER_TRAITS_NAMED_DECL JSONCONS_ALL_GETTER_SETTER_NAME_TRAITS
#define JSONCONS_STRICT_GETTER_SETTER_TRAITS_NAMED_DECL JSONCONS_ALL_GETTER_SETTER_NAME_TRAITS
#define JSONCONS_STRICT_TEMPLATE_GETTER_SETTER_TRAITS_NAMED_DECL JSONCONS_TPL_ALL_GETTER_SETTER_NAME_TRAITS
#define JSONCONS_STRICT_TPL_MEMBER_TRAITS_DECL JSONCONS_TPL_ALL_MEMBER_TRAITS
#define JSONCONS_STRICT_TPL_MEMBER_NAMED_TRAITS_DECL JSONCONS_TPL_ALL_MEMBER_NAME_TRAITS
#define JSONCONS_STRICT_TPL_GETTER_SETTER_NAMED_TRAITS_DECL JSONCONS_TPL_ALL_GETTER_SETTER_NAME_TRAITS
#define JSONCONS_STRICT_MEMBER_TRAITS_DECL JSONCONS_ALL_MEMBER_TRAITS
#define JSONCONS_TPL_STRICT_MEMBER_TRAITS_DECL JSONCONS_TPL_ALL_MEMBER_TRAITS
#define JSONCONS_STRICT_MEMBER_NAMED_TRAITS_DECL JSONCONS_ALL_MEMBER_NAME_TRAITS
#define JSONCONS_TPL_STRICT_MEMBER_NAMED_TRAITS_DECL JSONCONS_ALL_STRICT_MEMBER_NAME_TRAITS
#define JSONCONS_STRICT_PROPERTY_TRAITS_DECL JSONCONS_ALL_GETTER_SETTER_TRAITS
#define JSONCONS_TPL_STRICT_PROPERTY_TRAITS_DECL JSONCONS_TPL_ALL_GETTER_SETTER_TRAITS
#define JSONCONS_STRICT_GETTER_SETTER_NAMED_TRAITS_DECL JSONCONS_ALL_GETTER_SETTER_NAME_TRAITS
#define JSONCONS_TPL_STRICT_GETTER_SETTER_NAMED_TRAITS_DECL JSONCONS_TPL_ALL_GETTER_SETTER_NAME_TRAITS
#define JSONCONS_GETTER_CTOR_TRAITS_DECL JSONCONS_ALL_GETTER_CTOR_TRAITS
#define JSONCONS_TPL_GETTER_CTOR_TRAITS_DECL JSONCONS_TPL_ALL_GETTER_CTOR_TRAITS
#define JSONCONS_GETTER_CTOR_NAMED_TRAITS_DECL JSONCONS_ALL_GETTER_CTOR_NAME_TRAITS
#define JSONCONS_TPL_GETTER_CTOR_NAMED_TRAITS_DECL JSONCONS_TPL_ALL_GETTER_CTOR_NAME_TRAITS
#define JSONCONS_N_PROPERTY_TRAITS_DECL JSONCONS_N_GETTER_SETTER_TRAITS
#define JSONCONS_ALL_PROPERTY_TRAITS_DECL JSONCONS_ALL_GETTER_SETTER_TRAITS
#define JSONCONS_TPL_N_PROPERTY_TRAITS_DECL JSONCONS_TPL_N_GETTER_SETTER_TRAITS
#define JSONCONS_TPL_ALL_PROPERTY_TRAITS_DECL JSONCONS_TPL_ALL_GETTER_SETTER_TRAITS
#endif
#endif

View file

@ -0,0 +1,206 @@
// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_JSON_TYPE_HPP
#define JSONCONS_JSON_TYPE_HPP
#include <ostream>
#include <jsoncons/config/jsoncons_config.hpp>
namespace jsoncons {
enum class json_type : uint8_t
{
null_value,
bool_value,
int64_value,
uint64_value,
half_value,
double_value,
string_value,
byte_string_value,
array_value,
object_value
};
template <class CharT>
std::basic_ostream<CharT>& operator<<(std::basic_ostream<CharT>& os, json_type type)
{
static constexpr const CharT* null_value = JSONCONS_CSTRING_CONSTANT(CharT, "null");
static constexpr const CharT* bool_value = JSONCONS_CSTRING_CONSTANT(CharT, "bool");
static constexpr const CharT* int64_value = JSONCONS_CSTRING_CONSTANT(CharT, "int64");
static constexpr const CharT* uint64_value = JSONCONS_CSTRING_CONSTANT(CharT, "uint64");
static constexpr const CharT* half_value = JSONCONS_CSTRING_CONSTANT(CharT, "half");
static constexpr const CharT* double_value = JSONCONS_CSTRING_CONSTANT(CharT, "double");
static constexpr const CharT* string_value = JSONCONS_CSTRING_CONSTANT(CharT, "string");
static constexpr const CharT* byte_string_value = JSONCONS_CSTRING_CONSTANT(CharT, "byte_string");
static constexpr const CharT* array_value = JSONCONS_CSTRING_CONSTANT(CharT, "array");
static constexpr const CharT* object_value = JSONCONS_CSTRING_CONSTANT(CharT, "object");
switch (type)
{
case json_type::null_value:
{
os << null_value;
break;
}
case json_type::bool_value:
{
os << bool_value;
break;
}
case json_type::int64_value:
{
os << int64_value;
break;
}
case json_type::uint64_value:
{
os << uint64_value;
break;
}
case json_type::half_value:
{
os << half_value;
break;
}
case json_type::double_value:
{
os << double_value;
break;
}
case json_type::string_value:
{
os << string_value;
break;
}
case json_type::byte_string_value:
{
os << byte_string_value;
break;
}
case json_type::array_value:
{
os << array_value;
break;
}
case json_type::object_value:
{
os << object_value;
break;
}
}
return os;
}
enum class json_storage_kind : uint8_t
{
null_value = 0x00,
bool_value = 0x01,
int64_value = 0x02,
uint64_value = 0x03,
half_value = 0x04,
double_value = 0x05,
short_string_value = 0x06,
long_string_value = 0x07,
byte_string_value = 0x08,
array_value = 0x09,
empty_object_value = 0x0a,
object_value = 0x0b,
json_const_pointer = 0x0c
};
template <class CharT>
std::basic_ostream<CharT>& operator<<(std::basic_ostream<CharT>& os, json_storage_kind storage)
{
static constexpr const CharT* null_value = JSONCONS_CSTRING_CONSTANT(CharT, "null");
static constexpr const CharT* bool_value = JSONCONS_CSTRING_CONSTANT(CharT, "bool");
static constexpr const CharT* int64_value = JSONCONS_CSTRING_CONSTANT(CharT, "int64");
static constexpr const CharT* uint64_value = JSONCONS_CSTRING_CONSTANT(CharT, "uint64");
static constexpr const CharT* half_value = JSONCONS_CSTRING_CONSTANT(CharT, "half");
static constexpr const CharT* double_value = JSONCONS_CSTRING_CONSTANT(CharT, "double");
static constexpr const CharT* short_string_value = JSONCONS_CSTRING_CONSTANT(CharT, "short_string");
static constexpr const CharT* long_string_value = JSONCONS_CSTRING_CONSTANT(CharT, "string");
static constexpr const CharT* byte_string_value = JSONCONS_CSTRING_CONSTANT(CharT, "byte_string");
static constexpr const CharT* array_value = JSONCONS_CSTRING_CONSTANT(CharT, "array");
static constexpr const CharT* empty_object_value = JSONCONS_CSTRING_CONSTANT(CharT, "empty_object");
static constexpr const CharT* object_value = JSONCONS_CSTRING_CONSTANT(CharT, "object");
static constexpr const CharT* json_const_pointer = JSONCONS_CSTRING_CONSTANT(CharT, "json_const_pointer");
switch (storage)
{
case json_storage_kind::null_value:
{
os << null_value;
break;
}
case json_storage_kind::bool_value:
{
os << bool_value;
break;
}
case json_storage_kind::int64_value:
{
os << int64_value;
break;
}
case json_storage_kind::uint64_value:
{
os << uint64_value;
break;
}
case json_storage_kind::half_value:
{
os << half_value;
break;
}
case json_storage_kind::double_value:
{
os << double_value;
break;
}
case json_storage_kind::short_string_value:
{
os << short_string_value;
break;
}
case json_storage_kind::long_string_value:
{
os << long_string_value;
break;
}
case json_storage_kind::byte_string_value:
{
os << byte_string_value;
break;
}
case json_storage_kind::array_value:
{
os << array_value;
break;
}
case json_storage_kind::empty_object_value:
{
os << empty_object_value;
break;
}
case json_storage_kind::object_value:
{
os << object_value;
break;
}
case json_storage_kind::json_const_pointer:
{
os << json_const_pointer;
break;
}
}
return os;
}
} // jsoncons
#endif

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,89 @@
// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_PRETTY_PRINT_HPP
#define JSONCONS_PRETTY_PRINT_HPP
#include <string>
#include <exception>
#include <cstring>
#include <ostream>
#include <memory>
#include <typeinfo>
#include <cstring>
#include <jsoncons/json_exception.hpp>
#include <jsoncons/json_options.hpp>
#include <jsoncons/json_encoder.hpp>
#include <jsoncons/json_type_traits.hpp>
#include <jsoncons/json_error.hpp>
namespace jsoncons {
template<class Json>
class json_printable
{
public:
using char_type = typename Json::char_type;
json_printable(const Json& j, indenting line_indent)
: j_(&j), indenting_(line_indent)
{
}
json_printable(const Json& j,
const basic_json_encode_options<char_type>& options,
indenting line_indent)
: j_(&j), options_(options), indenting_(line_indent)
{
}
void dump(std::basic_ostream<char_type>& os) const
{
j_->dump(os, options_, indenting_);
}
friend std::basic_ostream<char_type>& operator<<(std::basic_ostream<char_type>& os, const json_printable<Json>& pr)
{
pr.dump(os);
return os;
}
const Json *j_;
basic_json_encode_options<char_type> options_;
indenting indenting_;
private:
json_printable();
};
template<class Json>
json_printable<Json> print(const Json& j)
{
return json_printable<Json>(j, indenting::no_indent);
}
template<class Json>
json_printable<Json> print(const Json& j,
const basic_json_encode_options<typename Json::char_type>& options)
{
return json_printable<Json>(j, options, indenting::no_indent);
}
template<class Json>
json_printable<Json> pretty_print(const Json& j)
{
return json_printable<Json>(j, indenting::indent);
}
template<class Json>
json_printable<Json> pretty_print(const Json& j,
const basic_json_encode_options<typename Json::char_type>& options)
{
return json_printable<Json>(j, options, indenting::indent);
}
}
#endif

View file

@ -0,0 +1,62 @@
/// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_SER_CONTEXT_HPP
#define JSONCONS_SER_CONTEXT_HPP
namespace jsoncons {
class ser_context
{
public:
virtual ~ser_context() noexcept = default;
virtual size_t line() const
{
return 0;
}
virtual size_t column() const
{
return 0;
}
virtual size_t position() const
{
return 0;
}
virtual size_t end_position() const
{
return 0;
}
#if !defined(JSONCONS_NO_DEPRECATED)
JSONCONS_DEPRECATED_MSG("Instead, use line()")
std::size_t line_number() const
{
return line();
}
JSONCONS_DEPRECATED_MSG("Instead, use column()")
std::size_t column_number() const
{
return column();
}
#endif
};
#if !defined(JSONCONS_NO_DEPRECATED)
JSONCONS_DEPRECATED_MSG("Instead, use ser_context") typedef ser_context null_ser_context;
JSONCONS_DEPRECATED_MSG("Instead, use ser_context") typedef ser_context parsing_context;
JSONCONS_DEPRECATED_MSG("Instead, use ser_context") typedef ser_context serializing_context;
JSONCONS_DEPRECATED_MSG("Instead, use ser_context") typedef ser_context null_parsing_context;
JSONCONS_DEPRECATED_MSG("Instead, use ser_context") typedef ser_context null_serializing_context;
#endif
}
#endif

View file

@ -0,0 +1,289 @@
// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_SINK_HPP
#define JSONCONS_SINK_HPP
#include <stdexcept>
#include <string>
#include <vector>
#include <ostream>
#include <cmath>
#include <exception>
#include <memory> // std::addressof
#include <cstring> // std::memcpy
#include <jsoncons/config/jsoncons_config.hpp>
#include <jsoncons/extension_traits.hpp>
namespace jsoncons {
// stream_sink
template <class CharT>
class stream_sink
{
public:
using value_type = CharT;
using container_type = std::basic_ostream<CharT>;
private:
static constexpr size_t default_buffer_length = 16384;
std::basic_ostream<CharT>* stream_ptr_;
std::vector<CharT> buffer_;
CharT * begin_buffer_;
const CharT* end_buffer_;
CharT* p_;
// Noncopyable
stream_sink(const stream_sink&) = delete;
stream_sink& operator=(const stream_sink&) = delete;
public:
stream_sink(stream_sink&&) = default;
stream_sink(std::basic_ostream<CharT>& os)
: stream_ptr_(std::addressof(os)), buffer_(default_buffer_length), begin_buffer_(buffer_.data()), end_buffer_(begin_buffer_+buffer_.size()), p_(begin_buffer_)
{
}
stream_sink(std::basic_ostream<CharT>& os, std::size_t buflen)
: stream_ptr_(std::addressof(os)), buffer_(buflen), begin_buffer_(buffer_.data()), end_buffer_(begin_buffer_+buffer_.size()), p_(begin_buffer_)
{
}
~stream_sink() noexcept
{
stream_ptr_->write(begin_buffer_, buffer_length());
stream_ptr_->flush();
}
// Movable
stream_sink& operator=(stream_sink&&) = default;
void flush()
{
stream_ptr_->write(begin_buffer_, buffer_length());
stream_ptr_->flush();
p_ = buffer_.data();
}
void append(const CharT* s, std::size_t length)
{
std::size_t diff = end_buffer_ - p_;
if (diff >= length)
{
std::memcpy(p_, s, length*sizeof(CharT));
p_ += length;
}
else
{
stream_ptr_->write(begin_buffer_, buffer_length());
stream_ptr_->write(s,length);
p_ = begin_buffer_;
}
}
void push_back(CharT ch)
{
if (p_ < end_buffer_)
{
*p_++ = ch;
}
else
{
stream_ptr_->write(begin_buffer_, buffer_length());
p_ = begin_buffer_;
push_back(ch);
}
}
private:
std::size_t buffer_length() const
{
return p_ - begin_buffer_;
}
};
// binary_stream_sink
class binary_stream_sink
{
public:
typedef uint8_t value_type;
using container_type = std::basic_ostream<char>;
private:
static constexpr size_t default_buffer_length = 16384;
std::basic_ostream<char>* stream_ptr_;
std::vector<uint8_t> buffer_;
uint8_t * begin_buffer_;
const uint8_t* end_buffer_;
uint8_t* p_;
// Noncopyable
binary_stream_sink(const binary_stream_sink&) = delete;
binary_stream_sink& operator=(const binary_stream_sink&) = delete;
public:
binary_stream_sink(binary_stream_sink&&) = default;
binary_stream_sink(std::basic_ostream<char>& os)
: stream_ptr_(std::addressof(os)),
buffer_(default_buffer_length),
begin_buffer_(buffer_.data()),
end_buffer_(begin_buffer_+buffer_.size()),
p_(begin_buffer_)
{
}
binary_stream_sink(std::basic_ostream<char>& os, std::size_t buflen)
: stream_ptr_(std::addressof(os)),
buffer_(buflen),
begin_buffer_(buffer_.data()),
end_buffer_(begin_buffer_+buffer_.size()),
p_(begin_buffer_)
{
}
~binary_stream_sink() noexcept
{
stream_ptr_->write((char*)begin_buffer_, buffer_length());
stream_ptr_->flush();
}
binary_stream_sink& operator=(binary_stream_sink&&) = default;
void flush()
{
stream_ptr_->write((char*)begin_buffer_, buffer_length());
p_ = buffer_.data();
}
void append(const uint8_t* s, std::size_t length)
{
std::size_t diff = end_buffer_ - p_;
if (diff >= length)
{
std::memcpy(p_, s, length*sizeof(uint8_t));
p_ += length;
}
else
{
stream_ptr_->write((char*)begin_buffer_, buffer_length());
stream_ptr_->write((const char*)s,length);
p_ = begin_buffer_;
}
}
void push_back(uint8_t ch)
{
if (p_ < end_buffer_)
{
*p_++ = ch;
}
else
{
stream_ptr_->write((char*)begin_buffer_, buffer_length());
p_ = begin_buffer_;
push_back(ch);
}
}
private:
std::size_t buffer_length() const
{
return p_ - begin_buffer_;
}
};
// string_sink
template <class StringT>
class string_sink
{
public:
using value_type = typename StringT::value_type;
using container_type = StringT;
private:
container_type* buf_ptr;
// Noncopyable
string_sink(const string_sink&) = delete;
string_sink& operator=(const string_sink&) = delete;
public:
string_sink(string_sink&& val) noexcept
: buf_ptr(nullptr)
{
std::swap(buf_ptr,val.buf_ptr);
}
string_sink(container_type& buf)
: buf_ptr(std::addressof(buf))
{
}
string_sink& operator=(string_sink&& val) noexcept
{
// TODO: Shouldn't val.buf_ptr be nullified?
// Also see move constructor above.
std::swap(buf_ptr,val.buf_ptr);
return *this;
}
void flush()
{
}
void append(const value_type* s, std::size_t length)
{
buf_ptr->insert(buf_ptr->end(), s, s+length);
}
void push_back(value_type ch)
{
buf_ptr->push_back(ch);
}
};
// bytes_sink
template <class Container, class = void>
class bytes_sink
{
};
template <class Container>
class bytes_sink<Container,typename std::enable_if<extension_traits::is_back_insertable_byte_container<Container>::value>::type>
{
public:
using container_type = Container;
using value_type = typename Container::value_type;
private:
container_type* buf_ptr;
// Noncopyable
bytes_sink(const bytes_sink&) = delete;
bytes_sink& operator=(const bytes_sink&) = delete;
public:
bytes_sink(bytes_sink&&) = default;
bytes_sink(container_type& buf)
: buf_ptr(std::addressof(buf))
{
}
bytes_sink& operator=(bytes_sink&&) = default;
void flush()
{
}
void push_back(uint8_t ch)
{
buf_ptr->push_back(static_cast<value_type>(ch));
}
};
} // namespace jsoncons
#endif

View file

@ -0,0 +1,793 @@
// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_SOURCE_HPP
#define JSONCONS_SOURCE_HPP
#include <stdexcept>
#include <string>
#include <vector>
#include <istream>
#include <memory> // std::addressof
#include <cstring> // std::memcpy
#include <exception>
#include <iterator>
#include <type_traits> // std::enable_if
#include <jsoncons/config/jsoncons_config.hpp>
#include <jsoncons/byte_string.hpp> // jsoncons::byte_traits
#include <jsoncons/extension_traits.hpp>
namespace jsoncons {
template <class CharT>
class basic_null_istream : public std::basic_istream<CharT>
{
class null_buffer : public std::basic_streambuf<CharT>
{
null_buffer(const null_buffer&) = delete;
null_buffer& operator=(const null_buffer&) = delete;
public:
using typename std::basic_streambuf<CharT>::int_type;
using typename std::basic_streambuf<CharT>::traits_type;
null_buffer() = default;
null_buffer(null_buffer&&) = default;
null_buffer& operator=(null_buffer&&) = default;
int_type overflow( int_type ch = typename std::basic_streambuf<CharT>::traits_type::eof() ) override
{
return ch;
}
} nb_;
public:
basic_null_istream()
: std::basic_istream<CharT>(&nb_)
{
}
basic_null_istream(const null_buffer&) = delete;
basic_null_istream& operator=(const null_buffer&) = delete;
basic_null_istream(basic_null_istream&&) noexcept
: std::basic_istream<CharT>(&nb_)
{
}
basic_null_istream& operator=(basic_null_istream&&) noexcept
{
return *this;
}
};
template <class CharT>
struct char_result
{
CharT value;
bool eof;
};
// text sources
template <class CharT>
class stream_source
{
static constexpr std::size_t default_max_buffer_size = 16384;
public:
using value_type = CharT;
private:
using char_type = typename std::conditional<sizeof(CharT) == sizeof(char),char,CharT>::type;
basic_null_istream<char_type> null_is_;
std::basic_istream<char_type>* stream_ptr_;
std::basic_streambuf<char_type>* sbuf_;
std::size_t position_;
std::vector<value_type> buffer_;
const value_type* buffer_data_;
std::size_t buffer_length_;
// Noncopyable
stream_source(const stream_source&) = delete;
stream_source& operator=(const stream_source&) = delete;
public:
stream_source()
: stream_ptr_(&null_is_), sbuf_(null_is_.rdbuf()), position_(0),
buffer_(1), buffer_data_(buffer_.data()), buffer_length_(0)
{
}
stream_source(std::basic_istream<char_type>& is, std::size_t buf_size = default_max_buffer_size)
: stream_ptr_(std::addressof(is)), sbuf_(is.rdbuf()), position_(0),
buffer_(buf_size), buffer_data_(buffer_.data()), buffer_length_(0)
{
}
stream_source(stream_source&& other) noexcept
: stream_ptr_(&null_is_), sbuf_(null_is_.rdbuf()), position_(0),
buffer_(), buffer_data_(buffer_.data()), buffer_length_(0)
{
if (other.stream_ptr_ != &other.null_is_)
{
stream_ptr_ = other.stream_ptr_;
sbuf_ = other.sbuf_;
position_ = other.position_;
buffer_ = std::move(other.buffer_);
buffer_data_ = buffer_.data() + (other.buffer_data_ - other.buffer_.data());
buffer_length_ = other.buffer_length_;
other = stream_source();
}
}
~stream_source()
{
}
stream_source& operator=(stream_source&& other) noexcept
{
if (other.stream_ptr_ != &other.null_is_)
{
stream_ptr_ = other.stream_ptr_;
sbuf_ = other.sbuf_;
position_ = other.position_;
buffer_ = std::move(other.buffer_);
buffer_data_ = buffer_.data() + (other.buffer_data_ - other.buffer_.data());
buffer_length_ = other.buffer_length_;
other = stream_source();
}
else
{
stream_ptr_ = &null_is_;
sbuf_ = null_is_.rdbuf();
position_ = 0;
buffer_data_ = buffer_.data();
buffer_length_ = 0;
}
return *this;
}
bool eof() const
{
return buffer_length_ == 0 && stream_ptr_->eof();
}
bool is_error() const
{
return stream_ptr_->bad();
}
std::size_t position() const
{
return position_;
}
void ignore(std::size_t length)
{
std::size_t len = 0;
if (buffer_length_ > 0)
{
len = (std::min)(buffer_length_, length);
position_ += len;
buffer_data_ += len;
buffer_length_ -= len;
}
while (len < length)
{
fill_buffer();
if (buffer_length_ == 0)
{
break;
}
std::size_t len2 = (std::min)(buffer_length_, length-len);
position_ += len2;
buffer_data_ += len2;
buffer_length_ -= len2;
len += len2;
}
}
char_result<value_type> peek()
{
if (buffer_length_ == 0)
{
fill_buffer();
}
if (buffer_length_ > 0)
{
value_type c = *buffer_data_;
return char_result<value_type>{c, false};
}
else
{
return char_result<value_type>{0, true};
}
}
span<const value_type> read_buffer()
{
if (buffer_length_ == 0)
{
fill_buffer();
}
const value_type* data = buffer_data_;
std::size_t length = buffer_length_;
buffer_data_ += buffer_length_;
position_ += buffer_length_;
buffer_length_ = 0;
return span<const value_type>(data, length);
}
std::size_t read(value_type* p, std::size_t length)
{
std::size_t len = 0;
if (buffer_length_ > 0)
{
len = (std::min)(buffer_length_, length);
std::memcpy(p, buffer_data_, len*sizeof(value_type));
buffer_data_ += len;
buffer_length_ -= len;
position_ += len;
}
if (length - len == 0)
{
return len;
}
else if (length - len < buffer_.size())
{
fill_buffer();
if (buffer_length_ > 0)
{
std::size_t len2 = (std::min)(buffer_length_, length-len);
std::memcpy(p+len, buffer_data_, len2*sizeof(value_type));
buffer_data_ += len2;
buffer_length_ -= len2;
position_ += len2;
len += len2;
}
return len;
}
else
{
if (stream_ptr_->eof())
{
buffer_length_ = 0;
return 0;
}
JSONCONS_TRY
{
std::streamsize count = sbuf_->sgetn(reinterpret_cast<char_type*>(p+len), length-len);
std::size_t len2 = static_cast<std::size_t>(count);
if (len2 < length-len)
{
stream_ptr_->clear(stream_ptr_->rdstate() | std::ios::eofbit);
}
len += len2;
position_ += len2;
return len;
}
JSONCONS_CATCH(const std::exception&)
{
stream_ptr_->clear(stream_ptr_->rdstate() | std::ios::badbit | std::ios::eofbit);
return 0;
}
}
}
private:
void fill_buffer()
{
if (stream_ptr_->eof())
{
buffer_length_ = 0;
return;
}
buffer_data_ = buffer_.data();
JSONCONS_TRY
{
std::streamsize count = sbuf_->sgetn(reinterpret_cast<char_type*>(buffer_.data()), buffer_.size());
buffer_length_ = static_cast<std::size_t>(count);
if (buffer_length_ < buffer_.size())
{
stream_ptr_->clear(stream_ptr_->rdstate() | std::ios::eofbit);
}
}
JSONCONS_CATCH(const std::exception&)
{
stream_ptr_->clear(stream_ptr_->rdstate() | std::ios::badbit | std::ios::eofbit);
buffer_length_ = 0;
}
}
};
// string_source
template <class CharT>
class string_source
{
public:
using value_type = CharT;
using string_view_type = jsoncons::basic_string_view<value_type>;
private:
const value_type* data_;
const value_type* current_;
const value_type* end_;
// Noncopyable
string_source(const string_source&) = delete;
string_source& operator=(const string_source&) = delete;
public:
string_source()
: data_(nullptr), current_(nullptr), end_(nullptr)
{
}
template <class Sourceable>
string_source(const Sourceable& s,
typename std::enable_if<extension_traits::is_sequence_of<Sourceable,value_type>::value>::type* = 0)
: data_(s.data()), current_(s.data()), end_(s.data()+s.size())
{
}
string_source(const value_type* data)
: data_(data), current_(data), end_(data+std::char_traits<value_type>::length(data))
{
}
string_source(string_source&& val) = default;
string_source& operator=(string_source&& val) = default;
bool eof() const
{
return current_ == end_;
}
bool is_error() const
{
return false;
}
std::size_t position() const
{
return (current_ - data_)/sizeof(value_type);
}
void ignore(std::size_t count)
{
std::size_t len;
if ((std::size_t)(end_ - current_) < count)
{
len = end_ - current_;
}
else
{
len = count;
}
current_ += len;
}
char_result<value_type> peek()
{
return current_ < end_ ? char_result<value_type>{*current_, false} : char_result<value_type>{0, true};
}
span<const value_type> read_buffer()
{
const value_type* data = current_;
std::size_t length = end_ - current_;
current_ = end_;
return span<const value_type>(data, length);
}
std::size_t read(value_type* p, std::size_t length)
{
std::size_t len;
if ((std::size_t)(end_ - current_) < length)
{
len = end_ - current_;
}
else
{
len = length;
}
std::memcpy(p, current_, len*sizeof(value_type));
current_ += len;
return len;
}
};
// iterator source
template <class IteratorT>
class iterator_source
{
public:
using value_type = typename std::iterator_traits<IteratorT>::value_type;
private:
static constexpr std::size_t default_max_buffer_size = 16384;
IteratorT current_;
IteratorT end_;
std::size_t position_;
std::vector<value_type> buffer_;
std::size_t buffer_length_;
using difference_type = typename std::iterator_traits<IteratorT>::difference_type;
using iterator_category = typename std::iterator_traits<IteratorT>::iterator_category;
// Noncopyable
iterator_source(const iterator_source&) = delete;
iterator_source& operator=(const iterator_source&) = delete;
public:
iterator_source(const IteratorT& first, const IteratorT& last, std::size_t buf_size = default_max_buffer_size)
: current_(first), end_(last), position_(0), buffer_(buf_size), buffer_length_(0)
{
}
iterator_source(iterator_source&& other) = default;
iterator_source& operator=(iterator_source&& other) = default;
bool eof() const
{
return !(current_ != end_);
}
bool is_error() const
{
return false;
}
std::size_t position() const
{
return position_;
}
void ignore(std::size_t count)
{
while (count-- > 0 && current_ != end_)
{
++position_;
++current_;
}
}
char_result<value_type> peek()
{
return current_ != end_ ? char_result<value_type>{*current_, false} : char_result<value_type>{0, true};
}
span<const value_type> read_buffer()
{
if (buffer_length_ == 0)
{
buffer_length_ = read(buffer_.data(), buffer_.size());
}
std::size_t length = buffer_length_;
buffer_length_ = 0;
return span<const value_type>(buffer_.data(), length);
}
template <class Category = iterator_category>
typename std::enable_if<std::is_same<Category,std::random_access_iterator_tag>::value, std::size_t>::type
read(value_type* data, std::size_t length)
{
std::size_t count = (std::min)(length, static_cast<std::size_t>(std::distance(current_, end_)));
//JSONCONS_COPY(current_, current_ + count, data);
auto end = current_ + count;
value_type* p = data;
while (current_ != end)
{
*p++ = *current_++;
}
//current_ += count;
position_ += count;
return count;
}
template <class Category = iterator_category>
typename std::enable_if<!std::is_same<Category,std::random_access_iterator_tag>::value, std::size_t>::type
read(value_type* data, std::size_t length)
{
value_type* p = data;
value_type* pend = data + length;
while (p < pend && current_ != end_)
{
*p = static_cast<value_type>(*current_);
++p;
++current_;
}
position_ += (p - data);
return p - data;
}
};
// binary sources
using binary_stream_source = stream_source<uint8_t>;
class bytes_source
{
public:
typedef uint8_t value_type;
private:
const value_type* data_;
const value_type* current_;
const value_type* end_;
// Noncopyable
bytes_source(const bytes_source&) = delete;
bytes_source& operator=(const bytes_source&) = delete;
public:
bytes_source()
: data_(nullptr), current_(nullptr), end_(nullptr)
{
}
template <class Sourceable>
bytes_source(const Sourceable& source,
typename std::enable_if<extension_traits::is_byte_sequence<Sourceable>::value,int>::type = 0)
: data_(reinterpret_cast<const value_type*>(source.data())),
current_(data_),
end_(data_+source.size())
{
}
bytes_source(bytes_source&&) = default;
bytes_source& operator=(bytes_source&&) = default;
bool eof() const
{
return current_ == end_;
}
bool is_error() const
{
return false;
}
std::size_t position() const
{
return current_ - data_;
}
void ignore(std::size_t count)
{
std::size_t len;
if ((std::size_t)(end_ - current_) < count)
{
len = end_ - current_;
}
else
{
len = count;
}
current_ += len;
}
char_result<value_type> peek()
{
return current_ < end_ ? char_result<value_type>{*current_, false} : char_result<value_type>{0, true};
}
span<const value_type> read_buffer()
{
const value_type* data = current_;
std::size_t length = end_ - current_;
current_ = end_;
return span<const value_type>(data, length);
}
std::size_t read(value_type* p, std::size_t length)
{
std::size_t len;
if ((std::size_t)(end_ - current_) < length)
{
len = end_ - current_;
}
else
{
len = length;
}
std::memcpy(p, current_, len*sizeof(value_type));
current_ += len;
return len;
}
};
// binary_iterator source
template <class IteratorT>
class binary_iterator_source
{
public:
using value_type = uint8_t;
private:
static constexpr std::size_t default_max_buffer_size = 16384;
IteratorT current_;
IteratorT end_;
std::size_t position_;
std::vector<value_type> buffer_;
std::size_t buffer_length_;
using difference_type = typename std::iterator_traits<IteratorT>::difference_type;
using iterator_category = typename std::iterator_traits<IteratorT>::iterator_category;
// Noncopyable
binary_iterator_source(const binary_iterator_source&) = delete;
binary_iterator_source& operator=(const binary_iterator_source&) = delete;
public:
binary_iterator_source(const IteratorT& first, const IteratorT& last, std::size_t buf_size = default_max_buffer_size)
: current_(first), end_(last), position_(0), buffer_(buf_size), buffer_length_(0)
{
}
binary_iterator_source(binary_iterator_source&& other) = default;
binary_iterator_source& operator=(binary_iterator_source&& other) = default;
bool eof() const
{
return !(current_ != end_);
}
bool is_error() const
{
return false;
}
std::size_t position() const
{
return position_;
}
void ignore(std::size_t count)
{
while (count-- > 0 && current_ != end_)
{
++position_;
++current_;
}
}
char_result<value_type> peek()
{
return current_ != end_ ? char_result<value_type>{static_cast<value_type>(*current_), false} : char_result<value_type>{0, true};
}
span<const value_type> read_buffer()
{
if (buffer_length_ == 0)
{
buffer_length_ = read(buffer_.data(), buffer_.size());
}
std::size_t length = buffer_length_;
buffer_length_ = 0;
return span<const value_type>(buffer_.data(), length);
}
template <class Category = iterator_category>
typename std::enable_if<std::is_same<Category,std::random_access_iterator_tag>::value, std::size_t>::type
read(value_type* data, std::size_t length)
{
std::size_t count = (std::min)(length, static_cast<std::size_t>(std::distance(current_, end_)));
//JSONCONS_COPY(current_, current_ + count, data);
auto end = current_ + count;
value_type* p = data;
while (current_ != end)
{
*p++ = *current_++;
}
//current_ += count;
position_ += count;
return count;
}
template <class Category = iterator_category>
typename std::enable_if<!std::is_same<Category,std::random_access_iterator_tag>::value, std::size_t>::type
read(value_type* data, std::size_t length)
{
value_type* p = data;
value_type* pend = data + length;
while (p < pend && current_ != end_)
{
*p = static_cast<value_type>(*current_);
++p;
++current_;
}
position_ += (p - data);
return p - data;
}
};
template <class Source>
struct source_reader
{
using value_type = typename Source::value_type;
static constexpr std::size_t max_buffer_length = 16384;
template <class Container>
static
typename std::enable_if<std::is_convertible<value_type,typename Container::value_type>::value &&
extension_traits::has_reserve<Container>::value &&
extension_traits::has_data_exact<value_type*,Container>::value
, std::size_t>::type
read(Source& source, Container& v, std::size_t length)
{
std::size_t unread = length;
std::size_t n = (std::min)(max_buffer_length, unread);
while (n > 0 && !source.eof())
{
std::size_t offset = v.size();
v.resize(v.size()+n);
std::size_t actual = source.read(v.data()+offset, n);
unread -= actual;
n = (std::min)(max_buffer_length, unread);
}
return length - unread;
}
template <class Container>
static
typename std::enable_if<std::is_convertible<value_type,typename Container::value_type>::value &&
extension_traits::has_reserve<Container>::value &&
!extension_traits::has_data_exact<value_type*, Container>::value
, std::size_t>::type
read(Source& source, Container& v, std::size_t length)
{
std::size_t unread = length;
std::size_t n = (std::min)(max_buffer_length, unread);
while (n > 0 && !source.eof())
{
v.reserve(v.size()+n);
std::size_t actual = 0;
while (actual < n)
{
typename Source::value_type c;
if (source.read(&c,1) != 1)
{
break;
}
v.push_back(c);
++actual;
}
unread -= actual;
n = (std::min)(max_buffer_length, unread);
}
return length - unread;
}
};
template <class Source>
constexpr std::size_t source_reader<Source>::max_buffer_length;
#if !defined(JSONCONS_NO_DEPRECATED)
using bin_stream_source = binary_stream_source;
#endif
} // namespace jsoncons
#endif

View file

@ -0,0 +1,148 @@
// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_BUFFER_READER_HPP
#define JSONCONS_BUFFER_READER_HPP
#include <cstddef>
#include <string>
#include <vector>
#include <stdexcept>
#include <system_error>
#include <memory> // std::allocator_traits
#include <vector> // std::vector
#include <jsoncons/unicode_traits.hpp>
#include <jsoncons/json_error.hpp> // json_errc
#include <jsoncons/source.hpp>
#include <jsoncons/json_exception.hpp>
namespace jsoncons {
// text_source_adaptor
template<class Source>
class text_source_adaptor
{
public:
using value_type = typename Source::value_type;
private:
Source source_;
bool bof_;
public:
text_source_adaptor()
: bof_(true)
{
}
template <class Sourceable>
text_source_adaptor(Sourceable&& source)
: source_(std::forward<Sourceable>(source)), bof_(true)
{
}
bool eof() const
{
return source_.eof();
}
bool is_error() const
{
return source_.is_error();
}
span<const value_type> read_buffer(std::error_code& ec)
{
if (source_.eof())
{
return span<const value_type>();
}
auto s = source_.read_buffer();
const value_type* data = s.data();
std::size_t length = s.size();
if (bof_ && length > 0)
{
auto r = unicode_traits::detect_encoding_from_bom(data, length);
if (!(r.encoding == unicode_traits::encoding_kind::utf8 || r.encoding == unicode_traits::encoding_kind::undetected))
{
ec = json_errc::illegal_unicode_character;
return span<const value_type>();
}
length -= (r.ptr - data);
data = r.ptr;
bof_ = false;
}
return span<const value_type>(data, length);
}
};
// json_source_adaptor
template<class Source>
class json_source_adaptor
{
public:
using value_type = typename Source::value_type;
private:
Source source_;
bool bof_;
public:
json_source_adaptor()
: bof_(true)
{
}
template <class Sourceable>
json_source_adaptor(Sourceable&& source)
: source_(std::forward<Sourceable>(source)), bof_(true)
{
}
bool eof() const
{
return source_.eof();
}
bool is_error() const
{
return source_.is_error();
}
span<const value_type> read_buffer(std::error_code& ec)
{
if (source_.eof())
{
return span<const value_type>();
}
auto s = source_.read_buffer();
const value_type* data = s.data();
std::size_t length = s.size();
if (bof_ && length > 0)
{
auto r = unicode_traits::detect_json_encoding(data, length);
if (!(r.encoding == unicode_traits::encoding_kind::utf8 || r.encoding == unicode_traits::encoding_kind::undetected))
{
ec = json_errc::illegal_unicode_character;
return span<const value_type>();
}
length -= (r.ptr - data);
data = r.ptr;
bof_ = false;
}
return span<const value_type>(data, length);
}
};
} // namespace jsoncons
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,449 @@
// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_STAJ_ITERATOR_HPP
#define JSONCONS_STAJ_ITERATOR_HPP
#include <new> // placement new
#include <memory>
#include <string>
#include <stdexcept>
#include <system_error>
#include <ios>
#include <iterator> // std::input_iterator_tag
#include <jsoncons/json_exception.hpp>
#include <jsoncons/staj_cursor.hpp>
#include <jsoncons/basic_json.hpp>
#include <jsoncons/decode_traits.hpp>
namespace jsoncons {
template <class T, class Json>
class staj_array_view;
template<class T, class Json>
class staj_array_iterator
{
using char_type = typename Json::char_type;
staj_array_view<T, Json>* view_;
std::exception_ptr eptr_;
public:
using value_type = T;
using difference_type = std::ptrdiff_t;
using pointer = T*;
using reference = T&;
using iterator_category = std::input_iterator_tag;
staj_array_iterator() noexcept
: view_(nullptr)
{
}
staj_array_iterator(staj_array_view<T, Json>& view)
: view_(std::addressof(view))
{
if (view_->cursor_->current().event_type() == staj_event_type::begin_array)
{
next();
}
else
{
view_->cursor_ = nullptr;
}
}
staj_array_iterator(staj_array_view<T, Json>& view,
std::error_code& ec)
: view_(std::addressof(view))
{
if (view_->cursor_->current().event_type() == staj_event_type::begin_array)
{
next(ec);
if (ec) {view_ = nullptr;}
}
else
{
view_ = nullptr;
}
}
~staj_array_iterator() noexcept
{
}
bool has_value() const
{
return !eptr_;
}
const T& operator*() const
{
if (eptr_)
{
std::rethrow_exception(eptr_);
}
else
{
return *view_->value_;
}
}
const T* operator->() const
{
if (eptr_)
{
std::rethrow_exception(eptr_);
}
else
{
return view_->value_.operator->();
}
}
staj_array_iterator& operator++()
{
next();
return *this;
}
staj_array_iterator& increment(std::error_code& ec)
{
next(ec);
if (ec) {view_ = nullptr;}
return *this;
}
staj_array_iterator operator++(int) // postfix increment
{
staj_array_iterator temp(*this);
next();
return temp;
}
friend bool operator==(const staj_array_iterator& a, const staj_array_iterator& b)
{
return (!a.view_ && !b.view_)
|| (!a.view_ && b.done())
|| (!b.view_ && a.done());
}
friend bool operator!=(const staj_array_iterator& a, const staj_array_iterator& b)
{
return !(a == b);
}
private:
bool done() const
{
return view_->cursor_->done() || view_->cursor_->current().event_type() == staj_event_type::end_array;
}
void next()
{
std::error_code ec;
next(ec);
if (ec)
{
JSONCONS_THROW(ser_error(ec, view_->cursor_->context().line(), view_->cursor_->context().column()));
}
}
void next(std::error_code& ec)
{
using char_type = typename Json::char_type;
if (!done())
{
view_->cursor_->next(ec);
if (ec)
{
return;
}
if (!done())
{
eptr_ = std::exception_ptr();
JSONCONS_TRY
{
view_->value_ = decode_traits<T,char_type>::decode(*view_->cursor_, view_->decoder_, ec);
}
JSONCONS_CATCH(const conv_error&)
{
eptr_ = std::current_exception();
}
}
}
}
};
template <class Key,class Json,class T=Json>
class staj_object_view;
template <class Key, class T, class Json>
class staj_object_iterator
{
using char_type = typename Json::char_type;
staj_object_view<Key, T, Json>* view_;
std::exception_ptr eptr_;
public:
using key_type = std::basic_string<char_type>;
using value_type = std::pair<key_type,T>;
using difference_type = std::ptrdiff_t;
using pointer = value_type*;
using reference = value_type&;
using iterator_category = std::input_iterator_tag;
public:
staj_object_iterator() noexcept
: view_(nullptr)
{
}
staj_object_iterator(staj_object_view<Key, T, Json>& view)
: view_(std::addressof(view))
{
if (view_->cursor_->current().event_type() == staj_event_type::begin_object)
{
next();
}
else
{
view_ = nullptr;
}
}
staj_object_iterator(staj_object_view<Key, T, Json>& view,
std::error_code& ec)
: view_(std::addressof(view))
{
if (view_->cursor_->current().event_type() == staj_event_type::begin_object)
{
next(ec);
if (ec) {view_ = nullptr;}
}
else
{
view_ = nullptr;
}
}
~staj_object_iterator() noexcept
{
}
bool has_value() const
{
return !eptr_;
}
const value_type& operator*() const
{
if (eptr_)
{
std::rethrow_exception(eptr_);
}
else
{
return *view_->key_value_;
}
}
const value_type* operator->() const
{
if (eptr_)
{
std::rethrow_exception(eptr_);
}
else
{
return view_->key_value_.operator->();
}
}
staj_object_iterator& operator++()
{
next();
return *this;
}
staj_object_iterator& increment(std::error_code& ec)
{
next(ec);
if (ec)
{
view_ = nullptr;
}
return *this;
}
staj_object_iterator operator++(int) // postfix increment
{
staj_object_iterator temp(*this);
next();
return temp;
}
friend bool operator==(const staj_object_iterator& a, const staj_object_iterator& b)
{
return (!a.view_ && !b.view_)
|| (!a.view_ && b.done())
|| (!b.view_ && a.done());
}
friend bool operator!=(const staj_object_iterator& a, const staj_object_iterator& b)
{
return !(a == b);
}
private:
bool done() const
{
return view_->cursor_->done() || view_->cursor_->current().event_type() == staj_event_type::end_object;
}
void next()
{
std::error_code ec;
next(ec);
if (ec)
{
JSONCONS_THROW(ser_error(ec, view_->cursor_->context().line(), view_->cursor_->context().column()));
}
}
void next(std::error_code& ec)
{
using char_type = typename Json::char_type;
view_->cursor_->next(ec);
if (ec)
{
return;
}
if (!done())
{
JSONCONS_ASSERT(view_->cursor_->current().event_type() == staj_event_type::key);
auto key = view_->cursor_->current(). template get<key_type>();
view_->cursor_->next(ec);
if (ec)
{
return;
}
if (!done())
{
eptr_ = std::exception_ptr();
JSONCONS_TRY
{
view_->key_value_ = value_type(std::move(key),decode_traits<T,char_type>::decode(*view_->cursor_, view_->decoder_, ec));
}
JSONCONS_CATCH(const conv_error&)
{
eptr_ = std::current_exception();
}
}
}
}
};
// staj_array_view
template <class T, class Json>
class staj_array_view
{
friend class staj_array_iterator<T, Json>;
public:
using char_type = typename Json::char_type;
using iterator = staj_array_iterator<T, Json>;
private:
basic_staj_cursor<char_type>* cursor_;
json_decoder<Json> decoder_;
jsoncons::optional<T> value_;
public:
staj_array_view(basic_staj_cursor<char_type>& cursor)
: cursor_(std::addressof(cursor))
{
}
iterator begin()
{
return staj_array_iterator<T, Json>(*this);
}
iterator end()
{
return staj_array_iterator<T, Json>();
}
};
// staj_object_view
template <class Key, class T, class Json>
class staj_object_view
{
friend class staj_object_iterator<Key,T,Json>;
public:
using char_type = typename Json::char_type;
using iterator = staj_object_iterator<Key,T,Json>;
using key_type = std::basic_string<char_type>;
using value_type = std::pair<key_type,T>;
private:
basic_staj_cursor<char_type>* cursor_;
json_decoder<Json> decoder_;
jsoncons::optional<value_type> key_value_;
public:
staj_object_view(basic_staj_cursor<char_type>& cursor)
: cursor_(std::addressof(cursor))
{
}
iterator begin()
{
return staj_object_iterator<Key,T,Json>(*this);
}
iterator end()
{
return staj_object_iterator<Key,T,Json>();
}
};
template <class T, class CharT, class Json=typename std::conditional<extension_traits::is_basic_json<T>::value,T,basic_json<CharT>>::type>
staj_array_view<T, Json> staj_array(basic_staj_cursor<CharT>& cursor)
{
return staj_array_view<T, Json>(cursor);
}
template <class Key, class T, class CharT, class Json=typename std::conditional<extension_traits::is_basic_json<T>::value,T,basic_json<CharT>>::type>
staj_object_view<Key, T, Json> staj_object(basic_staj_cursor<CharT>& cursor)
{
return staj_object_view<Key, T, Json>(cursor);
}
#if !defined(JSONCONS_NO_DEPRECATED)
template <class T, class CharT, class Json=typename std::conditional<extension_traits::is_basic_json<T>::value,T,basic_json<CharT>>::type>
JSONCONS_DEPRECATED_MSG("Instead, use staj_array()")
staj_array_view<T, Json> make_array_iterator(basic_staj_cursor<CharT>& cursor)
{
return staj_array_view<T, Json>(cursor);
}
template <class T, class CharT, class Json=typename std::conditional<extension_traits::is_basic_json<T>::value,T,basic_json<CharT>>::type>
JSONCONS_DEPRECATED_MSG("Instead, use staj_object()")
staj_object_view<std::basic_string<CharT>, T, Json> make_object_iterator(basic_staj_cursor<CharT>& cursor)
{
return staj_object_view<std::basic_string<CharT>, T, Json>(cursor);
}
#endif
} // namespace jsoncons
#endif

View file

@ -0,0 +1,245 @@
// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_TAG_TYPE_HPP
#define JSONCONS_TAG_TYPE_HPP
#include <ostream>
#include <jsoncons/config/jsoncons_config.hpp>
namespace jsoncons {
struct null_type
{
explicit null_type() = default;
};
struct temp_allocator_arg_t
{
explicit temp_allocator_arg_t() = default;
};
constexpr temp_allocator_arg_t temp_allocator_arg{};
struct result_allocator_arg_t
{
explicit result_allocator_arg_t() = default;
};
constexpr result_allocator_arg_t result_allocator_arg{};
struct half_arg_t
{
explicit half_arg_t() = default;
};
constexpr half_arg_t half_arg{};
struct json_array_arg_t
{
explicit json_array_arg_t() = default;
};
constexpr json_array_arg_t json_array_arg{};
struct json_object_arg_t
{
explicit json_object_arg_t() = default;
};
constexpr json_object_arg_t json_object_arg{};
struct byte_string_arg_t
{
explicit byte_string_arg_t() = default;
};
constexpr byte_string_arg_t byte_string_arg{};
struct json_const_pointer_arg_t
{
explicit json_const_pointer_arg_t() = default;
};
constexpr json_const_pointer_arg_t json_const_pointer_arg{};
enum class semantic_tag : uint8_t
{
none = 0,
undefined = 0x01,
datetime = 0x02,
epoch_second = 0x03,
epoch_milli = 0x04,
epoch_nano = 0x05,
bigint = 0x06,
bigdec = 0x07,
bigfloat = 0x08,
float128 = 0x09,
base16 = 0x1a,
base64 = 0x1b,
base64url = 0x1c,
uri = 0x0d,
clamped = 0x0e,
multi_dim_row_major = 0x0f,
multi_dim_column_major = 0x10,
ext = 0x11,
id = 0x12,
regex = 0x13,
code = 0x14
#if !defined(JSONCONS_NO_DEPRECATED)
, big_integer = bigint
, big_decimal = bigdec
, big_float = bigfloat
, date_time = datetime
, timestamp = epoch_second
#endif
};
template <class CharT>
std::basic_ostream<CharT>& operator<<(std::basic_ostream<CharT>& os, semantic_tag tag)
{
static constexpr const CharT* na_name = JSONCONS_CSTRING_CONSTANT(CharT, "n/a");
static constexpr const CharT* undefined_name = JSONCONS_CSTRING_CONSTANT(CharT, "undefined");
static constexpr const CharT* datetime_name = JSONCONS_CSTRING_CONSTANT(CharT, "datetime");
static constexpr const CharT* epoch_second_name = JSONCONS_CSTRING_CONSTANT(CharT, "epoch-second");
static constexpr const CharT* epoch_milli_name = JSONCONS_CSTRING_CONSTANT(CharT, "epoch-milli");
static constexpr const CharT* epoch_nano_name = JSONCONS_CSTRING_CONSTANT(CharT, "epoch-nano");
static constexpr const CharT* bigint_name = JSONCONS_CSTRING_CONSTANT(CharT, "bigint");
static constexpr const CharT* bigdec_name = JSONCONS_CSTRING_CONSTANT(CharT, "bigdec");
static constexpr const CharT* bigfloat_name = JSONCONS_CSTRING_CONSTANT(CharT, "bigfloat");
static constexpr const CharT* base16_name = JSONCONS_CSTRING_CONSTANT(CharT, "base16");
static constexpr const CharT* base64_name = JSONCONS_CSTRING_CONSTANT(CharT, "base64");
static constexpr const CharT* base64url_name = JSONCONS_CSTRING_CONSTANT(CharT, "base64url");
static constexpr const CharT* uri_name = JSONCONS_CSTRING_CONSTANT(CharT, "uri");
static constexpr const CharT* clamped_name = JSONCONS_CSTRING_CONSTANT(CharT, "clamped");
static constexpr const CharT* multi_dim_row_major_name = JSONCONS_CSTRING_CONSTANT(CharT, "multi-dim-row-major");
static constexpr const CharT* multi_dim_column_major_name = JSONCONS_CSTRING_CONSTANT(CharT, "multi-dim-column-major");
static constexpr const CharT* ext_name = JSONCONS_CSTRING_CONSTANT(CharT, "ext");
static constexpr const CharT* id_name = JSONCONS_CSTRING_CONSTANT(CharT, "id");
static constexpr const CharT* float128_name = JSONCONS_CSTRING_CONSTANT(CharT, "float128");
static constexpr const CharT* regex_name = JSONCONS_CSTRING_CONSTANT(CharT, "regex");
static constexpr const CharT* code_name = JSONCONS_CSTRING_CONSTANT(CharT, "code");
switch (tag)
{
case semantic_tag::none:
{
os << na_name;
break;
}
case semantic_tag::undefined:
{
os << undefined_name;
break;
}
case semantic_tag::datetime:
{
os << datetime_name;
break;
}
case semantic_tag::epoch_second:
{
os << epoch_second_name;
break;
}
case semantic_tag::epoch_milli:
{
os << epoch_milli_name;
break;
}
case semantic_tag::epoch_nano:
{
os << epoch_nano_name;
break;
}
case semantic_tag::bigint:
{
os << bigint_name;
break;
}
case semantic_tag::bigdec:
{
os << bigdec_name;
break;
}
case semantic_tag::bigfloat:
{
os << bigfloat_name;
break;
}
case semantic_tag::float128:
{
os << float128_name;
break;
}
case semantic_tag::base16:
{
os << base16_name;
break;
}
case semantic_tag::base64:
{
os << base64_name;
break;
}
case semantic_tag::base64url:
{
os << base64url_name;
break;
}
case semantic_tag::uri:
{
os << uri_name;
break;
}
case semantic_tag::clamped:
{
os << clamped_name;
break;
}
case semantic_tag::multi_dim_row_major:
{
os << multi_dim_row_major_name;
break;
}
case semantic_tag::multi_dim_column_major:
{
os << multi_dim_column_major_name;
break;
}
case semantic_tag::ext:
{
os << ext_name;
break;
}
case semantic_tag::id:
{
os << id_name;
break;
}
case semantic_tag::regex:
{
os << regex_name;
break;
}
case semantic_tag::code:
{
os << code_name;
break;
}
}
return os;
}
#if !defined(JSONCONS_NO_DEPRECATED)
JSONCONS_DEPRECATED_MSG("Instead, use semantic_tag") typedef semantic_tag semantic_tag_type;
JSONCONS_DEPRECATED_MSG("Instead, use byte_string_arg_t") typedef byte_string_arg_t bstr_arg_t;
constexpr byte_string_arg_t bstr_arg{};
#endif
}
#endif

View file

@ -0,0 +1,144 @@
// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_TEXT_SOURCE_ADAPTOR_HPP
#define JSONCONS_TEXT_SOURCE_ADAPTOR_HPP
#include <cstddef>
#include <string>
#include <vector>
#include <stdexcept>
#include <system_error>
#include <memory> // std::allocator_traits
#include <vector> // std::vector
#include <jsoncons/unicode_traits.hpp>
#include <jsoncons/json_error.hpp> // json_errc
#include <jsoncons/source.hpp>
#include <jsoncons/json_exception.hpp>
namespace jsoncons {
// unicode_source_adaptor
template<class Source,class Allocator>
class unicode_source_adaptor
{
public:
using value_type = typename Source::value_type;
using source_type = Source;
private:
source_type source_;
bool bof_;
public:
template <class Sourceable>
unicode_source_adaptor(Sourceable&& source)
: source_(std::forward<Sourceable>(source)),
bof_(true)
{
}
bool is_error() const
{
return source_.is_error();
}
bool eof() const
{
return source_.eof();
}
span<const value_type> read_buffer(std::error_code& ec)
{
if (source_.eof())
{
return span<const value_type>();
}
auto s = source_.read_buffer();
const value_type* data = s.data();
std::size_t length = s.size();
if (bof_ && length > 0)
{
auto r = unicode_traits::detect_encoding_from_bom(data, length);
if (!(r.encoding == unicode_traits::encoding_kind::utf8 || r.encoding == unicode_traits::encoding_kind::undetected))
{
ec = json_errc::illegal_unicode_character;
return;
}
length -= (r.ptr - data);
data = r.ptr;
bof_ = false;
}
return span<const value_type>(data, length);
}
};
// json_source_adaptor
template<class Source,class Allocator>
class json_source_adaptor
{
public:
using value_type = typename Source::value_type;
using value_type = typename Source::value_type;
using source_type = Source;
private:
source_type source_;
bool bof_;
public:
template <class Sourceable>
json_source_adaptor(Sourceable&& source)
: source_(std::forward<Sourceable>(source)),
bof_(true)
{
}
bool is_error() const
{
return source_.is_error();
}
bool eof() const
{
return source_.eof();
}
span<const value_type> read_buffer(std::error_code& ec)
{
if (source_.eof())
{
return span<const value_type>();
}
auto s = source_.read_buffer();
const value_type* data = s.data();
std::size_t length = s.size();
if (bof_ && length > 0)
{
auto r = unicode_traits::detect_json_encoding(data, length);
if (!(r.encoding == unicode_traits::encoding_kind::utf8 || r.encoding == unicode_traits::encoding_kind::undetected))
{
ec = json_errc::illegal_unicode_character;
return span<const value_type>();
}
length -= (r.ptr - data);
data = r.ptr;
bof_ = false;
}
return span<const value_type>(data, length);
}
};
} // namespace jsoncons
#endif

View file

@ -0,0 +1,250 @@
// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_TYPED_ARRAY_VIEW_HPP
#define JSONCONS_TYPED_ARRAY_VIEW_HPP
#include <memory> // std::allocator
#include <string>
#include <stdexcept>
#include <system_error>
#include <ios>
#include <type_traits> // std::enable_if
#include <array> // std::array
#include <functional> // std::function
#include <jsoncons/json_exception.hpp>
#include <jsoncons/json_visitor.hpp>
#include <jsoncons/bigint.hpp>
#include <jsoncons/json_parser.hpp>
#include <jsoncons/ser_context.hpp>
#include <jsoncons/sink.hpp>
#include <jsoncons/detail/write_number.hpp>
#include <jsoncons/json_type_traits.hpp>
#include <jsoncons/value_converter.hpp>
namespace jsoncons {
struct uint8_array_arg_t {explicit uint8_array_arg_t() = default; };
constexpr uint8_array_arg_t uint8_array_arg = uint8_array_arg_t();
struct uint16_array_arg_t {explicit uint16_array_arg_t() = default; };
struct uint32_array_arg_t {explicit uint32_array_arg_t() = default; };
constexpr uint32_array_arg_t uint32_array_arg = uint32_array_arg_t();
struct uint64_array_arg_t {explicit uint64_array_arg_t() = default; };
constexpr uint64_array_arg_t uint64_array_arg = uint64_array_arg_t();
struct int8_array_arg_t {explicit int8_array_arg_t() = default; };
constexpr int8_array_arg_t int8_array_arg = int8_array_arg_t();
struct int16_array_arg_t {explicit int16_array_arg_t() = default; };
constexpr int16_array_arg_t int16_array_arg = int16_array_arg_t();
struct int32_array_arg_t {explicit int32_array_arg_t() = default; };
constexpr int32_array_arg_t int32_array_arg = int32_array_arg_t();
struct int64_array_arg_t {explicit int64_array_arg_t() = default; };
constexpr int64_array_arg_t int64_array_arg = int64_array_arg_t();
constexpr uint16_array_arg_t uint16_array_arg = uint16_array_arg_t();
struct half_array_arg_t {explicit half_array_arg_t() = default; };
constexpr half_array_arg_t half_array_arg = half_array_arg_t();
struct float_array_arg_t {explicit float_array_arg_t() = default; };
constexpr float_array_arg_t float_array_arg = float_array_arg_t();
struct double_array_arg_t {explicit double_array_arg_t() = default; };
constexpr double_array_arg_t double_array_arg = double_array_arg_t();
struct float128_array_arg_t {explicit float128_array_arg_t() = default; };
constexpr float128_array_arg_t float128_array_arg = float128_array_arg_t();
enum class typed_array_type{uint8_value=1,uint16_value,uint32_value,uint64_value,
int8_value,int16_value,int32_value,int64_value,
half_value, float_value,double_value};
class typed_array_view
{
typed_array_type type_;
union
{
const uint8_t* uint8_data_;
const uint16_t* uint16_data_;
const uint32_t* uint32_data_;
const uint64_t* uint64_data_;
const int8_t* int8_data_;
const int16_t* int16_data_;
const int32_t* int32_data_;
const int64_t* int64_data_;
const float* float_data_;
const double* double_data_;
} data_;
std::size_t size_;
public:
typed_array_view()
: type_(), data_(), size_(0)
{
}
typed_array_view(const typed_array_view& other)
: type_(other.type_), data_(other.data_), size_(other.size())
{
}
typed_array_view(typed_array_view&& other) noexcept
{
swap(*this,other);
}
typed_array_view(const uint8_t* data, std::size_t size)
: type_(typed_array_type::uint8_value), size_(size)
{
data_.uint8_data_ = data;
}
typed_array_view(const uint16_t* data, std::size_t size)
: type_(typed_array_type::uint16_value), size_(size)
{
data_.uint16_data_ = data;
}
typed_array_view(const uint32_t* data, std::size_t size)
: type_(typed_array_type::uint32_value), size_(size)
{
data_.uint32_data_ = data;
}
typed_array_view(const uint64_t* data, std::size_t size)
: type_(typed_array_type::uint64_value), size_(size)
{
data_.uint64_data_ = data;
}
typed_array_view(const int8_t* data, std::size_t size)
: type_(typed_array_type::int8_value), size_(size)
{
data_.int8_data_ = data;
}
typed_array_view(const int16_t* data, std::size_t size)
: type_(typed_array_type::int16_value), size_(size)
{
data_.int16_data_ = data;
}
typed_array_view(const int32_t* data, std::size_t size)
: type_(typed_array_type::int32_value), size_(size)
{
data_.int32_data_ = data;
}
typed_array_view(const int64_t* data, std::size_t size)
: type_(typed_array_type::int64_value), size_(size)
{
data_.int64_data_ = data;
}
typed_array_view(half_array_arg_t, const uint16_t* data, std::size_t size)
: type_(typed_array_type::half_value), size_(size)
{
data_.uint16_data_ = data;
}
typed_array_view(const float* data, std::size_t size)
: type_(typed_array_type::float_value), size_(size)
{
data_.float_data_ = data;
}
typed_array_view(const double* data, std::size_t size)
: type_(typed_array_type::double_value), size_(size)
{
data_.double_data_ = data;
}
typed_array_view& operator=(const typed_array_view& other)
{
typed_array_view temp(other);
swap(*this,temp);
return *this;
}
typed_array_type type() const {return type_;}
std::size_t size() const
{
return size_;
}
jsoncons::span<const uint8_t> data(uint8_array_arg_t) const
{
JSONCONS_ASSERT(type_ == typed_array_type::uint8_value);
return jsoncons::span<const uint8_t>(data_.uint8_data_, size_);
}
jsoncons::span<const uint16_t> data(uint16_array_arg_t) const
{
JSONCONS_ASSERT(type_ == typed_array_type::uint16_value);
return jsoncons::span<const uint16_t>(data_.uint16_data_, size_);
}
jsoncons::span<const uint32_t> data(uint32_array_arg_t) const
{
JSONCONS_ASSERT(type_ == typed_array_type::uint32_value);
return jsoncons::span<const uint32_t>(data_.uint32_data_, size_);
}
jsoncons::span<const uint64_t> data(uint64_array_arg_t) const
{
JSONCONS_ASSERT(type_ == typed_array_type::uint64_value);
return jsoncons::span<const uint64_t>(data_.uint64_data_, size_);
}
jsoncons::span<const int8_t> data(int8_array_arg_t) const
{
JSONCONS_ASSERT(type_ == typed_array_type::int8_value);
return jsoncons::span<const int8_t>(data_.int8_data_, size_);
}
jsoncons::span<const int16_t> data(int16_array_arg_t) const
{
JSONCONS_ASSERT(type_ == typed_array_type::int16_value);
return jsoncons::span<const int16_t>(data_.int16_data_, size_);
}
jsoncons::span<const int32_t> data(int32_array_arg_t) const
{
JSONCONS_ASSERT(type_ == typed_array_type::int32_value);
return jsoncons::span<const int32_t>(data_.int32_data_, size_);
}
jsoncons::span<const int64_t> data(int64_array_arg_t) const
{
JSONCONS_ASSERT(type_ == typed_array_type::int64_value);
return jsoncons::span<const int64_t>(data_.int64_data_, size_);
}
jsoncons::span<const uint16_t> data(half_array_arg_t) const
{
JSONCONS_ASSERT(type_ == typed_array_type::half_value);
return jsoncons::span<const uint16_t>(data_.uint16_data_, size_);
}
jsoncons::span<const float> data(float_array_arg_t) const
{
JSONCONS_ASSERT(type_ == typed_array_type::float_value);
return jsoncons::span<const float>(data_.float_data_, size_);
}
jsoncons::span<const double> data(double_array_arg_t) const
{
JSONCONS_ASSERT(type_ == typed_array_type::double_value);
return jsoncons::span<const double>(data_.double_data_, size_);
}
friend void swap(typed_array_view& a, typed_array_view& b) noexcept
{
std::swap(a.data_,b.data_);
std::swap(a.type_,b.type_);
std::swap(a.size_,b.size_);
}
};
} // namespace jsoncons
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,635 @@
// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_URI_HPP
#define JSONCONS_URI_HPP
#include <string> // std::string
#include <algorithm>
#include <sstream>
#include <jsoncons/config/jsoncons_config.hpp>
#include <jsoncons/json_exception.hpp>
namespace jsoncons {
class uri
{
using part_type = std::pair<std::size_t,std::size_t>;
std::string uri_;
part_type scheme_;
part_type userinfo_;
part_type host_;
part_type port_;
part_type path_;
part_type query_;
part_type fragment_;
public:
uri() = default;
uri(const std::string& uri)
{
*this = parse(uri);
}
uri(jsoncons::string_view scheme,
jsoncons::string_view userinfo,
jsoncons::string_view host,
jsoncons::string_view port,
jsoncons::string_view path,
jsoncons::string_view query,
jsoncons::string_view fragment)
{
if (!scheme.empty())
{
uri_.append(std::string(scheme));
scheme_.second = uri_.length();
}
if (!userinfo.empty() || !host.empty() || !port.empty())
{
if (!scheme.empty())
{
uri_.append("://");
}
if (!userinfo.empty())
{
userinfo_.first = uri_.length();
uri_.append(std::string(userinfo));
userinfo_.second = uri_.length();
uri_.append("@");
}
else
{
userinfo_.first = userinfo_.second = uri_.length();
}
if (!host.empty())
{
host_.first = uri_.length();
uri_.append(std::string(host));
host_.second = uri_.length();
}
else
{
JSONCONS_THROW(json_runtime_error<std::invalid_argument>("uri error."));
}
if (!port.empty())
{
uri_.append(":");
port_.first = uri_.length();
uri_.append(std::string(port));
port_.second = uri_.length();
}
else
{
port_.first = port_.second = uri_.length();
}
}
else
{
userinfo_.first = userinfo_.second = uri_.length();
host_.first = host_.second = uri_.length();
port_.first = port_.second = uri_.length();
if (!scheme.empty())
{
if (!path.empty() || !query.empty() || !fragment.empty())
{
uri_.append(":");
}
else
{
JSONCONS_THROW(json_runtime_error<std::invalid_argument>("uri error."));
}
}
}
if (!path.empty())
{
// if the URI is not opaque and the path is not already prefixed
// with a '/', add one.
path_.first = uri_.length();
if (!host.empty() && (path.front() != '/'))
{
uri_.push_back('/');
}
uri_.append(std::string(path));
path_.second = uri_.length();
}
else
{
path_.first = path_.second = uri_.length();
}
if (!query.empty())
{
uri_.append("?");
query_.first = uri_.length();
uri_.append(std::string(query));
query_.second = uri_.length();
}
else
{
query_.first = query_.second = uri_.length();
}
if (!fragment.empty())
{
uri_.append("#");
fragment_.first = uri_.length();
uri_.append(std::string(fragment));
fragment_.second = uri_.length();
}
else
{
fragment_.first = fragment_.second = uri_.length();
}
}
const std::string& string() const
{
return uri_;
}
bool is_absolute() const noexcept
{
return scheme_.first != scheme_.second;
}
bool is_opaque() const noexcept
{
return is_absolute() && !authority().empty();
}
string_view base() const noexcept { return string_view(uri_.data()+scheme_.first,(path_.second-scheme_.first)); }
string_view scheme() const noexcept { return string_view(uri_.data()+scheme_.first,(scheme_.second-scheme_.first)); }
string_view userinfo() const noexcept { return string_view(uri_.data()+userinfo_.first,(userinfo_.second-userinfo_.first)); }
string_view host() const noexcept { return string_view(uri_.data()+host_.first,(host_.second-host_.first)); }
string_view port() const noexcept { return string_view(uri_.data()+port_.first,(port_.second-port_.first)); }
string_view path() const noexcept { return string_view(uri_.data()+path_.first,(path_.second-path_.first)); }
string_view query() const noexcept { return string_view(uri_.data()+query_.first,(query_.second-query_.first)); }
string_view fragment() const noexcept { return string_view(uri_.data()+fragment_.first,(fragment_.second-fragment_.first)); }
string_view authority() const noexcept { return string_view(uri_.data()+userinfo_.first,(port_.second-userinfo_.first)); }
uri resolve(const uri& base) const
{
// This implementation uses the psuedo-code given in
// http://tools.ietf.org/html/rfc3986#section-5.2.2
if (is_absolute() && !is_opaque())
{
return *this;
}
if (is_opaque())
{
return *this;
}
std::string userinfo, host, port, path, query, fragment;
if (!authority().empty())
{
// g -> http://g
if (!this->userinfo().empty())
{
userinfo = std::string(this->userinfo());
}
if (!this->host().empty())
{
host = std::string(this->host());
}
if (!this->port().empty())
{
port = std::string(this->port());
}
if (!this->path().empty())
{
path = remove_dot_segments(this->path());
}
if (!this->query().empty())
{
query = std::string(this->query());
}
}
else
{
if (this->path().empty())
{
if (!base.path().empty())
{
path = std::string(base.path());
}
if (!this->query().empty())
{
query = std::string(this->query());
}
else if (!base.query().empty())
{
query = std::string(base.query());
}
}
else
{
if (this->path().front() == '/')
{
path = remove_dot_segments(this->path());
}
else
{
path = merge_paths(base, *this);
}
if (!this->query().empty())
{
query = std::string(this->query());
}
}
if (!base.userinfo().empty())
{
userinfo = std::string(base.userinfo());
}
if (!base.host().empty())
{
host = std::string(base.host());
}
if (!base.port().empty())
{
port = std::string(base.port());
}
}
if (!this->fragment().empty())
{
fragment = std::string(this->fragment());
}
return uri(std::string(base.scheme()), userinfo, host, port, path, query, fragment);
}
int compare(const uri& other) const
{
int result = scheme().compare(other.scheme());
if (result != 0) return result;
result = userinfo().compare(other.userinfo());
if (result != 0) return result;
result = host().compare(other.host());
if (result != 0) return result;
result = port().compare(other.port());
if (result != 0) return result;
result = path().compare(other.path());
if (result != 0) return result;
result = query().compare(other.query());
if (result != 0) return result;
result = fragment().compare(other.fragment());
return result;
}
friend bool operator==(const uri& lhs, const uri& rhs)
{
return lhs.compare(rhs) == 0;
}
friend bool operator!=(const uri& lhs, const uri& rhs)
{
return lhs.compare(rhs) != 0;
}
friend bool operator<(const uri& lhs, const uri& rhs)
{
return lhs.compare(rhs) < 0;
}
friend bool operator<=(const uri& lhs, const uri& rhs)
{
return lhs.compare(rhs) <= 0;
}
friend bool operator>(const uri& lhs, const uri& rhs)
{
return lhs.compare(rhs) > 0;
}
friend bool operator>=(const uri& lhs, const uri& rhs)
{
return lhs.compare(rhs) >= 0;
}
private:
enum class parse_state {expect_scheme,
expect_first_slash,
expect_second_slash,
expect_authority,
expect_host_ipv6,
expect_userinfo,
expect_host,
expect_port,
expect_path,
expect_query,
expect_fragment};
uri(const std::string& uri, part_type scheme, part_type userinfo,
part_type host, part_type port, part_type path,
part_type query, part_type fragment)
: uri_(uri), scheme_(scheme), userinfo_(userinfo),
host_(host), port_(port), path_(path),
query_(query), fragment_(fragment)
{
}
static uri parse(const std::string& s)
{
part_type scheme;
part_type userinfo;
part_type host;
part_type port;
part_type path;
part_type query;
part_type fragment;
std::size_t start = 0;
parse_state state = parse_state::expect_scheme;
for (std::size_t i = 0; i < s.size(); ++i)
{
char c = s[i];
switch (state)
{
case parse_state::expect_scheme:
switch (c)
{
case ':':
scheme = std::make_pair(start,i);
state = parse_state::expect_first_slash;
start = i;
break;
case '#':
userinfo = std::make_pair(start,start);
host = std::make_pair(start,start);
port = std::make_pair(start,start);
path = std::make_pair(start,i);
query = std::make_pair(i,i);
state = parse_state::expect_fragment;
start = i+1;
break;
default:
break;
}
break;
case parse_state::expect_first_slash:
switch (c)
{
case '/':
state = parse_state::expect_second_slash;
break;
default:
start = i;
state = parse_state::expect_path;
break;
}
break;
case parse_state::expect_second_slash:
switch (c)
{
case '/':
state = parse_state::expect_authority;
start = i+1;
break;
default:
break;
}
break;
case parse_state::expect_authority:
switch (c)
{
case '[':
state = parse_state::expect_host_ipv6;
start = i+1;
break;
default:
state = parse_state::expect_userinfo;
start = i;
--i;
break;
}
break;
case parse_state::expect_host_ipv6:
switch (c)
{
case ']':
userinfo = std::make_pair(start,start);
host = std::make_pair(start,i);
port = std::make_pair(i,i);
state = parse_state::expect_path;
start = i+1;
break;
default:
break;
}
break;
case parse_state::expect_userinfo:
switch (c)
{
case '@':
userinfo = std::make_pair(start,i);
state = parse_state::expect_host;
start = i+1;
break;
case ':':
userinfo = std::make_pair(start,start);
host = std::make_pair(start,i);
state = parse_state::expect_port;
start = i+1;
break;
case '/':
userinfo = std::make_pair(start,start);
host = std::make_pair(start,i);
port = std::make_pair(i,i);
state = parse_state::expect_path;
start = i;
break;
default:
break;
}
break;
case parse_state::expect_host:
switch (c)
{
case ':':
host = std::make_pair(start,i);
state = parse_state::expect_port;
start = i+1;
break;
default:
break;
}
break;
case parse_state::expect_port:
switch (c)
{
case '/':
port = std::make_pair(start,i);
state = parse_state::expect_path;
start = i;
break;
default:
break;
}
break;
case parse_state::expect_path:
switch (c)
{
case '?':
path = std::make_pair(start,i);
state = parse_state::expect_query;
start = i+1;
break;
case '#':
path = std::make_pair(start,i);
query = std::make_pair(start,start);
state = parse_state::expect_fragment;
start = i+1;
break;
default:
break;
}
break;
case parse_state::expect_query:
switch (c)
{
case '#':
query = std::make_pair(start,i);
state = parse_state::expect_fragment;
start = i+1;
break;
default:
break;
}
break;
case parse_state::expect_fragment:
break;
}
}
switch (state)
{
case parse_state::expect_scheme:
userinfo = std::make_pair(start,start);
host = std::make_pair(start,start);
port = std::make_pair(start,start);
path = std::make_pair(start,s.size());
break;
case parse_state::expect_userinfo:
userinfo = std::make_pair(start,start);
host = std::make_pair(start,start);
port = std::make_pair(start,start);
path = std::make_pair(start,s.size());
break;
case parse_state::expect_path:
path = std::make_pair(start,s.size());
break;
case parse_state::expect_query:
query = std::make_pair(start,s.size());
break;
case parse_state::expect_fragment:
fragment = std::make_pair(start,s.size());
break;
default:
JSONCONS_THROW(std::invalid_argument("Invalid uri"));
break;
}
return uri(s, scheme, userinfo, host, port, path, query, fragment);
}
static std::string remove_dot_segments(const jsoncons::string_view& input)
{
std::string result = std::string(input);
/*
std::size_t pos = 0;
while (pos < input.size())
{
if (input.compare(0, 3, "../"))
{
network_boost::erase_head(input, 3);
} else if (network_boost::starts_with(input, "./")) {
network_boost::erase_head(input, 2);
} else if (network_boost::starts_with(input, "/./")) {
network_boost::replace_head(input, 3, "/");
} else if (input == "/.") {
network_boost::replace_head(input, 2, "/");
} else if (network_boost::starts_with(input, "/../")) {
network_boost::erase_head(input, 3);
remove_last_segment(result);
} else if (network_boost::starts_with(input, "/..")) {
network_boost::replace_head(input, 3, "/");
remove_last_segment(result);
} else if (network_boost::algorithm::all(input, [](char ch) { return ch == '.'; })) {
input.clear();
}
else {
int n = (input.front() == '/')? 1 : 0;
auto slash = network_boost::find_nth(input, "/", n);
result.append(std::begin(input), std::begin(slash));
input.erase(std::begin(input), std::begin(slash));
}
}
*/
return result;
}
static std::string merge_paths(const uri& base, const uri& relative)
{
std::string result;
if (base.path().empty())
{
result = "/";
}
else
{
const auto& base_path = base.path();
auto last_slash = base_path.rfind('/');
result.append(std::string(base_path.substr(0,last_slash+1)));
}
if (!relative.path().empty())
{
result.append(relative.path().begin(), relative.path().end());
}
return remove_dot_segments(jsoncons::string_view(result));
}
static void remove_last_segment(std::string& path)
{
auto last_slash = path.rfind('/');
if (last_slash != std::string::npos)
{
path.erase(last_slash);
}
}
};
} // namespace jsoncons
#endif

View file

@ -0,0 +1,340 @@
// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_CONVERTER_HPP
#define JSONCONS_CONVERTER_HPP
#include <system_error> // std::error_code
#include <jsoncons/extension_traits.hpp>
#include <jsoncons/byte_string.hpp>
#include <jsoncons/json_type.hpp>
#include <jsoncons/conv_error.hpp>
#include <jsoncons/detail/write_number.hpp> // from_integer
#include <jsoncons/tag_type.hpp>
namespace jsoncons {
template <class From, class Into, class Enable = void>
class value_converter
{
};
template <class Into>
class value_converter_base
{
public:
using allocator_type = typename std::conditional<extension_traits::has_allocator_type<Into>::value, typename Into::allocator_type, std::allocator<char>>::type;
private:
allocator_type alloc_;
public:
value_converter_base(const allocator_type& alloc = allocator_type())
: alloc_(alloc)
{
}
allocator_type get_allocator() const noexcept
{
return alloc_;
}
};
// From any byte sequence, Into string
template <class From, class Into>
class value_converter<From, Into,
typename std::enable_if<extension_traits::is_byte_sequence<From>::value && !extension_traits::is_string_or_string_view<From>::value &&
extension_traits::is_string<Into>::value>::type> : value_converter_base<Into>
{
public:
using allocator_type = typename value_converter_base<Into>::allocator_type;
template <class CharT = typename Into::value_type>
typename std::enable_if<extension_traits::is_narrow_character<CharT>::value,Into>::type
convert(const From& value, semantic_tag tag, std::error_code&)
{
Into s(this->get_allocator());
switch (tag)
{
case semantic_tag::base64:
encode_base64(value.begin(), value.end(), s);
break;
case semantic_tag::base16:
encode_base16(value.begin(), value.end(), s);
break;
default:
encode_base64url(value.begin(), value.end(), s);
break;
}
return s;
}
template <class CharT = typename Into::value_type>
typename std::enable_if<extension_traits::is_wide_character<CharT>::value,Into>::type
convert(const From& value, semantic_tag tag, std::error_code& ec)
{
std::string s;
switch (tag)
{
case semantic_tag::base64:
encode_base64(value.begin(), value.end(), s);
break;
case semantic_tag::base16:
encode_base16(value.begin(), value.end(), s);
break;
default:
encode_base64url(value.begin(), value.end(), s);
break;
}
Into ws(this->get_allocator());
auto retval = unicode_traits::convert(s.data(), s.size(), ws);
if (retval.ec != unicode_traits::conv_errc())
{
ec = conv_errc::not_wide_char;
}
return ws;
}
};
// From byte string, Into byte string
template <class From, class Into>
class value_converter<From, Into,
typename std::enable_if<extension_traits::is_byte_sequence<From>::value &&
!extension_traits::is_string_or_string_view<From>::value &&
!extension_traits::is_string_or_string_view<Into>::value &&
extension_traits::is_back_insertable_byte_container<Into>::value>::type> : value_converter_base<Into>
{
public:
using allocator_type = typename value_converter_base<Into>::allocator_type;
Into convert(const From& value, semantic_tag, std::error_code&)
{
Into s(value.begin(),value.end(),this->get_allocator());
return s;
}
};
// From string or string_view, Into string, same character type
template <class From, class Into>
class value_converter<From, Into,
typename std::enable_if<extension_traits::is_string_or_string_view<From>::value &&
extension_traits::is_string<Into>::value &&
std::is_same<typename From::value_type,typename Into::value_type>::value>::type> : value_converter_base<Into>
{
public:
using allocator_type = typename value_converter_base<Into>::allocator_type;
Into convert(const From& value, semantic_tag, std::error_code&)
{
return Into(value.begin(),value.end(),this->get_allocator());
}
};
// From string or string_view, Into string, different character type
template <class From, class Into>
class value_converter<From, Into,
typename std::enable_if<extension_traits::is_string_or_string_view<From>::value &&
extension_traits::is_string<Into>::value &&
!std::is_same<typename From::value_type,typename Into::value_type>::value>::type> : value_converter_base<Into>
{
public:
using allocator_type = typename value_converter_base<Into>::allocator_type;
Into convert(const From& value, semantic_tag, std::error_code& ec)
{
Into ws(this->get_allocator());
auto retval = unicode_traits::convert(value.data(), value.size(), ws);
if (retval.ec != unicode_traits::conv_errc())
{
ec = conv_errc::not_wide_char;
}
return ws;
}
};
// From string, Into byte_string
template <class From, class Into>
class value_converter<From, Into,
typename std::enable_if<extension_traits::is_char_sequence<From>::value &&
!extension_traits::is_string_or_string_view<Into>::value &&
extension_traits::is_back_insertable_byte_container<Into>::value>::type> : value_converter_base<Into>
{
public:
using allocator_type = typename value_converter_base<Into>::allocator_type;
template <class CharT = typename From::value_type>
typename std::enable_if<extension_traits::is_narrow_character<CharT>::value,Into>::type
convert(const From& value, semantic_tag tag, std::error_code& ec)
{
Into bytes(this->get_allocator());
switch (tag)
{
case semantic_tag::base16:
{
auto res = decode_base16(value.begin(), value.end(), bytes);
if (res.ec != conv_errc::success)
{
ec = conv_errc::not_byte_string;
}
break;
}
case semantic_tag::base64:
{
decode_base64(value.begin(), value.end(), bytes);
break;
}
case semantic_tag::base64url:
{
decode_base64url(value.begin(), value.end(), bytes);
break;
}
default:
{
ec = conv_errc::not_byte_string;
break;
}
}
return bytes;
}
template <class CharT = typename From::value_type>
typename std::enable_if<extension_traits::is_wide_character<CharT>::value,Into>::type
convert(const From& value, semantic_tag tag, std::error_code& ec)
{
Into bytes(this->get_allocator());
std::string s(this->get_allocator());
auto retval = unicode_traits::convert(value.data(), value.size(), s);
if (retval.ec != unicode_traits::conv_errc())
{
ec = conv_errc::not_wide_char;
}
switch (tag)
{
case semantic_tag::base16:
{
auto res = decode_base16(s.begin(), s.end(), bytes);
if (res.ec != conv_errc::success)
{
ec = conv_errc::not_byte_string;
}
break;
}
case semantic_tag::base64:
{
decode_base64(s.begin(), s.end(), bytes);
break;
}
case semantic_tag::base64url:
{
decode_base64url(s.begin(), s.end(), bytes);
break;
}
default:
{
ec = conv_errc::not_byte_string;
break;
}
}
return bytes;
}
};
// From integer, Into string
template <class From, class Into>
class value_converter<From, Into,
typename std::enable_if<extension_traits::is_integer<From>::value &&
extension_traits::is_string<Into>::value>::type> : value_converter_base<Into>
{
public:
using allocator_type = typename value_converter_base<Into>::allocator_type;
Into convert(From value, semantic_tag, std::error_code&)
{
Into s(this->get_allocator());
jsoncons::detail::from_integer(value, s);
return s;
}
};
// From integer, Into string
template <class From, class Into>
class value_converter<From, Into,
typename std::enable_if<std::is_floating_point<From>::value &&
extension_traits::is_string<Into>::value>::type> : value_converter_base<Into>
{
public:
using allocator_type = typename value_converter_base<Into>::allocator_type;
Into convert(From value, semantic_tag, std::error_code&)
{
Into s(this->get_allocator());
jsoncons::detail::write_double f{float_chars_format::general,0};
f(value, s);
return s;
}
};
// From half, Into string
template <class Into>
class value_converter<half_arg_t, Into,
typename std::enable_if<extension_traits::is_string<Into>::value>::type> : value_converter_base<Into>
{
public:
using allocator_type = typename value_converter_base<Into>::allocator_type;
Into convert(uint16_t value, semantic_tag, std::error_code&)
{
Into s(this->get_allocator());
jsoncons::detail::write_double f{float_chars_format::general,0};
double x = binary::decode_half(value);
f(x, s);
return s;
}
};
// From bool, Into string
template <class From, class Into>
class value_converter<From, Into,
typename std::enable_if<extension_traits::is_bool<From>::value &&
extension_traits::is_string<Into>::value>::type> : value_converter_base<Into>
{
public:
using allocator_type = typename value_converter_base<Into>::allocator_type;
using char_type = typename Into::value_type;
JSONCONS_CPP14_CONSTEXPR
Into convert(From value, semantic_tag, std::error_code&)
{
constexpr const char_type* true_constant = JSONCONS_CSTRING_CONSTANT(char_type,"true");
constexpr const char_type* false_constant = JSONCONS_CSTRING_CONSTANT(char_type,"false");
return value ? Into(true_constant,4) : Into(false_constant,5);
}
};
// From null, Into string
template <class Into>
class value_converter<null_type, Into, void> : value_converter_base<Into>
{
public:
using allocator_type = typename value_converter_base<Into>::allocator_type;
using char_type = typename Into::value_type;
JSONCONS_CPP14_CONSTEXPR
Into convert(semantic_tag, std::error_code&)
{
constexpr const char_type* null_constant = JSONCONS_CSTRING_CONSTANT(char_type,"null");
return Into(null_constant,4);
}
};
} // namespace jsoncons
#endif

View file

@ -0,0 +1,23 @@
// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_BSON_BSON_HPP
#define JSONCONS_BSON_BSON_HPP
#include <string>
#include <vector>
#include <memory>
#include <type_traits> // std::enable_if
#include <istream> // std::basic_istream
#include <jsoncons/json.hpp>
#include <jsoncons/config/jsoncons_config.hpp>
#include <jsoncons_ext/bson/bson_encoder.hpp>
#include <jsoncons_ext/bson/bson_reader.hpp>
#include <jsoncons_ext/bson/bson_cursor.hpp>
#include <jsoncons_ext/bson/encode_bson.hpp>
#include <jsoncons_ext/bson/decode_bson.hpp>
#endif

View file

@ -0,0 +1,320 @@
// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_BSON_BSON_CURSOR_HPP
#define JSONCONS_BSON_BSON_CURSOR_HPP
#include <memory> // std::allocator
#include <string>
#include <vector>
#include <stdexcept>
#include <system_error>
#include <ios>
#include <istream> // std::basic_istream
#include <jsoncons/byte_string.hpp>
#include <jsoncons/config/jsoncons_config.hpp>
#include <jsoncons/json_visitor.hpp>
#include <jsoncons/json_exception.hpp>
#include <jsoncons/staj_cursor.hpp>
#include <jsoncons/source.hpp>
#include <jsoncons_ext/bson/bson_parser.hpp>
namespace jsoncons {
namespace bson {
template<class Source=jsoncons::binary_stream_source,class Allocator=std::allocator<char>>
class basic_bson_cursor : public basic_staj_cursor<char>, private virtual ser_context
{
using super_type = basic_staj_cursor<char>;
public:
using source_type = Source;
using char_type = char;
using allocator_type = Allocator;
private:
basic_bson_parser<Source,Allocator> parser_;
basic_staj_visitor<char_type> cursor_visitor_;
bool eof_;
// Noncopyable and nonmoveable
basic_bson_cursor(const basic_bson_cursor&) = delete;
basic_bson_cursor& operator=(const basic_bson_cursor&) = delete;
public:
using string_view_type = string_view;
template <class Sourceable>
basic_bson_cursor(Sourceable&& source,
const bson_decode_options& options = bson_decode_options(),
const Allocator& alloc = Allocator())
: parser_(std::forward<Sourceable>(source), options, alloc),
cursor_visitor_(accept_all),
eof_(false)
{
if (!done())
{
next();
}
}
// Constructors that set parse error codes
template <class Sourceable>
basic_bson_cursor(Sourceable&& source,
std::error_code& ec)
: basic_bson_cursor(std::allocator_arg, Allocator(),
std::forward<Sourceable>(source),
bson_decode_options(),
ec)
{
}
template <class Sourceable>
basic_bson_cursor(Sourceable&& source,
const bson_decode_options& options,
std::error_code& ec)
: basic_bson_cursor(std::allocator_arg, Allocator(),
std::forward<Sourceable>(source),
options,
ec)
{
}
template <class Sourceable>
basic_bson_cursor(std::allocator_arg_t, const Allocator& alloc,
Sourceable&& source,
const bson_decode_options& options,
std::error_code& ec)
: parser_(std::forward<Sourceable>(source), options, alloc),
cursor_visitor_(accept_all),
eof_(false)
{
if (!done())
{
next(ec);
}
}
void reset()
{
parser_.reset();
cursor_visitor_.reset();
eof_ = false;
if (!done())
{
next();
}
}
template <class Sourceable>
void reset(Sourceable&& source)
{
parser_.reset(std::forward<Sourceable>(source));
cursor_visitor_.reset();
eof_ = false;
if (!done())
{
next();
}
}
void reset(std::error_code& ec)
{
parser_.reset();
cursor_visitor_.reset();
eof_ = false;
if (!done())
{
next(ec);
}
}
template <class Sourceable>
void reset(Sourceable&& source, std::error_code& ec)
{
parser_.reset(std::forward<Sourceable>(source));
cursor_visitor_.reset();
eof_ = false;
if (!done())
{
next(ec);
}
}
bool done() const override
{
return parser_.done();
}
void array_expected(std::error_code& ec) override
{
if (cursor_visitor_.event().event_type() == staj_event_type::begin_object)
{
parser_.array_expected(cursor_visitor_, ec);
}
else
{
super_type::array_expected(ec);
}
}
const staj_event& current() const override
{
return cursor_visitor_.event();
}
void read_to(basic_json_visitor<char_type>& visitor) override
{
std::error_code ec;
read_to(visitor, ec);
if (ec)
{
JSONCONS_THROW(ser_error(ec,parser_.line(),parser_.column()));
}
}
void read_to(basic_json_visitor<char_type>& visitor,
std::error_code& ec) override
{
if (send_json_event(cursor_visitor_.event(), visitor, *this, ec))
{
read_next(visitor, ec);
}
}
void next() override
{
std::error_code ec;
next(ec);
if (ec)
{
JSONCONS_THROW(ser_error(ec,parser_.line(),parser_.column()));
}
}
void next(std::error_code& ec) override
{
read_next(ec);
}
const ser_context& context() const override
{
return *this;
}
bool eof() const
{
return eof_;
}
std::size_t line() const override
{
return parser_.line();
}
std::size_t column() const override
{
return parser_.column();
}
friend
staj_filter_view operator|(basic_bson_cursor& cursor,
std::function<bool(const staj_event&, const ser_context&)> pred)
{
return staj_filter_view(cursor, pred);
}
#if !defined(JSONCONS_NO_DEPRECATED)
template <class Sourceable>
JSONCONS_DEPRECATED_MSG("Instead, use pipe syntax for filter")
basic_bson_cursor(Sourceable&& source,
std::function<bool(const staj_event&, const ser_context&)> filter,
std::error_code& ec)
: basic_bson_cursor(std::allocator_arg, Allocator(),
std::forward<Sourceable>(source), filter, ec)
{
}
template <class Sourceable>
JSONCONS_DEPRECATED_MSG("Instead, use pipe syntax for filter")
basic_bson_cursor(Sourceable&& source,
std::function<bool(const staj_event&, const ser_context&)> filter,
const bson_decode_options& options = bson_decode_options(),
const Allocator& alloc = Allocator())
: parser_(std::forward<Sourceable>(source), options, alloc),
cursor_visitor_(filter),
eof_(false)
{
if (!done())
{
next();
}
}
template <class Sourceable>
JSONCONS_DEPRECATED_MSG("Instead, use pipe syntax for filter")
basic_bson_cursor(std::allocator_arg_t, const Allocator& alloc,
Sourceable&& source,
std::function<bool(const staj_event&, const ser_context&)> filter,
std::error_code& ec)
: parser_(std::forward<Sourceable>(source),alloc),
cursor_visitor_(filter),
eof_(false)
{
if (!done())
{
next(ec);
}
}
JSONCONS_DEPRECATED_MSG("Instead, use read_to(basic_json_visitor<char_type>&)")
void read(basic_json_visitor<char_type>& visitor)
{
read_to(visitor);
}
JSONCONS_DEPRECATED_MSG("Instead, use read_to(basic_json_visitor<char_type>&, std::error_code&)")
void read(basic_json_visitor<char_type>& visitor,
std::error_code& ec)
{
read_to(visitor, ec);
}
#endif
private:
static bool accept_all(const staj_event&, const ser_context&)
{
return true;
}
void read_next(std::error_code& ec)
{
parser_.restart();
while (!parser_.stopped())
{
parser_.parse(cursor_visitor_, ec);
if (ec) return;
}
}
void read_next(basic_json_visitor<char_type>& visitor, std::error_code& ec)
{
parser_.restart();
while (!parser_.stopped())
{
parser_.parse(visitor, ec);
if (ec) return;
}
}
};
using bson_stream_cursor = basic_bson_cursor<jsoncons::binary_stream_source>;
using bson_bytes_cursor = basic_bson_cursor<jsoncons::bytes_source>;
} // namespace bson
} // namespace jsoncons
#endif

View file

@ -0,0 +1,865 @@
#ifndef JSONCONS_BSON_BSON_DECIMAL128_HPP
#define JSONCONS_BSON_BSON_DECIMAL128_HPP
/*
* Implements decimal128_to_chars and decimal128_from_chars
*
* Based on the libjson functions bson_decimal128_to_string
* and bson_decimal128_from_string_w_len, available at
* https://github.com/mongodb/mongo-c-driver/blob/master/src/libbson/src/bson/bson-decimal128.h
* and https://github.com/mongodb/mongo-c-driver/blob/master/src/libbson/src/bson/bson-decimal128.c
*
*/
/*
* Copyright 2015 MongoDB, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdlib.h>
#include <string.h>
#include <cstring>
#include <ctype.h>
#include <system_error>
#include <algorithm>
#include <jsoncons/config/jsoncons_config.hpp>
namespace jsoncons { namespace bson {
struct decimal128_to_chars_result
{
char* ptr;
std::errc ec;
};
struct decimal128_from_chars_result
{
const char* ptr;
std::errc ec;
};
/**
* BSON_DECIMAL128_STRING:
*
* The length of a decimal128 string (with null terminator).
*
* 1 for the sign
* 35 for digits and radix
* 2 for exponent indicator and sign
* 4 for exponent digits
*/
#define BSON_DECIMAL128_STRING 43
struct TP1
{
uint64_t low;
uint64_t high;
constexpr TP1() : low(0), high(0) {}
constexpr TP1(uint64_t hi, uint64_t lo) : low(lo), high(hi) {}
};
struct TP2
{
uint64_t high;
uint64_t low;
constexpr TP2() : high(0), low(0) {}
constexpr TP2(uint64_t hi, uint64_t lo) : high(hi), low(lo) {}
};
typedef std::conditional<
jsoncons::endian::native == jsoncons::endian::little,
TP1,
TP2
>::type decimal128_t;
inline
bool operator==(const decimal128_t& lhs, const decimal128_t& rhs)
{
return lhs.high == rhs.high && lhs.low == rhs.low;
}
inline
bool operator!=(const decimal128_t& lhs, const decimal128_t& rhs)
{
return !(lhs == rhs);
}
struct decimal128_limits
{
// The length of a decimal128 string (without null terminator).
//
// 1 for the sign
// 35 for digits and radix
// 2 for exponent indicator and sign
// 4 for exponent digits
static constexpr int buf_size = 42;
static constexpr int exponent_max = 6111;
static constexpr int exponent_min = -6176;
static constexpr int exponent_bias = 6176;
static constexpr int max_digits = 34;
static constexpr decimal128_t nan() {return decimal128_t(0x7c00000000000000ull, 0);}
static constexpr decimal128_t infinity() {return decimal128_t(0x7800000000000000ull, 0);}
static constexpr decimal128_t neg_infinity() {return decimal128_t(0x7800000000000000ull + 0x8000000000000000ull, 0);}
};
inline
bool is_nan(decimal128_t dec) { return dec == decimal128_limits::nan(); }
inline
bool is_inf(decimal128_t dec) { return dec == decimal128_limits::infinity(); }
inline
bool is_neg_inf(decimal128_t dec) { return dec == decimal128_limits::neg_infinity(); }
/**
* bson_uint128_t:
*
* This struct represents a 128 bit integer.
*/
typedef struct {
uint32_t parts[4]; /* 32-bit words stored high to low. */
} bson_uint128_t;
typedef struct {
uint64_t high, low;
} bson_uint128_6464_t;
namespace detail {
/**
*------------------------------------------------------------------------------
*
* bson_uint128_divide1B --
*
* This function divides a #bson_uint128_t by 1000000000 (1 billion) and
* computes the quotient and remainder.
*
* The remainder will contain 9 decimal digits for conversion to string.
*
* @value The #bson_uint128_t operand.
* @quotient A pointer to store the #bson_uint128_t quotient.
* @rem A pointer to store the #uint64_t remainder.
*
* Returns:
* The quotient at @quotient and the remainder at @rem.
*
* Side effects:
* None.
*
*------------------------------------------------------------------------------
*/
inline
void bson_uint128_divide1B (bson_uint128_t value, /* IN */
bson_uint128_t *quotient, /* OUT */
uint32_t *rem) /* OUT */
{
const uint32_t DIVISOR = 1000 * 1000 * 1000;
uint64_t _rem = 0;
int i = 0;
if (!value.parts[0] && !value.parts[1] && !value.parts[2] &&
!value.parts[3]) {
*quotient = value;
*rem = 0;
return;
}
for (i = 0; i <= 3; i++) {
_rem <<= 32; /* Adjust remainder to match value of next dividend */
_rem += value.parts[i]; /* Add the divided to _rem */
value.parts[i] = (uint32_t) (_rem / DIVISOR);
_rem %= DIVISOR; /* Store the remainder */
}
*quotient = value;
*rem = (uint32_t) _rem;
}
/**
*-------------------------------------------------------------------------
*
* mul64x64 --
*
* This function multiplies two &uint64_t into a &bson_uint128_6464_t.
*
* Returns:
* The product of @left and @right.
*
* Side Effects:
* None.
*
*-------------------------------------------------------------------------
*/
inline
void mul_64x64 (uint64_t left, /* IN */
uint64_t right, /* IN */
bson_uint128_6464_t *product) /* OUT */
{
uint64_t left_high, left_low, right_high, right_low, product_high,
product_mid, product_mid2, product_low;
bson_uint128_6464_t rt = {0,0};
if (!left && !right) {
*product = rt;
return;
}
left_high = left >> 32;
left_low = (uint32_t) left;
right_high = right >> 32;
right_low = (uint32_t) right;
product_high = left_high * right_high;
product_mid = left_high * right_low;
product_mid2 = left_low * right_high;
product_low = left_low * right_low;
product_high += product_mid >> 32;
product_mid = (uint32_t) product_mid + product_mid2 + (product_low >> 32);
product_high = product_high + (product_mid >> 32);
product_low = (product_mid << 32) + (uint32_t) product_low;
rt.high = product_high;
rt.low = product_low;
*product = rt;
}
/**
*------------------------------------------------------------------------------
*
* dec128_tolower --
*
* This function converts the ASCII character @c to lowercase. It is locale
* insensitive (unlike the stdlib tolower).
*
* Returns:
* The lowercased character.
*/
inline
char dec128_tolower (char c)
{
if (isupper (c)) {
c += 32;
}
return c;
}
/**
*------------------------------------------------------------------------------
*
* dec128_istreq --
*
* This function compares the null-terminated *ASCII* strings @a and @b
* for case-insensitive equality.
*
* Returns:
* true if the strings are equal, false otherwise.
*/
inline
bool dec128_istreq (const char* a, const char* lasta,
const char* b, const char* lastb)
{
while (!(a == lasta && b == lastb))
{
// strings are different lengths
if (a == lasta || b == lastb)
{
return false;
}
if (dec128_tolower (*a) != dec128_tolower (*b)) {
return false;
}
a++;
b++;
}
return true;
}
} // namespace detail
/**
*------------------------------------------------------------------------------
*
* decimal128_to_chars --
*
* This function converts a BID formatted decimal128 value to string,
* accepting a &decimal128_t as @dec. The string is stored at @str.
*
* @dec : The BID formatted decimal to convert.
* @str : The output decimal128 string. At least %BSON_DECIMAL128_STRING
*characters.
*
* Returns:
* None.
*
* Side effects:
* None.
*
*------------------------------------------------------------------------------
*/
inline
decimal128_to_chars_result decimal128_to_chars(char* first, char* last, const decimal128_t& dec)
{
const std::string bson_decimal128_inf = "Infinity";
const std::string bson_decimal128_nan = "NaN";
const uint32_t combination_mask = 0x1f; /* Extract least significant 5 bits */
const uint32_t exponent_mask = 0x3fff; /* Extract least significant 14 bits */
const uint32_t combination_infinity = 30; /* Value of combination field for Inf */
const uint32_t combination_nan = 31; /* Value of combination field for NaN */
const uint32_t exponent_bias = 6176; /* decimal128 exponent bias */
char* str_out = first; /* output pointer in string */
char significand_str[35]; /* decoded significand digits */
/* Note: bits in this routine are referred to starting at 0, */
/* from the sign bit, towards the coefficient. */
uint32_t high; /* bits 0 - 31 */
uint32_t midh; /* bits 32 - 63 */
uint32_t midl; /* bits 64 - 95 */
uint32_t low; /* bits 96 - 127 */
uint32_t combination; /* bits 1 - 5 */
uint32_t biased_exponent; /* decoded biased exponent (14 bits) */
uint32_t significand_digits = 0; /* the number of significand digits */
uint32_t significand[36] = {0}; /* the base-10 digits in the significand */
uint32_t *significand_read = significand; /* read pointer into significand */
int32_t exponent; /* unbiased exponent */
int32_t scientific_exponent; /* the exponent if scientific notation is
* used */
bool is_zero = false; /* true if the number is zero */
uint8_t significand_msb; /* the most signifcant significand bits (50-46) */
bson_uint128_t
significand128; /* temporary storage for significand decoding */
memset (significand_str, 0, sizeof (significand_str));
if ((int64_t) dec.high < 0) { /* negative */
*(str_out++) = '-';
}
low = (uint32_t) dec.low, midl = (uint32_t) (dec.low >> 32),
midh = (uint32_t) dec.high, high = (uint32_t) (dec.high >> 32);
/* Decode combination field and exponent */
combination = (high >> 26) & combination_mask;
if (JSONCONS_UNLIKELY ((combination >> 3) == 3)) {
/* Check for 'special' values */
if (combination == combination_infinity) { /* Infinity */
if (last-str_out >= static_cast<ptrdiff_t >(bson_decimal128_inf.size()))
{
std::memcpy(str_out, bson_decimal128_inf.data(), bson_decimal128_inf.size());
str_out += bson_decimal128_inf.size();
}
*str_out = 0;
//strcpy_s (str_out, last-str_out, bson_decimal128_inf.c_str());
return decimal128_to_chars_result{str_out, std::errc()};
} else if (combination == combination_nan) { /* NaN */
/* first, not str_out, to erase the sign */
str_out = first;
if (last-str_out >= static_cast<ptrdiff_t >(bson_decimal128_nan.size()))
{
std::memcpy(str_out, bson_decimal128_nan.data(), bson_decimal128_nan.size());
str_out += bson_decimal128_nan.size();
}
*str_out = 0;
//strcpy_s (first, last-first, bson_decimal128_nan.c_str());
/* we don't care about the NaN payload. */
return decimal128_to_chars_result{str_out, std::errc()};
} else {
biased_exponent = (high >> 15) & exponent_mask;
significand_msb = 0x8 + ((high >> 14) & 0x1);
}
} else {
significand_msb = (high >> 14) & 0x7;
biased_exponent = (high >> 17) & exponent_mask;
}
exponent = biased_exponent - exponent_bias;
/* Create string of significand digits */
/* Convert the 114-bit binary number represented by */
/* (high, midh, midl, low) to at most 34 decimal */
/* digits through modulo and division. */
significand128.parts[0] = (high & 0x3fff) + ((significand_msb & 0xf) << 14);
significand128.parts[1] = midh;
significand128.parts[2] = midl;
significand128.parts[3] = low;
if (significand128.parts[0] == 0 && significand128.parts[1] == 0 &&
significand128.parts[2] == 0 && significand128.parts[3] == 0) {
is_zero = true;
} else if (significand128.parts[0] >= (1 << 17)) {
/* The significand is non-canonical or zero.
* In order to preserve compatibility with the densely packed decimal
* format, the maximum value for the significand of decimal128 is
* 1e34 - 1. If the value is greater than 1e34 - 1, the IEEE 754
* standard dictates that the significand is interpreted as zero.
*/
is_zero = true;
} else {
for (int k = 3; k >= 0; k--) {
uint32_t least_digits = 0;
detail::bson_uint128_divide1B (
significand128, &significand128, &least_digits);
/* We now have the 9 least significant digits (in base 2). */
/* Convert and output to string. */
if (!least_digits) {
continue;
}
for (int j = 8; j >= 0; j--) {
significand[k * 9 + j] = least_digits % 10;
least_digits /= 10;
}
}
}
/* Output format options: */
/* Scientific - [-]d.dddE(+/-)dd or [-]dE(+/-)dd */
/* Regular - ddd.ddd */
if (is_zero) {
significand_digits = 1;
*significand_read = 0;
} else {
significand_digits = 36;
while (!(*significand_read)) {
significand_digits--;
significand_read++;
}
}
scientific_exponent = significand_digits - 1 + exponent;
/* The scientific exponent checks are dictated by the string conversion
* specification and are somewhat arbitrary cutoffs.
*
* We must check exponent > 0, because if this is the case, the number
* has trailing zeros. However, we *cannot* output these trailing zeros,
* because doing so would change the precision of the value, and would
* change stored data if the string converted number is round tripped.
*/
if (scientific_exponent < -6 || exponent > 0) {
/* Scientific format */
*(str_out++) = char(*(significand_read++)) + '0';
significand_digits--;
if (significand_digits) {
*(str_out++) = '.';
}
for (std::size_t i = 0; i < significand_digits && (str_out - first) < 36; i++) {
*(str_out++) = char(*(significand_read++)) + '0';
}
/* Exponent */
*(str_out++) = 'E';
std::string s;
if (scientific_exponent >= 0) {
s.push_back('+');
}
jsoncons::detail::from_integer(scientific_exponent, s);
if (str_out + s.size() < last)
{
std::memcpy(str_out, s.data(), s.size());
}
else
{
return decimal128_to_chars_result{str_out, std::errc::value_too_large};
}
str_out += s.size();
} else {
/* Regular format with no decimal place */
if (exponent >= 0) {
for (std::size_t i = 0; i < significand_digits && (str_out - first) < 36; i++) {
*(str_out++) = char(*(significand_read++)) + '0';
}
} else {
int32_t radix_position = significand_digits + exponent;
if (radix_position > 0) { /* non-zero digits before radix */
for (int32_t i = 0;
i < radix_position && (str_out < last);
i++) {
*(str_out++) = char(*(significand_read++)) + '0';
}
} else { /* leading zero before radix point */
*(str_out++) = '0';
}
*(str_out++) = '.';
while (radix_position++ < 0) { /* add leading zeros after radix */
*(str_out++) = '0';
}
for (std::size_t i = 0;
(i < significand_digits - (std::max) (radix_position - 1, 0)) &&
(str_out < last);
i++) {
*(str_out++) = char(*(significand_read++)) + '0';
}
}
}
return decimal128_to_chars_result{str_out, std::errc()};
}
/**
*------------------------------------------------------------------------------
*
* bson_decimal128_from_string_w_len --
*
* This function converts @string in the format [+-]ddd[.]ddd[E][+-]dddd to
* decimal128. Out of range values are converted to +/-Infinity. Invalid
* strings are converted to NaN. @len is the length of the string, or -1
* meaning the string is null-terminated.
*
* If more digits are provided than the available precision allows,
* round to the nearest expressable decimal128 with ties going to even will
* occur.
*
* Note: @string must be ASCII only!
*
* Returns:
* true on success, or false on failure. @dec will be NaN if @str was invalid
* The &decimal128_t converted from @string at @dec.
*
* Side effects:
* None.
*
*------------------------------------------------------------------------------
*/
inline
decimal128_from_chars_result decimal128_from_chars(const char* first, const char* last, decimal128_t& dec)
{
const string_view inf_str = "inf";
const string_view infinity_str = "infinity";
const string_view nan_str = "nan";
ptrdiff_t len = last - first;
bson_uint128_6464_t significand = {0,0};
const char* str_read = first; /* Read pointer for consuming str. */
/* Parsing state tracking */
bool is_negative = false;
bool saw_radix = false;
bool includes_sign = false; /* True if the input first contains a sign. */
bool found_nonzero = false;
size_t significant_digits = 0; /* Total number of significant digits
* (no leading or trailing zero) */
size_t ndigits_read = 0; /* Total number of significand digits read */
size_t ndigits = 0; /* Total number of digits (no leading zeros) */
size_t radix_position = 0; /* The number of the digits after radix */
size_t first_nonzero = 0; /* The index of the first non-zero in *str* */
uint16_t digits[decimal128_limits::max_digits] = {0};
uint16_t ndigits_stored = 0; /* The number of digits in digits */
uint16_t *digits_insert = digits; /* Insertion pointer for digits */
size_t first_digit = 0; /* The index of the first non-zero digit */
size_t last_digit = 0; /* The index of the last digit */
int32_t exponent = 0;
uint64_t significand_high = 0; /* The high 17 digits of the significand */
uint64_t significand_low = 0; /* The low 17 digits of the significand */
uint16_t biased_exponent = 0; /* The biased exponent */
dec.high = 0;
dec.low = 0;
if (*str_read == '+' || *str_read == '-') {
is_negative = *(str_read++) == '-';
includes_sign = true;
}
/* Check for Infinity or NaN */
if (!isdigit (*str_read) && *str_read != '.') {
if (detail::dec128_istreq (str_read, last, inf_str.data(), inf_str.data()+inf_str.length()) ||
detail::dec128_istreq (str_read, last, infinity_str.data(), infinity_str.data()+infinity_str.length()))
{
dec = is_negative ? decimal128_limits::neg_infinity() : decimal128_limits::infinity();
return decimal128_from_chars_result{str_read,std::errc()};
} else if (detail::dec128_istreq (str_read, last, nan_str.data(), nan_str.data()+nan_str.length())) {
dec = decimal128_limits::nan();
return decimal128_from_chars_result{str_read,std::errc()};
}
dec = decimal128_limits::nan();
return decimal128_from_chars_result{str_read,std::errc::invalid_argument};
}
/* Read digits */
while (((isdigit (*str_read) || *str_read == '.')) &&
(len == -1 || str_read < first + len)) {
if (*str_read == '.') {
if (saw_radix) {
dec = decimal128_limits::nan();
return decimal128_from_chars_result{str_read,std::errc::invalid_argument};
}
saw_radix = true;
str_read++;
continue;
}
if (ndigits_stored < 34) {
if (*str_read != '0' || found_nonzero) {
if (!found_nonzero) {
first_nonzero = ndigits_read;
}
found_nonzero = true;
*(digits_insert++) = *(str_read) - '0'; /* Only store 34 digits */
ndigits_stored++;
}
}
if (found_nonzero) {
ndigits++;
}
if (saw_radix) {
radix_position++;
}
ndigits_read++;
str_read++;
}
if (saw_radix && !ndigits_read) {
dec = decimal128_limits::nan();
return decimal128_from_chars_result{str_read,std::errc::invalid_argument};
}
/* Read exponent if exists */
if (*str_read == 'e' || *str_read == 'E') {
++str_read;
if (*str_read == '+') {
++str_read;
}
auto result = jsoncons::detail::to_integer(str_read, last - str_read, exponent);
if (result.ec != jsoncons::detail::to_integer_errc())
{
dec = decimal128_limits::nan();
return decimal128_from_chars_result{str_read,std::errc::invalid_argument};
}
str_read = result.ptr;
}
if ((len == -1 || str_read < first + len) && *str_read) {
dec = decimal128_limits::nan();
return decimal128_from_chars_result{str_read,std::errc::invalid_argument};
}
/* Done reading input. */
/* Find first non-zero digit in digits */
first_digit = 0;
if (!ndigits_stored) { /* value is zero */
first_digit = 0;
last_digit = 0;
digits[0] = 0;
ndigits = 1;
ndigits_stored = 1;
significant_digits = 0;
} else {
last_digit = ndigits_stored - 1;
significant_digits = ndigits;
/* Mark trailing zeros as non-significant */
while (first[first_nonzero + significant_digits - 1 + includes_sign +
saw_radix] == '0') {
significant_digits--;
}
}
/* Normalization of exponent */
/* Correct exponent based on radix position, and shift significand as needed
*/
/* to represent user input */
/* Overflow prevention */
if (exponent <= static_cast<int32_t>(radix_position) && static_cast<int32_t>(radix_position) - exponent > (1 << 14)) {
exponent = decimal128_limits::exponent_min;
} else {
exponent -= static_cast<int32_t>(radix_position);
}
/* Attempt to normalize the exponent */
while (exponent > decimal128_limits::exponent_max) {
/* Shift exponent to significand and decrease */
last_digit++;
if (last_digit - first_digit > decimal128_limits::max_digits) {
/* The exponent is too great to shift into the significand. */
if (significant_digits == 0) {
/* Value is zero, we are allowed to clamp the exponent. */
exponent = decimal128_limits::exponent_max;
break;
}
/* Overflow is not permitted, error. */
dec = decimal128_limits::nan();
return decimal128_from_chars_result{str_read,std::errc::invalid_argument};
}
exponent--;
}
while (exponent < decimal128_limits::exponent_min || ndigits_stored < ndigits) {
/* Shift last digit */
if (last_digit == 0) {
/* underflow is not allowed, but zero clamping is */
if (significant_digits == 0) {
exponent = decimal128_limits::exponent_min;
break;
}
dec = decimal128_limits::nan();
return decimal128_from_chars_result{str_read,std::errc::invalid_argument};
}
if (ndigits_stored < ndigits) {
if (first[ndigits - 1 + includes_sign + saw_radix] - '0' != 0 &&
significant_digits != 0) {
dec = decimal128_limits::nan();
return decimal128_from_chars_result{str_read,std::errc::invalid_argument};
}
ndigits--; /* adjust to match digits not stored */
} else {
if (digits[last_digit] != 0) {
/* Inexact rounding is not allowed. */
dec = decimal128_limits::nan();
return decimal128_from_chars_result{str_read,std::errc::invalid_argument};
}
last_digit--; /* adjust to round */
}
if (exponent < decimal128_limits::exponent_max) {
exponent++;
} else {
dec = decimal128_limits::nan();
return decimal128_from_chars_result{str_read,std::errc::invalid_argument};
}
}
/* Round */
/* We've normalized the exponent, but might still need to round. */
if (last_digit - first_digit + 1 < significant_digits) {
uint8_t round_digit;
/* There are non-zero digits after last_digit that need rounding. */
/* We round to nearest, ties to even */
round_digit =
first[first_nonzero + last_digit + includes_sign + saw_radix + 1] -
'0';
if (round_digit != 0) {
/* Inexact (non-zero) rounding is not allowed */
dec = decimal128_limits::nan();
return decimal128_from_chars_result{str_read,std::errc::invalid_argument};
}
}
/* Encode significand */
significand_high = 0, /* The high 17 digits of the significand */
significand_low = 0; /* The low 17 digits of the significand */
if (significant_digits == 0) { /* read a zero */
significand_high = 0;
significand_low = 0;
} else if (last_digit - first_digit < 17) {
size_t d_idx = first_digit;
significand_low = digits[d_idx++];
for (; d_idx <= last_digit; d_idx++) {
significand_low *= 10;
significand_low += digits[d_idx];
significand_high = 0;
}
} else {
size_t d_idx = first_digit;
significand_high = digits[d_idx++];
for (; d_idx <= last_digit - 17; d_idx++) {
significand_high *= 10;
significand_high += digits[d_idx];
}
significand_low = digits[d_idx++];
for (; d_idx <= last_digit; d_idx++) {
significand_low *= 10;
significand_low += digits[d_idx];
}
}
detail::mul_64x64 (significand_high, 100000000000000000ull, &significand);
significand.low += significand_low;
if (significand.low < significand_low) {
significand.high += 1;
}
biased_exponent = static_cast<uint16_t>(exponent + static_cast<int32_t>(decimal128_limits::exponent_bias));
/* Encode combination, exponent, and significand. */
if ((significand.high >> 49) & 1) {
/* Encode '11' into bits 1 to 3 */
dec.high |= (0x3ull << 61);
dec.high |= (biased_exponent & 0x3fffull) << 47;
dec.high |= significand.high & 0x7fffffffffffull;
} else {
dec.high |= (biased_exponent & 0x3fffull) << 49;
dec.high |= significand.high & 0x1ffffffffffffull;
}
dec.low = significand.low;
/* Encode sign */
if (is_negative) {
dec.high |= 0x8000000000000000ull;
}
return decimal128_from_chars_result{str_read,std::errc()};
}
} // namespace bson
} // namespace jsoncons
#endif

View file

@ -0,0 +1,585 @@
// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_BSON_BSON_ENCODER_HPP
#define JSONCONS_BSON_BSON_ENCODER_HPP
#include <string>
#include <vector>
#include <limits> // std::numeric_limits
#include <memory>
#include <utility> // std::move
#include <jsoncons/json_exception.hpp>
#include <jsoncons/json_visitor.hpp>
#include <jsoncons/config/jsoncons_config.hpp>
#include <jsoncons/sink.hpp>
#include <jsoncons/detail/parse_number.hpp>
#include <jsoncons_ext/bson/bson_type.hpp>
#include <jsoncons_ext/bson/bson_error.hpp>
#include <jsoncons_ext/bson/bson_options.hpp>
#include <jsoncons_ext/bson/bson_decimal128.hpp>
#include <jsoncons_ext/bson/bson_oid.hpp>
namespace jsoncons { namespace bson {
template<class Sink=jsoncons::binary_stream_sink,class Allocator=std::allocator<char>>
class basic_bson_encoder final : public basic_json_visitor<char>
{
enum class decimal_parse_state { start, integer, exp1, exp2, fraction1 };
static constexpr int64_t nanos_in_milli = 1000000;
static constexpr int64_t nanos_in_second = 1000000000;
static constexpr int64_t millis_in_second = 1000;
public:
using allocator_type = Allocator;
using char_type = char;
using typename basic_json_visitor<char>::string_view_type;
using sink_type = Sink;
private:
struct stack_item
{
jsoncons::bson::bson_container_type type_;
std::size_t offset_;
std::size_t name_offset_;
std::size_t index_;
stack_item(jsoncons::bson::bson_container_type type, std::size_t offset) noexcept
: type_(type), offset_(offset), name_offset_(0), index_(0)
{
}
std::size_t offset() const
{
return offset_;
}
std::size_t member_offset() const
{
return name_offset_;
}
void member_offset(std::size_t offset)
{
name_offset_ = offset;
}
std::size_t next_index()
{
return index_++;
}
bool is_object() const
{
return type_ == jsoncons::bson::bson_container_type::document;
}
};
sink_type sink_;
const bson_encode_options options_;
allocator_type alloc_;
std::vector<stack_item> stack_;
std::vector<uint8_t> buffer_;
int nesting_depth_;
// Noncopyable and nonmoveable
basic_bson_encoder(const basic_bson_encoder&) = delete;
basic_bson_encoder& operator=(const basic_bson_encoder&) = delete;
public:
explicit basic_bson_encoder(Sink&& sink,
const Allocator& alloc = Allocator())
: basic_bson_encoder(std::forward<Sink>(sink),
bson_encode_options(),
alloc)
{
}
explicit basic_bson_encoder(Sink&& sink,
const bson_encode_options& options,
const Allocator& alloc = Allocator())
: sink_(std::forward<Sink>(sink)),
options_(options),
alloc_(alloc),
nesting_depth_(0)
{
}
~basic_bson_encoder() noexcept
{
sink_.flush();
}
void reset()
{
stack_.clear();
buffer_.clear();
nesting_depth_ = 0;
}
void reset(Sink&& sink)
{
sink_ = std::move(sink);
reset();
}
private:
// Implementing methods
void visit_flush() override
{
sink_.flush();
}
bool visit_begin_object(semantic_tag, const ser_context&, std::error_code& ec) override
{
if (JSONCONS_UNLIKELY(++nesting_depth_ > options_.max_nesting_depth()))
{
ec = bson_errc::max_nesting_depth_exceeded;
return false;
}
if (buffer_.size() > 0)
{
if (stack_.empty())
{
ec = bson_errc::expected_bson_document;
return false;
}
before_value(jsoncons::bson::bson_type::document_type);
}
stack_.emplace_back(jsoncons::bson::bson_container_type::document, buffer_.size());
buffer_.insert(buffer_.end(), sizeof(int32_t), 0);
return true;
}
bool visit_end_object(const ser_context&, std::error_code&) override
{
JSONCONS_ASSERT(!stack_.empty());
--nesting_depth_;
buffer_.push_back(0x00);
std::size_t length = buffer_.size() - stack_.back().offset();
binary::native_to_little(static_cast<uint32_t>(length), buffer_.begin()+stack_.back().offset());
stack_.pop_back();
if (stack_.empty())
{
for (auto c : buffer_)
{
sink_.push_back(c);
}
}
return true;
}
bool visit_begin_array(semantic_tag, const ser_context&, std::error_code& ec) override
{
if (JSONCONS_UNLIKELY(++nesting_depth_ > options_.max_nesting_depth()))
{
ec = bson_errc::max_nesting_depth_exceeded;
return false;
}
if (buffer_.size() > 0)
{
if (stack_.empty())
{
ec = bson_errc::expected_bson_document;
return false;
}
before_value(jsoncons::bson::bson_type::array_type);
}
stack_.emplace_back(jsoncons::bson::bson_container_type::array, buffer_.size());
buffer_.insert(buffer_.end(), sizeof(int32_t), 0);
return true;
}
bool visit_end_array(const ser_context&, std::error_code&) override
{
JSONCONS_ASSERT(!stack_.empty());
--nesting_depth_;
buffer_.push_back(0x00);
std::size_t length = buffer_.size() - stack_.back().offset();
binary::native_to_little(static_cast<uint32_t>(length), buffer_.begin()+stack_.back().offset());
stack_.pop_back();
if (stack_.empty())
{
for (auto c : buffer_)
{
sink_.push_back(c);
}
}
return true;
}
bool visit_key(const string_view_type& name, const ser_context&, std::error_code&) override
{
stack_.back().member_offset(buffer_.size());
buffer_.push_back(0x00); // reserve space for code
for (auto c : name)
{
buffer_.push_back(c);
}
buffer_.push_back(0x00);
return true;
}
bool visit_null(semantic_tag tag, const ser_context&, std::error_code& ec) override
{
if (stack_.empty())
{
ec = bson_errc::expected_bson_document;
return false;
}
switch (tag)
{
case semantic_tag::undefined:
before_value(jsoncons::bson::bson_type::undefined_type);
break;
default:
before_value(jsoncons::bson::bson_type::null_type);
break;
}
return true;
}
bool visit_bool(bool val, semantic_tag, const ser_context&, std::error_code& ec) override
{
if (stack_.empty())
{
ec = bson_errc::expected_bson_document;
return false;
}
before_value(jsoncons::bson::bson_type::bool_type);
if (val)
{
buffer_.push_back(0x01);
}
else
{
buffer_.push_back(0x00);
}
return true;
}
bool visit_string(const string_view_type& sv, semantic_tag tag, const ser_context&, std::error_code& ec) override
{
if (stack_.empty())
{
ec = bson_errc::expected_bson_document;
return false;
}
switch (tag)
{
case semantic_tag::float128:
{
before_value(jsoncons::bson::bson_type::decimal128_type);
decimal128_t dec;
auto rc = decimal128_from_chars(sv.data(), sv.data()+sv.size(), dec);
if (rc.ec != std::errc())
{
ec = bson_errc::invalid_decimal128_string;
return false;
}
binary::native_to_little(dec.low,std::back_inserter(buffer_));
binary::native_to_little(dec.high,std::back_inserter(buffer_));
break;
}
case semantic_tag::id:
{
before_value(jsoncons::bson::bson_type::object_id_type);
oid_t oid(sv);
for (auto b : oid)
{
buffer_.push_back(b);
}
break;
}
case semantic_tag::regex:
{
before_value(jsoncons::bson::bson_type::regex_type);
std::size_t first = sv.find_first_of('/');
std::size_t last = sv.find_last_of('/');
if (first == string_view::npos || last == string_view::npos || first == last)
{
ec = bson_errc::invalid_regex_string;
return false;
}
string_view regex = sv.substr(first+1,last-1);
for (auto c : regex)
{
buffer_.push_back(c);
}
buffer_.push_back(0x00);
string_view options = sv.substr(last+1);
for (auto c : options)
{
buffer_.push_back(c);
}
buffer_.push_back(0x00);
break;
}
default:
switch (tag)
{
case semantic_tag::code:
before_value(jsoncons::bson::bson_type::javascript_type);
break;
default:
before_value(jsoncons::bson::bson_type::string_type);
break;
}
std::size_t offset = buffer_.size();
buffer_.insert(buffer_.end(), sizeof(int32_t), 0);
std::size_t string_offset = buffer_.size();
auto sink = unicode_traits::validate(sv.data(), sv.size());
if (sink.ec != unicode_traits::conv_errc())
{
ec = bson_errc::invalid_utf8_text_string;
return false;
}
for (auto c : sv)
{
buffer_.push_back(c);
}
buffer_.push_back(0x00);
std::size_t length = buffer_.size() - string_offset;
binary::native_to_little(static_cast<uint32_t>(length), buffer_.begin()+offset);
break;
}
return true;
}
bool visit_byte_string(const byte_string_view& b,
semantic_tag,
const ser_context&,
std::error_code& ec) override
{
if (stack_.empty())
{
ec = bson_errc::expected_bson_document;
return false;
}
before_value(jsoncons::bson::bson_type::binary_type);
std::size_t offset = buffer_.size();
buffer_.insert(buffer_.end(), sizeof(int32_t), 0);
std::size_t string_offset = buffer_.size();
buffer_.push_back(0x80); // default subtype
for (auto c : b)
{
buffer_.push_back(c);
}
std::size_t length = buffer_.size() - string_offset - 1;
binary::native_to_little(static_cast<uint32_t>(length), buffer_.begin()+offset);
return true;
}
bool visit_byte_string(const byte_string_view& b,
uint64_t ext_tag,
const ser_context&,
std::error_code& ec) override
{
if (stack_.empty())
{
ec = bson_errc::expected_bson_document;
return false;
}
before_value(jsoncons::bson::bson_type::binary_type);
std::size_t offset = buffer_.size();
buffer_.insert(buffer_.end(), sizeof(int32_t), 0);
std::size_t string_offset = buffer_.size();
buffer_.push_back(static_cast<uint8_t>(ext_tag)); // default subtype
for (auto c : b)
{
buffer_.push_back(c);
}
std::size_t length = buffer_.size() - string_offset - 1;
binary::native_to_little(static_cast<uint32_t>(length), buffer_.begin()+offset);
return true;
}
bool visit_int64(int64_t val,
semantic_tag tag,
const ser_context&,
std::error_code& ec) override
{
static constexpr int64_t min_value_div_1000 = (std::numeric_limits<int64_t>::min)() / 1000;
static constexpr int64_t max_value_div_1000 = (std::numeric_limits<int64_t>::max)() / 1000;
if (stack_.empty())
{
ec = bson_errc::expected_bson_document;
return false;
}
switch (tag)
{
case semantic_tag::epoch_second:
if (val < min_value_div_1000)
{
ec = bson_errc::datetime_too_small;
return false;
}
if (val > max_value_div_1000)
{
ec = bson_errc::datetime_too_large;
return false;
}
before_value(jsoncons::bson::bson_type::datetime_type);
binary::native_to_little(val*millis_in_second,std::back_inserter(buffer_));
return true;
case semantic_tag::epoch_milli:
before_value(jsoncons::bson::bson_type::datetime_type);
binary::native_to_little(val,std::back_inserter(buffer_));
return true;
case semantic_tag::epoch_nano:
before_value(jsoncons::bson::bson_type::datetime_type);
if (val != 0)
{
val /= nanos_in_milli;
}
binary::native_to_little(static_cast<int64_t>(val),std::back_inserter(buffer_));
return true;
default:
{
if (val >= (std::numeric_limits<int32_t>::lowest)() && val <= (std::numeric_limits<int32_t>::max)())
{
before_value(jsoncons::bson::bson_type::int32_type);
binary::native_to_little(static_cast<uint32_t>(val),std::back_inserter(buffer_));
}
else
{
before_value(jsoncons::bson::bson_type::int64_type);
binary::native_to_little(static_cast<int64_t>(val),std::back_inserter(buffer_));
}
return true;
}
}
}
bool visit_uint64(uint64_t val,
semantic_tag tag,
const ser_context&,
std::error_code& ec) override
{
static constexpr uint64_t max_value_div_1000 = (std::numeric_limits<uint64_t>::max)() / 1000;
if (stack_.empty())
{
ec = bson_errc::expected_bson_document;
return false;
}
switch (tag)
{
case semantic_tag::epoch_second:
if (val > max_value_div_1000)
{
ec = bson_errc::datetime_too_large;
return false;
}
before_value(jsoncons::bson::bson_type::datetime_type);
binary::native_to_little(static_cast<int64_t>(val*millis_in_second),std::back_inserter(buffer_));
return true;
case semantic_tag::epoch_milli:
before_value(jsoncons::bson::bson_type::datetime_type);
binary::native_to_little(static_cast<int64_t>(val),std::back_inserter(buffer_));
return true;
case semantic_tag::epoch_nano:
before_value(jsoncons::bson::bson_type::datetime_type);
if (val != 0)
{
val /= nanos_in_second;
}
binary::native_to_little(static_cast<int64_t>(val),std::back_inserter(buffer_));
return true;
default:
{
bool more;
if (val <= static_cast<uint64_t>((std::numeric_limits<int32_t>::max)()))
{
before_value(jsoncons::bson::bson_type::int32_type);
binary::native_to_little(static_cast<uint32_t>(val),std::back_inserter(buffer_));
more = true;
}
else if (val <= static_cast<uint64_t>((std::numeric_limits<int64_t>::max)()))
{
before_value(jsoncons::bson::bson_type::int64_type);
binary::native_to_little(static_cast<uint64_t>(val),std::back_inserter(buffer_));
more = true;
}
else
{
ec = bson_errc::number_too_large;
more = false;
}
return more;
}
}
}
bool visit_double(double val,
semantic_tag,
const ser_context&,
std::error_code& ec) override
{
if (stack_.empty())
{
ec = bson_errc::expected_bson_document;
return false;
}
before_value(jsoncons::bson::bson_type::double_type);
binary::native_to_little(val,std::back_inserter(buffer_));
return true;
}
void before_value(uint8_t code)
{
JSONCONS_ASSERT(!stack_.empty());
if (stack_.back().is_object())
{
buffer_[stack_.back().member_offset()] = code;
}
else
{
buffer_.push_back(code);
std::string name = std::to_string(stack_.back().next_index());
buffer_.insert(buffer_.end(), name.begin(), name.end());
buffer_.push_back(0x00);
}
}
};
using bson_stream_encoder = basic_bson_encoder<jsoncons::binary_stream_sink>;
using bson_bytes_encoder = basic_bson_encoder<jsoncons::bytes_sink<std::vector<uint8_t>>>;
#if !defined(JSONCONS_NO_DEPRECATED)
template<class Sink=jsoncons::binary_stream_sink>
using basic_bson_serializer = basic_bson_encoder<Sink>;
JSONCONS_DEPRECATED_MSG("Instead, use bson_stream_encoder") typedef bson_stream_encoder bson_encoder;
JSONCONS_DEPRECATED_MSG("Instead, use bson_stream_encoder") typedef bson_stream_encoder bson_serializer;
JSONCONS_DEPRECATED_MSG("Instead, use bson_bytes_encoder") typedef bson_bytes_encoder bson_buffer_serializer;
#endif
}}
#endif

View file

@ -0,0 +1,103 @@
/// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_BSON_BSON_ERROR_HPP
#define JSONCONS_BSON_BSON_ERROR_HPP
#include <system_error>
#include <jsoncons/config/jsoncons_config.hpp>
namespace jsoncons { namespace bson {
enum class bson_errc
{
success = 0,
unexpected_eof = 1,
source_error,
invalid_utf8_text_string,
max_nesting_depth_exceeded,
string_length_is_non_positive,
length_is_negative,
number_too_large,
invalid_decimal128_string,
datetime_too_small,
datetime_too_large,
expected_bson_document,
invalid_regex_string,
size_mismatch,
unknown_type
};
class bson_error_category_impl
: public std::error_category
{
public:
const char* name() const noexcept override
{
return "jsoncons/bson";
}
std::string message(int ev) const override
{
switch (static_cast<bson_errc>(ev))
{
case bson_errc::unexpected_eof:
return "Unexpected end of file";
case bson_errc::source_error:
return "Source error";
case bson_errc::invalid_utf8_text_string:
return "Illegal UTF-8 encoding in text string";
case bson_errc::max_nesting_depth_exceeded:
return "Data item nesting exceeds limit in options";
case bson_errc::string_length_is_non_positive:
return "Request for the length of a string returned a non-positive result";
case bson_errc::length_is_negative:
return "Request for the length of a binary returned a negative result";
case bson_errc::unknown_type:
return "An unknown type was found in the stream";
case bson_errc::number_too_large:
return "Number too large";
case bson_errc::invalid_decimal128_string:
return "Invalid decimal128 string";
case bson_errc::datetime_too_large:
return "datetime too large";
case bson_errc::datetime_too_small:
return "datetime too small";
case bson_errc::expected_bson_document:
return "Expected BSON document";
case bson_errc::invalid_regex_string:
return "Invalid regex string";
case bson_errc::size_mismatch:
return "Document or array size doesn't match bytes read";
default:
return "Unknown BSON parser error";
}
}
};
inline
const std::error_category& bson_error_category()
{
static bson_error_category_impl instance;
return instance;
}
inline
std::error_code make_error_code(bson_errc result)
{
return std::error_code(static_cast<int>(result),bson_error_category());
}
}}
namespace std {
template<>
struct is_error_code_enum<jsoncons::bson::bson_errc> : public true_type
{
};
}
#endif

View file

@ -0,0 +1,245 @@
#ifndef JSONCONS_BSON_BSON_OID_HPP
#define JSONCONS_BSON_BSON_OID_HPP
/*
* Implements class oid_t and non member function bson_oid_to_string
*
* Based on the libjson functions bson_oid_to_string
* and bson_oid_init_from_string_unsafe , available at
* https://github.com/mongodb/mongo-c-driver/blob/master/src/libbson/src/bson/bson-oid.h
* and https://github.com/mongodb/mongo-c-driver/blob/master/src/libbson/src/bson/bson-oid.c
*
*/
/*
* Copyright 2015 MongoDB, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <cstdlib>
#include <cstring>
#include <ctype.h>
#include <system_error>
#include <algorithm>
#include <string>
#include <type_traits>
#include <array>
#include <jsoncons/config/jsoncons_config.hpp>
namespace jsoncons { namespace bson {
class oid_t
{
std::array<uint8_t,12> bytes_;
public:
using iterator = std::array<uint8_t,12>::iterator;
using const_iterator = std::array<uint8_t,12>::const_iterator;
oid_t(const std::array<uint8_t,12>& bytes)
: bytes_(bytes)
{
}
oid_t(uint8_t data[12])
{
std::memcpy(bytes_.data(),data,12);
}
oid_t(const string_view& str)
{
for (std::size_t i = 0; i < bytes_.size(); i++)
{
bytes_[i] = ((parse_hex_char (str[2 * i]) << 4) |
(parse_hex_char (str[2 * i + 1])));
}
}
const uint8_t* data() const
{
return bytes_.data();
}
std::size_t size() const
{
return bytes_.size();
}
iterator begin()
{
return bytes_.begin();
}
iterator end()
{
return bytes_.end();
}
const_iterator begin() const
{
return bytes_.begin();
}
const_iterator end() const
{
return bytes_.end();
}
private:
static uint8_t parse_hex_char (char hex)
{
switch (hex) {
case '0':
return 0;
case '1':
return 1;
case '2':
return 2;
case '3':
return 3;
case '4':
return 4;
case '5':
return 5;
case '6':
return 6;
case '7':
return 7;
case '8':
return 8;
case '9':
return 9;
case 'a':
case 'A':
return 0xa;
case 'b':
case 'B':
return 0xb;
case 'c':
case 'C':
return 0xc;
case 'd':
case 'D':
return 0xd;
case 'e':
case 'E':
return 0xe;
case 'f':
case 'F':
return 0xf;
default:
return 0;
}
}
};
namespace detail {
inline
const uint16_t* get_hex_char_pairs(std::true_type) // big endian
{
static const uint16_t hex_char_pairs[] = {
12336, 12337, 12338, 12339, 12340, 12341, 12342, 12343, 12344, 12345, 12385,
12386, 12387, 12388, 12389, 12390, 12592, 12593, 12594, 12595, 12596, 12597,
12598, 12599, 12600, 12601, 12641, 12642, 12643, 12644, 12645, 12646, 12848,
12849, 12850, 12851, 12852, 12853, 12854, 12855, 12856, 12857, 12897, 12898,
12899, 12900, 12901, 12902, 13104, 13105, 13106, 13107, 13108, 13109, 13110,
13111, 13112, 13113, 13153, 13154, 13155, 13156, 13157, 13158, 13360, 13361,
13362, 13363, 13364, 13365, 13366, 13367, 13368, 13369, 13409, 13410, 13411,
13412, 13413, 13414, 13616, 13617, 13618, 13619, 13620, 13621, 13622, 13623,
13624, 13625, 13665, 13666, 13667, 13668, 13669, 13670, 13872, 13873, 13874,
13875, 13876, 13877, 13878, 13879, 13880, 13881, 13921, 13922, 13923, 13924,
13925, 13926, 14128, 14129, 14130, 14131, 14132, 14133, 14134, 14135, 14136,
14137, 14177, 14178, 14179, 14180, 14181, 14182, 14384, 14385, 14386, 14387,
14388, 14389, 14390, 14391, 14392, 14393, 14433, 14434, 14435, 14436, 14437,
14438, 14640, 14641, 14642, 14643, 14644, 14645, 14646, 14647, 14648, 14649,
14689, 14690, 14691, 14692, 14693, 14694, 24880, 24881, 24882, 24883, 24884,
24885, 24886, 24887, 24888, 24889, 24929, 24930, 24931, 24932, 24933, 24934,
25136, 25137, 25138, 25139, 25140, 25141, 25142, 25143, 25144, 25145, 25185,
25186, 25187, 25188, 25189, 25190, 25392, 25393, 25394, 25395, 25396, 25397,
25398, 25399, 25400, 25401, 25441, 25442, 25443, 25444, 25445, 25446, 25648,
25649, 25650, 25651, 25652, 25653, 25654, 25655, 25656, 25657, 25697, 25698,
25699, 25700, 25701, 25702, 25904, 25905, 25906, 25907, 25908, 25909, 25910,
25911, 25912, 25913, 25953, 25954, 25955, 25956, 25957, 25958, 26160, 26161,
26162, 26163, 26164, 26165, 26166, 26167, 26168, 26169, 26209, 26210, 26211,
26212, 26213, 26214};
return hex_char_pairs;
}
inline
const uint16_t* get_hex_char_pairs(std::false_type) // little endian
{
static const uint16_t hex_char_pairs[] = {
12336, 12592, 12848, 13104, 13360, 13616, 13872, 14128, 14384, 14640, 24880,
25136, 25392, 25648, 25904, 26160, 12337, 12593, 12849, 13105, 13361, 13617,
13873, 14129, 14385, 14641, 24881, 25137, 25393, 25649, 25905, 26161, 12338,
12594, 12850, 13106, 13362, 13618, 13874, 14130, 14386, 14642, 24882, 25138,
25394, 25650, 25906, 26162, 12339, 12595, 12851, 13107, 13363, 13619, 13875,
14131, 14387, 14643, 24883, 25139, 25395, 25651, 25907, 26163, 12340, 12596,
12852, 13108, 13364, 13620, 13876, 14132, 14388, 14644, 24884, 25140, 25396,
25652, 25908, 26164, 12341, 12597, 12853, 13109, 13365, 13621, 13877, 14133,
14389, 14645, 24885, 25141, 25397, 25653, 25909, 26165, 12342, 12598, 12854,
13110, 13366, 13622, 13878, 14134, 14390, 14646, 24886, 25142, 25398, 25654,
25910, 26166, 12343, 12599, 12855, 13111, 13367, 13623, 13879, 14135, 14391,
14647, 24887, 25143, 25399, 25655, 25911, 26167, 12344, 12600, 12856, 13112,
13368, 13624, 13880, 14136, 14392, 14648, 24888, 25144, 25400, 25656, 25912,
26168, 12345, 12601, 12857, 13113, 13369, 13625, 13881, 14137, 14393, 14649,
24889, 25145, 25401, 25657, 25913, 26169, 12385, 12641, 12897, 13153, 13409,
13665, 13921, 14177, 14433, 14689, 24929, 25185, 25441, 25697, 25953, 26209,
12386, 12642, 12898, 13154, 13410, 13666, 13922, 14178, 14434, 14690, 24930,
25186, 25442, 25698, 25954, 26210, 12387, 12643, 12899, 13155, 13411, 13667,
13923, 14179, 14435, 14691, 24931, 25187, 25443, 25699, 25955, 26211, 12388,
12644, 12900, 13156, 13412, 13668, 13924, 14180, 14436, 14692, 24932, 25188,
25444, 25700, 25956, 26212, 12389, 12645, 12901, 13157, 13413, 13669, 13925,
14181, 14437, 14693, 24933, 25189, 25445, 25701, 25957, 26213, 12390, 12646,
12902, 13158, 13414, 13670, 13926, 14182, 14438, 14694, 24934, 25190, 25446,
25702, 25958, 26214};
return hex_char_pairs;
}
inline
void init_hex_char_pairs(const oid_t& oid, uint16_t* data)
{
const uint8_t* bytes = oid.data();
const uint16_t* gHexCharPairs = get_hex_char_pairs(std::integral_constant<bool, jsoncons::endian::native == jsoncons::endian::big>());
data[0] = gHexCharPairs[bytes[0]];
data[1] = gHexCharPairs[bytes[1]];
data[2] = gHexCharPairs[bytes[2]];
data[3] = gHexCharPairs[bytes[3]];
data[4] = gHexCharPairs[bytes[4]];
data[5] = gHexCharPairs[bytes[5]];
data[6] = gHexCharPairs[bytes[6]];
data[7] = gHexCharPairs[bytes[7]];
data[8] = gHexCharPairs[bytes[8]];
data[9] = gHexCharPairs[bytes[9]];
data[10] = gHexCharPairs[bytes[10]];
data[11] = gHexCharPairs[bytes[11]];
}
} // namsepace detail
template <typename StringT>
inline
void to_string(const oid_t& oid, StringT& s)
{
s.resize(24);
detail::init_hex_char_pairs(oid, reinterpret_cast<uint16_t*>(&s[0]));
}
} // namespace bson
} // namespace jsoncons
#endif

View file

@ -0,0 +1,75 @@
// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_BSON_BSON_OPTIONS_HPP
#define JSONCONS_BSON_BSON_OPTIONS_HPP
#include <string>
#include <limits> // std::numeric_limits
#include <cwchar>
#include <jsoncons/json_exception.hpp>
#include <jsoncons_ext/bson/bson_type.hpp>
namespace jsoncons { namespace bson {
class bson_options;
class bson_options_common
{
friend class bson_options;
int max_nesting_depth_;
protected:
virtual ~bson_options_common() = default;
bson_options_common()
: max_nesting_depth_(1024)
{
}
bson_options_common(const bson_options_common&) = default;
bson_options_common& operator=(const bson_options_common&) = default;
bson_options_common(bson_options_common&&) = default;
bson_options_common& operator=(bson_options_common&&) = default;
public:
int max_nesting_depth() const
{
return max_nesting_depth_;
}
};
class bson_decode_options : public virtual bson_options_common
{
friend class bson_options;
public:
bson_decode_options()
{
}
};
class bson_encode_options : public virtual bson_options_common
{
friend class bson_options;
public:
bson_encode_options()
{
}
};
class bson_options final : public bson_decode_options, public bson_encode_options
{
public:
using bson_options_common::max_nesting_depth;
bson_options& max_nesting_depth(int value)
{
this->max_nesting_depth_ = value;
return *this;
}
};
}}
#endif

View file

@ -0,0 +1,645 @@
// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_BSON_BSON_PARSER_HPP
#define JSONCONS_BSON_BSON_PARSER_HPP
#include <string>
#include <vector>
#include <memory>
#include <utility> // std::move
#include <jsoncons/json.hpp>
#include <jsoncons/source.hpp>
#include <jsoncons/json_visitor.hpp>
#include <jsoncons/config/jsoncons_config.hpp>
#include <jsoncons_ext/bson/bson_type.hpp>
#include <jsoncons_ext/bson/bson_decimal128.hpp>
#include <jsoncons_ext/bson/bson_error.hpp>
#include <jsoncons_ext/bson/bson_options.hpp>
#include <jsoncons_ext/bson/bson_oid.hpp>
namespace jsoncons { namespace bson {
enum class parse_mode {root,accept,document,array,value};
struct parse_state
{
parse_mode mode;
std::size_t length;
std::size_t pos;
uint8_t type;
std::size_t index;
parse_state(parse_mode mode_, std::size_t length_, std::size_t pos_, uint8_t type_ = 0) noexcept
: mode(mode_), length(length_), pos(pos_), type(type_), index(0)
{
}
parse_state(const parse_state&) = default;
parse_state(parse_state&&) = default;
parse_state& operator=(const parse_state&) = default;
parse_state& operator=(parse_state&&) = default;
};
template <class Source,class Allocator=std::allocator<char>>
class basic_bson_parser : public ser_context
{
using char_type = char;
using char_traits_type = std::char_traits<char>;
using temp_allocator_type = Allocator;
using char_allocator_type = typename std::allocator_traits<temp_allocator_type>:: template rebind_alloc<char_type>;
using byte_allocator_type = typename std::allocator_traits<temp_allocator_type>:: template rebind_alloc<uint8_t>;
using parse_state_allocator_type = typename std::allocator_traits<temp_allocator_type>:: template rebind_alloc<parse_state>;
Source source_;
bson_decode_options options_;
bool more_;
bool done_;
std::vector<uint8_t,byte_allocator_type> bytes_buffer_;
std::basic_string<char,std::char_traits<char>,char_allocator_type> text_buffer_;
std::vector<parse_state,parse_state_allocator_type> state_stack_;
public:
template <class Sourceable>
basic_bson_parser(Sourceable&& source,
const bson_decode_options& options = bson_decode_options(),
const Allocator alloc = Allocator())
: source_(std::forward<Sourceable>(source)),
options_(options),
more_(true),
done_(false),
text_buffer_(alloc),
state_stack_(alloc)
{
state_stack_.emplace_back(parse_mode::root,0,0);
}
void restart()
{
more_ = true;
}
void reset()
{
more_ = true;
done_ = false;
bytes_buffer_.clear();
text_buffer_.clear();
state_stack_.clear();
state_stack_.emplace_back(parse_mode::root,0,0);
}
template <class Sourceable>
void reset(Sourceable&& source)
{
source_ = std::forward<Sourceable>(source);
reset();
}
bool done() const
{
return done_;
}
bool stopped() const
{
return !more_;
}
std::size_t line() const override
{
return 0;
}
std::size_t column() const override
{
return source_.position();
}
void array_expected(json_visitor& visitor, std::error_code& ec)
{
if (state_stack_.size() == 2 && state_stack_.back().mode == parse_mode::document)
{
state_stack_.back().mode = parse_mode::array;
more_ = visitor.begin_array(semantic_tag::none, *this, ec);
}
}
void parse(json_visitor& visitor, std::error_code& ec)
{
if (JSONCONS_UNLIKELY(source_.is_error()))
{
ec = bson_errc::source_error;
more_ = false;
return;
}
while (!done_ && more_)
{
switch (state_stack_.back().mode)
{
case parse_mode::root:
state_stack_.back().mode = parse_mode::accept;
begin_document(visitor, ec);
break;
case parse_mode::document:
{
uint8_t type;
std::size_t n = source_.read(&type, 1);
state_stack_.back().pos += n;
if (JSONCONS_UNLIKELY(n != 1))
{
ec = bson_errc::unexpected_eof;
more_ = false;
return;
}
if (type != 0x00)
{
read_e_name(visitor,jsoncons::bson::bson_container_type::document,ec);
state_stack_.back().mode = parse_mode::value;
state_stack_.back().type = type;
}
else
{
end_document(visitor,ec);
}
break;
}
case parse_mode::array:
{
uint8_t type;
std::size_t n = source_.read(&type, 1);
state_stack_.back().pos += n;
if (JSONCONS_UNLIKELY(n != 1))
{
ec = bson_errc::unexpected_eof;
more_ = false;
return;
}
if (type != 0x00)
{
read_e_name(visitor,jsoncons::bson::bson_container_type::array,ec);
read_value(visitor, type, ec);
}
else
{
end_array(visitor,ec);
}
break;
}
case parse_mode::value:
state_stack_.back().mode = parse_mode::document;
read_value(visitor,state_stack_.back().type,ec);
break;
case parse_mode::accept:
{
JSONCONS_ASSERT(state_stack_.size() == 1);
state_stack_.clear();
more_ = false;
done_ = true;
visitor.flush();
break;
}
}
}
}
private:
void begin_document(json_visitor& visitor, std::error_code& ec)
{
if (JSONCONS_UNLIKELY(static_cast<int>(state_stack_.size()) > options_.max_nesting_depth()))
{
ec = bson_errc::max_nesting_depth_exceeded;
more_ = false;
return;
}
uint8_t buf[sizeof(int32_t)];
size_t n = source_.read(buf, sizeof(int32_t));
if (JSONCONS_UNLIKELY(n != sizeof(int32_t)))
{
ec = bson_errc::unexpected_eof;
more_ = false;
return;
}
auto length = binary::little_to_native<int32_t>(buf, sizeof(buf));
more_ = visitor.begin_object(semantic_tag::none, *this, ec);
state_stack_.emplace_back(parse_mode::document,length,n);
}
void end_document(json_visitor& visitor, std::error_code& ec)
{
JSONCONS_ASSERT(state_stack_.size() >= 2);
more_ = visitor.end_object(*this,ec);
if (JSONCONS_UNLIKELY(state_stack_.back().pos != state_stack_.back().length))
{
ec = bson_errc::size_mismatch;
more_ = false;
return;
}
std::size_t pos = state_stack_.back().pos;
state_stack_.pop_back();
state_stack_.back().pos += pos;
}
void begin_array(json_visitor& visitor, std::error_code& ec)
{
if (JSONCONS_UNLIKELY(static_cast<int>(state_stack_.size()) > options_.max_nesting_depth()))
{
ec = bson_errc::max_nesting_depth_exceeded;
more_ = false;
return;
}
uint8_t buf[sizeof(int32_t)];
std::size_t n = source_.read(buf, sizeof(int32_t));
if (JSONCONS_UNLIKELY(n != sizeof(int32_t)))
{
ec = bson_errc::unexpected_eof;
more_ = false;
return;
}
auto length = binary::little_to_native<int32_t>(buf, sizeof(buf));
more_ = visitor.begin_array(semantic_tag::none, *this, ec);
if (ec)
{
return;
}
state_stack_.emplace_back(parse_mode::array, length, n);
}
void end_array(json_visitor& visitor, std::error_code& ec)
{
JSONCONS_ASSERT(state_stack_.size() >= 2);
more_ = visitor.end_array(*this, ec);
if (JSONCONS_UNLIKELY(state_stack_.back().pos != state_stack_.back().length))
{
ec = bson_errc::size_mismatch;
more_ = false;
return;
}
std::size_t pos = state_stack_.back().pos;
state_stack_.pop_back();
state_stack_.back().pos += pos;
}
void read_e_name(json_visitor& visitor, jsoncons::bson::bson_container_type type, std::error_code& ec)
{
text_buffer_.clear();
read_cstring(ec);
if (ec)
{
return;
}
if (type == jsoncons::bson::bson_container_type::document)
{
auto result = unicode_traits::validate(text_buffer_.data(),text_buffer_.size());
if (JSONCONS_UNLIKELY(result.ec != unicode_traits::conv_errc()))
{
ec = bson_errc::invalid_utf8_text_string;
more_ = false;
return;
}
more_ = visitor.key(jsoncons::basic_string_view<char>(text_buffer_.data(),text_buffer_.length()), *this, ec);
}
}
void read_value(json_visitor& visitor, uint8_t type, std::error_code& ec)
{
switch (type)
{
case jsoncons::bson::bson_type::double_type:
{
uint8_t buf[sizeof(double)];
std::size_t n = source_.read(buf, sizeof(double));
state_stack_.back().pos += n;
if (JSONCONS_UNLIKELY(n != sizeof(double)))
{
ec = bson_errc::unexpected_eof;
more_ = false;
return;
}
double res = binary::little_to_native<double>(buf, sizeof(buf));
more_ = visitor.double_value(res, semantic_tag::none, *this, ec);
break;
}
case jsoncons::bson::bson_type::symbol_type:
case jsoncons::bson::bson_type::min_key_type:
case jsoncons::bson::bson_type::max_key_type:
case jsoncons::bson::bson_type::string_type:
{
text_buffer_.clear();
read_string(ec);
if (ec)
{
return;
}
auto result = unicode_traits::validate(text_buffer_.data(), text_buffer_.size());
if (JSONCONS_UNLIKELY(result.ec != unicode_traits::conv_errc()))
{
ec = bson_errc::invalid_utf8_text_string;
more_ = false;
return;
}
more_ = visitor.string_value(text_buffer_, semantic_tag::none, *this, ec);
break;
}
case jsoncons::bson::bson_type::javascript_type:
{
text_buffer_.clear();
read_string(ec);
if (ec)
{
return;
}
auto result = unicode_traits::validate(text_buffer_.data(), text_buffer_.size());
if (JSONCONS_UNLIKELY(result.ec != unicode_traits::conv_errc()))
{
ec = bson_errc::invalid_utf8_text_string;
more_ = false;
return;
}
more_ = visitor.string_value(text_buffer_, semantic_tag::code, *this, ec);
break;
}
case jsoncons::bson::bson_type::regex_type:
{
text_buffer_.clear();
text_buffer_.push_back('/');
read_cstring(ec);
if (ec)
{
return;
}
text_buffer_.push_back('/');
read_cstring(ec);
if (ec)
{
return;
}
more_ = visitor.string_value(text_buffer_, semantic_tag::regex, *this, ec);
break;
}
case jsoncons::bson::bson_type::document_type:
{
begin_document(visitor,ec);
break;
}
case jsoncons::bson::bson_type::array_type:
{
begin_array(visitor,ec);
break;
}
case jsoncons::bson::bson_type::undefined_type:
{
more_ = visitor.null_value(semantic_tag::undefined, *this, ec);
break;
}
case jsoncons::bson::bson_type::null_type:
{
more_ = visitor.null_value(semantic_tag::none, *this, ec);
break;
}
case jsoncons::bson::bson_type::bool_type:
{
uint8_t c;
std::size_t n = source_.read(&c, 1);
state_stack_.back().pos += n;
if (JSONCONS_UNLIKELY(n != 1))
{
ec = bson_errc::unexpected_eof;
more_ = false;
return;
}
more_ = visitor.bool_value(c != 0, semantic_tag::none, *this, ec);
break;
}
case jsoncons::bson::bson_type::int32_type:
{
uint8_t buf[sizeof(int32_t)];
std::size_t n = source_.read(buf, sizeof(int32_t));
state_stack_.back().pos += n;
if (JSONCONS_UNLIKELY(n != sizeof(int32_t)))
{
ec = bson_errc::unexpected_eof;
more_ = false;
return;
}
auto val = binary::little_to_native<int32_t>(buf, sizeof(buf));
more_ = visitor.int64_value(val, semantic_tag::none, *this, ec);
break;
}
case jsoncons::bson::bson_type::timestamp_type:
{
uint8_t buf[sizeof(uint64_t)];
std::size_t n = source_.read(buf, sizeof(uint64_t));
state_stack_.back().pos += n;
if (JSONCONS_UNLIKELY(n != sizeof(uint64_t)))
{
ec = bson_errc::unexpected_eof;
more_ = false;
return;
}
auto val = binary::little_to_native<uint64_t>(buf, sizeof(buf));
more_ = visitor.uint64_value(val, semantic_tag::none, *this, ec);
break;
}
case jsoncons::bson::bson_type::int64_type:
{
uint8_t buf[sizeof(int64_t)];
std::size_t n = source_.read(buf, sizeof(int64_t));
state_stack_.back().pos += n;
if (JSONCONS_UNLIKELY(n != sizeof(int64_t)))
{
ec = bson_errc::unexpected_eof;
more_ = false;
return;
}
auto val = binary::little_to_native<int64_t>(buf, sizeof(buf));
more_ = visitor.int64_value(val, semantic_tag::none, *this, ec);
break;
}
case jsoncons::bson::bson_type::datetime_type:
{
uint8_t buf[sizeof(int64_t)];
std::size_t n = source_.read(buf, sizeof(int64_t));
state_stack_.back().pos += n;
if (JSONCONS_UNLIKELY(n != sizeof(int64_t)))
{
ec = bson_errc::unexpected_eof;
more_ = false;
return;
}
auto val = binary::little_to_native<int64_t>(buf, sizeof(buf));
more_ = visitor.int64_value(val, semantic_tag::epoch_milli, *this, ec);
break;
}
case jsoncons::bson::bson_type::binary_type:
{
uint8_t buf[sizeof(int32_t)];
std::size_t n = source_.read(buf, sizeof(int32_t));
state_stack_.back().pos += n;
if (JSONCONS_UNLIKELY(n != sizeof(int32_t)))
{
ec = bson_errc::unexpected_eof;
more_ = false;
return;
}
const auto len = binary::little_to_native<int32_t>(buf, sizeof(buf));
if (JSONCONS_UNLIKELY(len < 0))
{
ec = bson_errc::length_is_negative;
more_ = false;
return;
}
uint8_t subtype;
n = source_.read(&subtype, 1);
state_stack_.back().pos += n;
if (JSONCONS_UNLIKELY(n != 1))
{
ec = bson_errc::unexpected_eof;
more_ = false;
return;
}
bytes_buffer_.clear();
n = source_reader<Source>::read(source_, bytes_buffer_, len);
state_stack_.back().pos += n;
if (JSONCONS_UNLIKELY(n != static_cast<std::size_t>(len)))
{
ec = bson_errc::unexpected_eof;
more_ = false;
return;
}
more_ = visitor.byte_string_value(bytes_buffer_,
subtype,
*this,
ec);
break;
}
case jsoncons::bson::bson_type::decimal128_type:
{
uint8_t buf[sizeof(uint64_t)*2];
std::size_t n = source_.read(buf, sizeof(buf));
state_stack_.back().pos += n;
if (JSONCONS_UNLIKELY(n != sizeof(buf)))
{
ec = bson_errc::unexpected_eof;
more_ = false;
return;
}
decimal128_t dec;
dec.low = binary::little_to_native<uint64_t>(buf, sizeof(uint64_t));
dec.high = binary::little_to_native<uint64_t>(buf+sizeof(uint64_t), sizeof(uint64_t));
text_buffer_.clear();
text_buffer_.resize(bson::decimal128_limits::buf_size);
auto r = bson::decimal128_to_chars(&text_buffer_[0], &text_buffer_[0]+text_buffer_.size(), dec);
more_ = visitor.string_value(string_view(text_buffer_.data(),static_cast<std::size_t>(r.ptr-text_buffer_.data())), semantic_tag::float128, *this, ec);
break;
}
case jsoncons::bson::bson_type::object_id_type:
{
uint8_t buf[12];
std::size_t n = source_.read(buf, sizeof(buf));
state_stack_.back().pos += n;
if (JSONCONS_UNLIKELY(n != sizeof(buf)))
{
ec = bson_errc::unexpected_eof;
more_ = false;
return;
}
oid_t oid(buf);
to_string(oid, text_buffer_);
more_ = visitor.string_value(text_buffer_, semantic_tag::id, *this, ec);
break;
}
default:
{
ec = bson_errc::unknown_type;
more_ = false;
return;
}
}
}
void read_cstring(std::error_code& ec)
{
uint8_t c = 0xff;
while (true)
{
std::size_t n = source_.read(&c, 1);
state_stack_.back().pos += n;
if (JSONCONS_UNLIKELY(n != 1))
{
ec = bson_errc::unexpected_eof;
more_ = false;
return;
}
if (c == 0)
{
break;
}
text_buffer_.push_back(c);
}
}
void read_string(std::error_code& ec)
{
uint8_t buf[sizeof(int32_t)];
std::size_t n = source_.read(buf, sizeof(int32_t));
state_stack_.back().pos += n;
if (JSONCONS_UNLIKELY(n != sizeof(int32_t)))
{
ec = bson_errc::unexpected_eof;
more_ = false;
return;
}
auto len = binary::little_to_native<int32_t>(buf, sizeof(buf));
if (JSONCONS_UNLIKELY(len < 1))
{
ec = bson_errc::string_length_is_non_positive;
more_ = false;
return;
}
std::size_t size = static_cast<std::size_t>(len) - static_cast<std::size_t>(1);
n = source_reader<Source>::read(source_, text_buffer_, size);
state_stack_.back().pos += n;
if (JSONCONS_UNLIKELY(n != size))
{
ec = bson_errc::unexpected_eof;
more_ = false;
return;
}
uint8_t c;
n = source_.read(&c, 1);
state_stack_.back().pos += n;
if (JSONCONS_UNLIKELY(n != 1))
{
ec = bson_errc::unexpected_eof;
more_ = false;
return;
}
}
};
}}
#endif

View file

@ -0,0 +1,92 @@
// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_BSON_BSON_READER_HPP
#define JSONCONS_BSON_BSON_READER_HPP
#include <string>
#include <vector>
#include <memory>
#include <utility> // std::move
#include <jsoncons/json.hpp>
#include <jsoncons/source.hpp>
#include <jsoncons/json_visitor.hpp>
#include <jsoncons/config/jsoncons_config.hpp>
#include <jsoncons_ext/bson/bson_type.hpp>
#include <jsoncons_ext/bson/bson_error.hpp>
#include <jsoncons_ext/bson/bson_parser.hpp>
namespace jsoncons { namespace bson {
template <class Source,class Allocator=std::allocator<char>>
class basic_bson_reader
{
basic_bson_parser<Source,Allocator> parser_;
json_visitor& visitor_;
public:
template <class Sourceable>
basic_bson_reader(Sourceable&& source,
json_visitor& visitor,
const Allocator alloc)
: basic_bson_reader(std::forward<Sourceable>(source),
visitor,
bson_decode_options(),
alloc)
{
}
template <class Sourceable>
basic_bson_reader(Sourceable&& source,
json_visitor& visitor,
const bson_decode_options& options = bson_decode_options(),
const Allocator alloc=Allocator())
: parser_(std::forward<Sourceable>(source), options, alloc),
visitor_(visitor)
{
}
void read()
{
std::error_code ec;
read(ec);
if (ec)
{
JSONCONS_THROW(ser_error(ec,line(),column()));
}
}
void read(std::error_code& ec)
{
parser_.reset();
parser_.parse(visitor_, ec);
if (ec)
{
return;
}
}
std::size_t line() const
{
return parser_.line();
}
std::size_t column() const
{
return parser_.column();
}
};
using bson_stream_reader = basic_bson_reader<jsoncons::binary_stream_source>;
using bson_bytes_reader = basic_bson_reader<jsoncons::bytes_source>;
#if !defined(JSONCONS_NO_DEPRECATED)
JSONCONS_DEPRECATED_MSG("Instead, use bson_stream_reader") typedef bson_stream_reader bson_reader;
JSONCONS_DEPRECATED_MSG("Instead, use bson_bytes_reader") typedef bson_bytes_reader bson_buffer_reader;
#endif
}}
#endif

View file

@ -0,0 +1,44 @@
// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_BSON_BSON_TYPE_HPP
#define JSONCONS_BSON_BSON_TYPE_HPP
#include <string>
#include <memory>
#include <jsoncons/config/jsoncons_config.hpp>
namespace jsoncons { namespace bson {
namespace bson_type
{
const uint8_t double_type = 0x01;
const uint8_t string_type = 0x02; // UTF-8 string
const uint8_t document_type = 0x03;
const uint8_t array_type = 0x04;
const uint8_t binary_type = 0x05;
const uint8_t undefined_type = 0x06; // map to null
const uint8_t object_id_type = 0x07;
const uint8_t bool_type = 0x08;
const uint8_t datetime_type = 0x09;
const uint8_t null_type = 0x0a;
const uint8_t regex_type = 0x0b;
const uint8_t javascript_type = 0x0d;
const uint8_t symbol_type = 0x0e; // deprecated, mapped to string
const uint8_t javascript_with_scope_type = 0x0f; // unsupported
const uint8_t int32_type = 0x10;
const uint8_t timestamp_type = 0x11; // MongoDB internal Timestamp, uint64
const uint8_t int64_type = 0x12;
const uint8_t decimal128_type = 0x13;
const uint8_t min_key_type = 0xff;
const uint8_t max_key_type = 0x7f;
}
enum class bson_container_type {document, array};
}}
#endif

View file

@ -0,0 +1,201 @@
// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_BSON_DECODE_BSON_HPP
#define JSONCONS_BSON_DECODE_BSON_HPP
#include <string>
#include <vector>
#include <memory>
#include <type_traits> // std::enable_if
#include <istream> // std::basic_istream
#include <jsoncons/json.hpp>
#include <jsoncons/config/jsoncons_config.hpp>
#include <jsoncons_ext/bson/bson_reader.hpp>
#include <jsoncons_ext/bson/bson_cursor.hpp>
namespace jsoncons {
namespace bson {
template<class T, class Source>
typename std::enable_if<extension_traits::is_basic_json<T>::value &&
extension_traits::is_byte_sequence<Source>::value,T>::type
decode_bson(const Source& v,
const bson_decode_options& options = bson_decode_options())
{
jsoncons::json_decoder<T> decoder;
auto adaptor = make_json_visitor_adaptor<json_visitor>(decoder);
basic_bson_reader<jsoncons::bytes_source> reader(v, adaptor, options);
reader.read();
if (!decoder.is_valid())
{
JSONCONS_THROW(ser_error(conv_errc::conversion_failed, reader.line(), reader.column()));
}
return decoder.get_result();
}
template<class T, class Source>
typename std::enable_if<!extension_traits::is_basic_json<T>::value &&
extension_traits::is_byte_sequence<Source>::value,T>::type
decode_bson(const Source& v,
const bson_decode_options& options = bson_decode_options())
{
basic_bson_cursor<bytes_source> cursor(v, options);
json_decoder<basic_json<char,sorted_policy>> decoder{};
std::error_code ec;
T val = decode_traits<T,char>::decode(cursor, decoder, ec);
if (ec)
{
JSONCONS_THROW(ser_error(ec, cursor.context().line(), cursor.context().column()));
}
return val;
}
template<class T>
typename std::enable_if<extension_traits::is_basic_json<T>::value,T>::type
decode_bson(std::istream& is,
const bson_decode_options& options = bson_decode_options())
{
jsoncons::json_decoder<T> decoder;
auto adaptor = make_json_visitor_adaptor<json_visitor>(decoder);
bson_stream_reader reader(is, adaptor, options);
reader.read();
if (!decoder.is_valid())
{
JSONCONS_THROW(ser_error(conv_errc::conversion_failed, reader.line(), reader.column()));
}
return decoder.get_result();
}
template<class T>
typename std::enable_if<!extension_traits::is_basic_json<T>::value,T>::type
decode_bson(std::istream& is,
const bson_decode_options& options = bson_decode_options())
{
basic_bson_cursor<binary_stream_source> cursor(is, options);
json_decoder<basic_json<char,sorted_policy>> decoder{};
std::error_code ec;
T val = decode_traits<T,char>::decode(cursor, decoder, ec);
if (ec)
{
JSONCONS_THROW(ser_error(ec, cursor.context().line(), cursor.context().column()));
}
return val;
}
template<class T, class InputIt>
typename std::enable_if<extension_traits::is_basic_json<T>::value,T>::type
decode_bson(InputIt first, InputIt last,
const bson_decode_options& options = bson_decode_options())
{
jsoncons::json_decoder<T> decoder;
auto adaptor = make_json_visitor_adaptor<json_visitor>(decoder);
basic_bson_reader<binary_iterator_source<InputIt>> reader(binary_iterator_source<InputIt>(first, last), adaptor, options);
reader.read();
if (!decoder.is_valid())
{
JSONCONS_THROW(ser_error(conv_errc::conversion_failed, reader.line(), reader.column()));
}
return decoder.get_result();
}
template<class T, class InputIt>
typename std::enable_if<!extension_traits::is_basic_json<T>::value,T>::type
decode_bson(InputIt first, InputIt last,
const bson_decode_options& options = bson_decode_options())
{
basic_bson_cursor<binary_iterator_source<InputIt>> cursor(binary_iterator_source<InputIt>(first, last), options);
json_decoder<basic_json<char,sorted_policy>> decoder{};
std::error_code ec;
T val = decode_traits<T,char>::decode(cursor, decoder, ec);
if (ec)
{
JSONCONS_THROW(ser_error(ec, cursor.context().line(), cursor.context().column()));
}
return val;
}
// With leading allocator parameter
template<class T, class Source, class TempAllocator>
typename std::enable_if<extension_traits::is_basic_json<T>::value &&
extension_traits::is_byte_sequence<Source>::value,T>::type
decode_bson(temp_allocator_arg_t, const TempAllocator& temp_alloc,
const Source& v,
const bson_decode_options& options = bson_decode_options())
{
json_decoder<T,TempAllocator> decoder(temp_alloc);
auto adaptor = make_json_visitor_adaptor<json_visitor>(decoder);
basic_bson_reader<jsoncons::bytes_source,TempAllocator> reader(v, adaptor, options, temp_alloc);
reader.read();
if (!decoder.is_valid())
{
JSONCONS_THROW(ser_error(conv_errc::conversion_failed, reader.line(), reader.column()));
}
return decoder.get_result();
}
template<class T, class Source, class TempAllocator>
typename std::enable_if<!extension_traits::is_basic_json<T>::value &&
extension_traits::is_byte_sequence<Source>::value,T>::type
decode_bson(temp_allocator_arg_t, const TempAllocator& temp_alloc,
const Source& v,
const bson_decode_options& options = bson_decode_options())
{
basic_bson_cursor<bytes_source,TempAllocator> cursor(v, options, temp_alloc);
json_decoder<basic_json<char,sorted_policy,TempAllocator>,TempAllocator> decoder(temp_alloc, temp_alloc);
std::error_code ec;
T val = decode_traits<T,char>::decode(cursor, decoder, ec);
if (ec)
{
JSONCONS_THROW(ser_error(ec, cursor.context().line(), cursor.context().column()));
}
return val;
}
template<class T,class TempAllocator>
typename std::enable_if<extension_traits::is_basic_json<T>::value,T>::type
decode_bson(temp_allocator_arg_t, const TempAllocator& temp_alloc,
std::istream& is,
const bson_decode_options& options = bson_decode_options())
{
json_decoder<T,TempAllocator> decoder(temp_alloc);
auto adaptor = make_json_visitor_adaptor<json_visitor>(decoder);
basic_bson_reader<jsoncons::binary_stream_source,TempAllocator> reader(is, adaptor, options, temp_alloc);
reader.read();
if (!decoder.is_valid())
{
JSONCONS_THROW(ser_error(conv_errc::conversion_failed, reader.line(), reader.column()));
}
return decoder.get_result();
}
template<class T,class TempAllocator>
typename std::enable_if<!extension_traits::is_basic_json<T>::value,T>::type
decode_bson(temp_allocator_arg_t, const TempAllocator& temp_alloc,
std::istream& is,
const bson_decode_options& options = bson_decode_options())
{
basic_bson_cursor<binary_stream_source,TempAllocator> cursor(is, options, temp_alloc);
json_decoder<basic_json<char,sorted_policy,TempAllocator>,TempAllocator> decoder(temp_alloc, temp_alloc);
std::error_code ec;
T val = decode_traits<T,char>::decode(cursor, decoder, ec);
if (ec)
{
JSONCONS_THROW(ser_error(ec, cursor.context().line(), cursor.context().column()));
}
return val;
}
} // bson
} // jsoncons
#endif

View file

@ -0,0 +1,144 @@
// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_BSON_ENCODE_BSON_HPP
#define JSONCONS_BSON_ENCODE_BSON_HPP
#include <string>
#include <vector>
#include <memory>
#include <type_traits> // std::enable_if
#include <istream> // std::basic_istream
#include <jsoncons/json.hpp>
#include <jsoncons/config/jsoncons_config.hpp>
#include <jsoncons_ext/bson/bson_encoder.hpp>
#include <jsoncons_ext/bson/bson_reader.hpp>
namespace jsoncons {
namespace bson {
template<class T, class Container>
typename std::enable_if<extension_traits::is_basic_json<T>::value &&
extension_traits::is_back_insertable_byte_container<Container>::value,void>::type
encode_bson(const T& j,
Container& v,
const bson_encode_options& options = bson_encode_options())
{
using char_type = typename T::char_type;
basic_bson_encoder<jsoncons::bytes_sink<Container>> encoder(v, options);
auto adaptor = make_json_visitor_adaptor<basic_json_visitor<char_type>>(encoder);
j.dump(adaptor);
}
template<class T, class Container>
typename std::enable_if<!extension_traits::is_basic_json<T>::value &&
extension_traits::is_back_insertable_byte_container<Container>::value,void>::type
encode_bson(const T& val,
Container& v,
const bson_encode_options& options = bson_encode_options())
{
basic_bson_encoder<jsoncons::bytes_sink<Container>> encoder(v, options);
std::error_code ec;
encode_traits<T,char>::encode(val, encoder, json(), ec);
if (ec)
{
JSONCONS_THROW(ser_error(ec));
}
}
template<class T>
typename std::enable_if<extension_traits::is_basic_json<T>::value,void>::type
encode_bson(const T& j,
std::ostream& os,
const bson_encode_options& options = bson_encode_options())
{
using char_type = typename T::char_type;
bson_stream_encoder encoder(os, options);
auto adaptor = make_json_visitor_adaptor<basic_json_visitor<char_type>>(encoder);
j.dump(adaptor);
}
template<class T>
typename std::enable_if<!extension_traits::is_basic_json<T>::value,void>::type
encode_bson(const T& val,
std::ostream& os,
const bson_encode_options& options = bson_encode_options())
{
bson_stream_encoder encoder(os, options);
std::error_code ec;
encode_traits<T,char>::encode(val, encoder, json(), ec);
if (ec)
{
JSONCONS_THROW(ser_error(ec));
}
}
// with temp_allocator_rag
template<class T, class Container, class TempAllocator>
typename std::enable_if<extension_traits::is_basic_json<T>::value &&
extension_traits::is_back_insertable_byte_container<Container>::value,void>::type
encode_bson(temp_allocator_arg_t, const TempAllocator& temp_alloc,
const T& j,
Container& v,
const bson_encode_options& options = bson_encode_options())
{
using char_type = typename T::char_type;
basic_bson_encoder<jsoncons::bytes_sink<Container>,TempAllocator> encoder(v, options, temp_alloc);
auto adaptor = make_json_visitor_adaptor<basic_json_visitor<char_type>>(encoder);
j.dump(adaptor);
}
template<class T, class Container, class TempAllocator>
typename std::enable_if<!extension_traits::is_basic_json<T>::value &&
extension_traits::is_back_insertable_byte_container<Container>::value,void>::type
encode_bson(temp_allocator_arg_t, const TempAllocator& temp_alloc,
const T& val,
Container& v,
const bson_encode_options& options = bson_encode_options())
{
basic_bson_encoder<jsoncons::bytes_sink<Container>,TempAllocator> encoder(v, options, temp_alloc);
std::error_code ec;
encode_traits<T,char>::encode(val, encoder, json(), ec);
if (ec)
{
JSONCONS_THROW(ser_error(ec));
}
}
template<class T,class TempAllocator>
typename std::enable_if<extension_traits::is_basic_json<T>::value,void>::type
encode_bson(temp_allocator_arg_t, const TempAllocator& temp_alloc,
const T& j,
std::ostream& os,
const bson_encode_options& options = bson_encode_options())
{
using char_type = typename T::char_type;
basic_bson_encoder<jsoncons::binary_stream_sink,TempAllocator> encoder(os, options, temp_alloc);
auto adaptor = make_json_visitor_adaptor<basic_json_visitor<char_type>>(encoder);
j.dump(adaptor);
}
template<class T,class TempAllocator>
typename std::enable_if<!extension_traits::is_basic_json<T>::value,void>::type
encode_bson(temp_allocator_arg_t, const TempAllocator& temp_alloc,
const T& val,
std::ostream& os,
const bson_encode_options& options = bson_encode_options())
{
basic_bson_encoder<jsoncons::binary_stream_sink,TempAllocator> encoder(os, options, temp_alloc);
std::error_code ec;
encode_traits<T,char>::encode(val, encoder, json(), ec);
if (ec)
{
JSONCONS_THROW(ser_error(ec));
}
}
} // bson
} // jsoncons
#endif

View file

@ -0,0 +1,26 @@
// Copyright 2017-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_CBOR_CBOR_HPP
#define JSONCONS_CBOR_CBOR_HPP
#include <string>
#include <vector>
#include <memory>
#include <type_traits> // std::enable_if
#include <istream> // std::basic_istream
#include <jsoncons/json.hpp>
#include <jsoncons/json_filter.hpp>
#include <jsoncons/config/jsoncons_config.hpp>
#include <jsoncons_ext/cbor/cbor_reader.hpp>
#include <jsoncons_ext/cbor/cbor_cursor.hpp>
#include <jsoncons_ext/cbor/cbor_encoder.hpp>
#include <jsoncons_ext/cbor/encode_cbor.hpp>
#include <jsoncons_ext/cbor/decode_cbor.hpp>
#endif

View file

@ -0,0 +1,351 @@
// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_CBOR_CBOR_CURSOR_HPP
#define JSONCONS_CBOR_CBOR_CURSOR_HPP
#include <memory> // std::allocator
#include <string>
#include <vector>
#include <stdexcept>
#include <system_error>
#include <ios>
#include <istream> // std::basic_istream
#include <jsoncons/byte_string.hpp>
#include <jsoncons/config/jsoncons_config.hpp>
#include <jsoncons/json_visitor.hpp>
#include <jsoncons/json_exception.hpp>
#include <jsoncons/staj_cursor.hpp>
#include <jsoncons/source.hpp>
#include <jsoncons_ext/cbor/cbor_parser.hpp>
namespace jsoncons {
namespace cbor {
template<class Source=jsoncons::binary_stream_source,class Allocator=std::allocator<char>>
class basic_cbor_cursor : public basic_staj_cursor<char>, private virtual ser_context
{
public:
using source_type = Source;
using char_type = char;
using allocator_type = Allocator;
private:
basic_cbor_parser<Source,Allocator> parser_;
basic_staj_visitor<char_type> cursor_visitor_;
basic_item_event_visitor_to_json_visitor<char_type,Allocator> cursor_handler_adaptor_;
bool eof_;
// Noncopyable and nonmoveable
basic_cbor_cursor(const basic_cbor_cursor&) = delete;
basic_cbor_cursor& operator=(const basic_cbor_cursor&) = delete;
public:
using string_view_type = string_view;
template <class Sourceable>
basic_cbor_cursor(Sourceable&& source,
const cbor_decode_options& options = cbor_decode_options(),
const Allocator& alloc = Allocator())
: parser_(std::forward<Sourceable>(source), options, alloc),
cursor_visitor_(accept_all),
cursor_handler_adaptor_(cursor_visitor_, alloc),
eof_(false)
{
if (!done())
{
next();
}
}
// Constructors that set parse error codes
template <class Sourceable>
basic_cbor_cursor(Sourceable&& source,
std::error_code& ec)
: basic_cbor_cursor(std::allocator_arg, Allocator(),
std::forward<Sourceable>(source),
cbor_decode_options(),
ec)
{
}
template <class Sourceable>
basic_cbor_cursor(Sourceable&& source,
const cbor_decode_options& options,
std::error_code& ec)
: basic_cbor_cursor(std::allocator_arg, Allocator(),
std::forward<Sourceable>(source),
options,
ec)
{
}
template <class Sourceable>
basic_cbor_cursor(std::allocator_arg_t, const Allocator& alloc,
Sourceable&& source,
const cbor_decode_options& options,
std::error_code& ec)
: parser_(std::forward<Sourceable>(source), options, alloc),
cursor_visitor_(accept_all),
cursor_handler_adaptor_(cursor_visitor_, alloc),
eof_(false)
{
if (!done())
{
next(ec);
}
}
void reset()
{
parser_.reset();
cursor_visitor_.reset();
cursor_handler_adaptor_.reset();
eof_ = false;
if (!done())
{
next();
}
}
template <class Sourceable>
void reset(Sourceable&& source)
{
parser_.reset(std::forward<Sourceable>(source));
cursor_visitor_.reset();
cursor_handler_adaptor_.reset();
eof_ = false;
if (!done())
{
next();
}
}
void reset(std::error_code& ec)
{
parser_.reset();
cursor_visitor_.reset();
cursor_handler_adaptor_.reset();
eof_ = false;
if (!done())
{
next(ec);
}
}
template <class Sourceable>
void reset(Sourceable&& source, std::error_code& ec)
{
parser_.reset(std::forward<Sourceable>(source));
cursor_visitor_.reset();
cursor_handler_adaptor_.reset();
eof_ = false;
if (!done())
{
next(ec);
}
}
bool done() const override
{
return parser_.done();
}
bool is_typed_array() const
{
return cursor_visitor_.is_typed_array();
}
const staj_event& current() const override
{
return cursor_visitor_.event();
}
void read_to(basic_json_visitor<char_type>& visitor) override
{
std::error_code ec;
read_to(visitor, ec);
if (ec)
{
JSONCONS_THROW(ser_error(ec,parser_.line(),parser_.column()));
}
}
void read_to(basic_json_visitor<char_type>& visitor,
std::error_code& ec) override
{
if (cursor_visitor_.dump(visitor, *this, ec))
{
read_next(visitor, ec);
}
}
void next() override
{
std::error_code ec;
next(ec);
if (ec)
{
JSONCONS_THROW(ser_error(ec,parser_.line(),parser_.column()));
}
}
void next(std::error_code& ec) override
{
read_next(ec);
}
const ser_context& context() const override
{
return *this;
}
bool eof() const
{
return eof_;
}
std::size_t line() const override
{
return parser_.line();
}
std::size_t column() const override
{
return parser_.column();
}
friend
staj_filter_view operator|(basic_cbor_cursor& cursor,
std::function<bool(const staj_event&, const ser_context&)> pred)
{
return staj_filter_view(cursor, pred);
}
#if !defined(JSONCONS_NO_DEPRECATED)
template <class Sourceable>
JSONCONS_DEPRECATED_MSG("Instead, use pipe syntax for filter")
basic_cbor_cursor(Sourceable&& source,
std::function<bool(const staj_event&, const ser_context&)> filter,
const cbor_decode_options& options = cbor_decode_options(),
const Allocator& alloc = Allocator())
: parser_(std::forward<Sourceable>(source), options, alloc),
cursor_visitor_(filter),
cursor_handler_adaptor_(cursor_visitor_, alloc),
eof_(false)
{
if (!done())
{
next();
}
}
template <class Sourceable>
JSONCONS_DEPRECATED_MSG("Instead, use pipe syntax for filter")
basic_cbor_cursor(Sourceable&& source,
std::function<bool(const staj_event&, const ser_context&)> filter,
std::error_code& ec)
: basic_cbor_cursor(std::allocator_arg, Allocator(),
std::forward<Sourceable>(source), filter, ec)
{
}
template <class Sourceable>
JSONCONS_DEPRECATED_MSG("Instead, use pipe syntax for filter")
basic_cbor_cursor(std::allocator_arg_t, const Allocator& alloc,
Sourceable&& source,
std::function<bool(const staj_event&, const ser_context&)> filter,
std::error_code& ec)
: parser_(std::forward<Sourceable>(source), alloc),
cursor_visitor_(filter),
cursor_handler_adaptor_(cursor_visitor_, alloc),
eof_(false)
{
if (!done())
{
next(ec);
}
}
JSONCONS_DEPRECATED_MSG("Instead, use read_to(basic_json_visitor<char_type>&)")
void read(basic_json_visitor<char_type>& visitor)
{
read_to(visitor);
}
JSONCONS_DEPRECATED_MSG("Instead, use read_to(basic_json_visitor<char_type>&, std::error_code&)")
void read(basic_json_visitor<char_type>& visitor,
std::error_code& ec)
{
read_to(visitor, ec);
}
#endif
private:
static bool accept_all(const staj_event&, const ser_context&)
{
return true;
}
void read_next(std::error_code& ec)
{
if (cursor_visitor_.in_available())
{
cursor_visitor_.send_available(ec);
}
else
{
parser_.restart();
while (!parser_.stopped())
{
parser_.parse(cursor_handler_adaptor_, ec);
if (ec) return;
}
}
}
void read_next(basic_json_visitor<char_type>& visitor, std::error_code& ec)
{
{
struct resource_wrapper
{
basic_item_event_visitor_to_json_visitor<char_type,Allocator>& adaptor;
basic_json_visitor<char_type>& original;
resource_wrapper(basic_item_event_visitor_to_json_visitor<char_type,Allocator>& adaptor,
basic_json_visitor<char_type>& visitor)
: adaptor(adaptor), original(adaptor.destination())
{
adaptor.destination(visitor);
}
~resource_wrapper()
{
adaptor.destination(original);
}
} wrapper(cursor_handler_adaptor_, visitor);
parser_.restart();
while (!parser_.stopped())
{
parser_.parse(cursor_handler_adaptor_, ec);
if (ec)
{
return;
}
}
}
}
};
using cbor_stream_cursor = basic_cbor_cursor<jsoncons::binary_stream_source>;
using cbor_bytes_cursor = basic_cbor_cursor<jsoncons::bytes_source>;
} // namespace cbor
} // namespace jsoncons
#endif

View file

@ -0,0 +1,93 @@
// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_CBOR_CBOR_DETAIL_HPP
#define JSONCONS_CBOR_CBOR_DETAIL_HPP
#include <string>
#include <vector>
#include <memory>
#include <iterator> // std::forward_iterator_tag
#include <limits> // std::numeric_limits
#include <utility> // std::move
#include <jsoncons/json.hpp>
#include <jsoncons/json_visitor.hpp>
#include <jsoncons/config/jsoncons_config.hpp>
// 0x00..0x17 (0..23)
#define JSONCONS_CBOR_0x00_0x17 \
0x00:case 0x01:case 0x02:case 0x03:case 0x04:case 0x05:case 0x06:case 0x07:case 0x08:case 0x09:case 0x0a:case 0x0b:case 0x0c:case 0x0d:case 0x0e:case 0x0f:case 0x10:case 0x11:case 0x12:case 0x13:case 0x14:case 0x15:case 0x16:case 0x17
#define JSONCONS_CBOR_ARRAY_TAGS \
0x40:case 0x41:case 0x42:case 0x43:case 0x44:case 0x45:case 0x46:case 0x47:case 0x48:case 0x49:case 0x4a:case 0x4b:case 0x4c:case 0x4d:case 0x4e:case 0x4f:case 0x50:case 0x51:case 0x52:case 0x53:case 0x54:case 0x55:case 0x56:case 0x57
namespace jsoncons { namespace cbor { namespace detail {
//const uint8_t cbor_array_tags_010_mask = 0b11100000;
//const uint8_t cbor_array_tags_f_mask = 0b00010000;
//const uint8_t cbor_array_tags_s_mask = 0b00001000;
//const uint8_t cbor_array_tags_e_mask = 0b00000100;
//const uint8_t cbor_array_tags_ll_mask = 0b00000011;
const uint8_t cbor_array_tags_010_mask = 0xE0;
const uint8_t cbor_array_tags_f_mask = 0x10;
const uint8_t cbor_array_tags_s_mask = 0x08;
const uint8_t cbor_array_tags_e_mask = 0x04;
const uint8_t cbor_array_tags_ll_mask = 0x03;
const uint8_t cbor_array_tags_010_shift = 5;
const uint8_t cbor_array_tags_f_shift = 4;
const uint8_t cbor_array_tags_s_shift = 3;
const uint8_t cbor_array_tags_e_shift = 2;
const uint8_t cbor_array_tags_ll_shift = 0;
enum class cbor_major_type : uint8_t
{
unsigned_integer = 0x00,
negative_integer = 0x01,
byte_string = 0x02,
text_string = 0x03,
array = 0x04,
map = 0x05,
semantic_tag = 0x06,
simple = 0x7
};
namespace additional_info
{
const uint8_t indefinite_length = 0x1f;
}
inline
size_t min_length_for_stringref(uint64_t index)
{
std::size_t n;
if (index <= 23)
{
n = 3;
}
else if (index <= 255)
{
n = 4;
}
else if (index <= 65535)
{
n = 5;
}
else if (index <= 4294967295)
{
n = 7;
}
else
{
n = 11;
}
return n;
}
}}}
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,105 @@
/// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_CBOR_CBOR_ERROR_HPP
#define JSONCONS_CBOR_CBOR_ERROR_HPP
#include <system_error>
#include <jsoncons/config/jsoncons_config.hpp>
#include <jsoncons/json_exception.hpp> // jsoncons::ser_error
namespace jsoncons { namespace cbor {
enum class cbor_errc
{
success = 0,
unexpected_eof,
source_error,
invalid_decimal_fraction,
invalid_bigfloat,
invalid_utf8_text_string,
too_many_items,
too_few_items,
number_too_large,
stringref_too_large,
max_nesting_depth_exceeded,
unknown_type,
illegal_chunked_string
};
class cbor_error_category_impl
: public std::error_category
{
public:
const char* name() const noexcept override
{
return "jsoncons/cbor";
}
std::string message(int ev) const override
{
switch (static_cast<cbor_errc>(ev))
{
case cbor_errc::unexpected_eof:
return "Unexpected end of file";
case cbor_errc::source_error:
return "Source error";
case cbor_errc::invalid_decimal_fraction:
return "Invalid decimal fraction";
case cbor_errc::invalid_bigfloat:
return "Invalid bigfloat";
case cbor_errc::invalid_utf8_text_string:
return "Illegal UTF-8 encoding in text string";
case cbor_errc::too_many_items:
return "Too many items were added to a CBOR map or array of known length";
case cbor_errc::too_few_items:
return "Too few items were added to a CBOR map or array of known length";
case cbor_errc::number_too_large:
return "Number exceeds implementation limits";
case cbor_errc::stringref_too_large:
return "stringref exceeds stringref map size";
case cbor_errc::max_nesting_depth_exceeded:
return "Data item nesting exceeds limit in options";
case cbor_errc::unknown_type:
return "An unknown type was found in the stream";
case cbor_errc::illegal_chunked_string:
return "An illegal type was found while parsing an indefinite length string";
default:
return "Unknown CBOR parser error";
}
}
};
inline
const std::error_category& cbor_error_category()
{
static cbor_error_category_impl instance;
return instance;
}
inline
std::error_code make_error_code(cbor_errc e)
{
return std::error_code(static_cast<int>(e),cbor_error_category());
}
#if !defined(JSONCONS_NO_DEPRECATED)
JSONCONS_DEPRECATED_MSG("Instead, use ser_error") typedef ser_error cbor_error;
JSONCONS_DEPRECATED_MSG("Instead, use ser_error") typedef ser_error cbor_decode_error;
JSONCONS_DEPRECATED_MSG("Instead, use ser_error") typedef ser_error cbor_reader_errc;
#endif
}}
namespace std {
template<>
struct is_error_code_enum<jsoncons::cbor::cbor_errc> : public true_type
{
};
}
#endif

View file

@ -0,0 +1,262 @@
// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_CBOR_EVENT_READER_HPP
#define JSONCONS_CBOR_EVENT_READER_HPP
#include <memory> // std::allocator
#include <string>
#include <vector>
#include <stdexcept>
#include <system_error>
#include <ios>
#include <istream> // std::basic_istream
#include <jsoncons/byte_string.hpp>
#include <jsoncons/config/jsoncons_config.hpp>
#include <jsoncons/item_event_visitor.hpp>
#include <jsoncons/json_exception.hpp>
#include <jsoncons/item_event_reader.hpp>
#include <jsoncons/source.hpp>
#include <jsoncons_ext/cbor/cbor_parser.hpp>
namespace jsoncons {
namespace cbor {
template<class Source=jsoncons::binary_stream_source,class Allocator=std::allocator<char>>
class cbor_event_reader : public basic_item_event_reader<char>, private virtual ser_context
{
public:
using source_type = Source;
using char_type = char;
using allocator_type = Allocator;
private:
basic_cbor_parser<Source,Allocator> parser_;
basic_item_event_receiver<char_type> event_receiver_;
bool eof_;
// Noncopyable and nonmoveable
cbor_event_reader(const cbor_event_reader&) = delete;
cbor_event_reader& operator=(const cbor_event_reader&) = delete;
public:
using string_view_type = string_view;
template <class Sourceable>
cbor_event_reader(Sourceable&& source,
const cbor_decode_options& options = cbor_decode_options(),
const Allocator& alloc = Allocator())
: parser_(std::forward<Sourceable>(source), options, alloc),
event_receiver_(accept_all),
eof_(false)
{
if (!done())
{
next();
}
}
// Constructors that set parse error codes
template <class Sourceable>
cbor_event_reader(Sourceable&& source,
std::error_code& ec)
: cbor_event_reader(std::allocator_arg, Allocator(),
std::forward<Sourceable>(source),
cbor_decode_options(),
ec)
{
}
template <class Sourceable>
cbor_event_reader(Sourceable&& source,
const cbor_decode_options& options,
std::error_code& ec)
: cbor_event_reader(std::allocator_arg, Allocator(),
std::forward<Sourceable>(source),
options,
ec)
{
}
template <class Sourceable>
cbor_event_reader(std::allocator_arg_t, const Allocator& alloc,
Sourceable&& source,
const cbor_decode_options& options,
std::error_code& ec)
: parser_(std::forward<Sourceable>(source), options, alloc),
event_receiver_(accept_all),
eof_(false)
{
if (!done())
{
next(ec);
}
}
void reset()
{
parser_.reset();
event_receiver_.reset();
eof_ = false;
if (!done())
{
next();
}
}
template <class Sourceable>
void reset(Sourceable&& source)
{
parser_.reset(std::forward<Sourceable>(source));
event_receiver_.reset();
eof_ = false;
if (!done())
{
next();
}
}
void reset(std::error_code& ec)
{
parser_.reset();
event_receiver_.reset();
eof_ = false;
if (!done())
{
next(ec);
}
}
template <class Sourceable>
void reset(Sourceable&& source, std::error_code& ec)
{
parser_.reset(std::forward<Sourceable>(source));
event_receiver_.reset();
eof_ = false;
if (!done())
{
next(ec);
}
}
bool done() const override
{
return parser_.done();
}
bool is_typed_array() const
{
return event_receiver_.is_typed_array();
}
const basic_item_event<char_type>& current() const override
{
return event_receiver_.event();
}
void read_to(basic_item_event_visitor<char_type>& visitor) override
{
std::error_code ec;
read_to(visitor, ec);
if (ec)
{
JSONCONS_THROW(ser_error(ec,parser_.line(),parser_.column()));
}
}
void read_to(basic_item_event_visitor<char_type>& visitor,
std::error_code& ec) override
{
if (event_receiver_.dump(visitor, *this, ec))
{
read_next(visitor, ec);
}
}
void next() override
{
std::error_code ec;
next(ec);
if (ec)
{
JSONCONS_THROW(ser_error(ec,parser_.line(),parser_.column()));
}
}
void next(std::error_code& ec) override
{
read_next(ec);
}
const ser_context& context() const override
{
return *this;
}
bool eof() const
{
return eof_;
}
std::size_t line() const override
{
return parser_.line();
}
std::size_t column() const override
{
return parser_.column();
}
friend
staj2_filter_view operator|(cbor_event_reader& cursor,
std::function<bool(const item_event&, const ser_context&)> pred)
{
return staj2_filter_view(cursor, pred);
}
private:
static bool accept_all(const item_event&, const ser_context&)
{
return true;
}
void read_next(std::error_code& ec)
{
if (event_receiver_.in_available())
{
event_receiver_.send_available(ec);
}
else
{
parser_.restart();
while (!parser_.stopped())
{
parser_.parse(event_receiver_, ec);
if (ec) return;
}
}
}
void read_next(basic_item_event_visitor<char_type>& visitor, std::error_code& ec)
{
parser_.restart();
while (!parser_.stopped())
{
parser_.parse(visitor, ec);
if (ec)
{
return;
}
}
}
};
} // namespace cbor
} // namespace jsoncons
#endif

View file

@ -0,0 +1,113 @@
// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_CBOR_CBOR_OPTIONS_HPP
#define JSONCONS_CBOR_CBOR_OPTIONS_HPP
#include <string>
#include <limits> // std::numeric_limits
#include <cwchar>
#include <jsoncons/json_exception.hpp>
#include <jsoncons_ext/cbor/cbor_detail.hpp>
namespace jsoncons { namespace cbor {
class cbor_options;
class cbor_options_common
{
friend class cbor_options;
int max_nesting_depth_;
protected:
virtual ~cbor_options_common() = default;
cbor_options_common()
: max_nesting_depth_(1024)
{
}
cbor_options_common(const cbor_options_common&) = default;
cbor_options_common& operator=(const cbor_options_common&) = default;
cbor_options_common(cbor_options_common&&) = default;
cbor_options_common& operator=(cbor_options_common&&) = default;
public:
int max_nesting_depth() const
{
return max_nesting_depth_;
}
};
class cbor_decode_options : public virtual cbor_options_common
{
friend class cbor_options;
public:
cbor_decode_options()
{
}
};
class cbor_encode_options : public virtual cbor_options_common
{
friend class cbor_options;
bool use_stringref_;
bool use_typed_arrays_;
public:
cbor_encode_options()
: use_stringref_(false),
use_typed_arrays_(false)
{
}
bool pack_strings() const
{
return use_stringref_;
}
bool use_typed_arrays() const
{
return use_typed_arrays_;
}
};
class cbor_options final : public cbor_decode_options, public cbor_encode_options
{
public:
using cbor_options_common::max_nesting_depth;
using cbor_encode_options::pack_strings;
using cbor_encode_options::use_typed_arrays;
cbor_options& max_nesting_depth(int value)
{
this->max_nesting_depth_ = value;
return *this;
}
cbor_options& pack_strings(bool value)
{
this->use_stringref_ = value;
return *this;
}
cbor_options& use_typed_arrays(bool value)
{
this->use_typed_arrays_ = value;
return *this;
}
#if !defined(JSONCONS_NO_DEPRECATED)
JSONCONS_DEPRECATED_MSG("Instead, use use_typed_arrays(bool)")
cbor_options& enable_typed_arrays(bool value)
{
this->use_typed_arrays_ = value;
return *this;
}
#endif
};
}}
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,116 @@
// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_CBOR_CBOR_READER_HPP
#define JSONCONS_CBOR_CBOR_READER_HPP
#include <string>
#include <vector>
#include <memory>
#include <utility> // std::move
#include <jsoncons/json.hpp>
#include <jsoncons/source.hpp>
#include <jsoncons/config/jsoncons_config.hpp>
#include <jsoncons_ext/cbor/cbor_encoder.hpp>
#include <jsoncons_ext/cbor/cbor_error.hpp>
#include <jsoncons_ext/cbor/cbor_detail.hpp>
#include <jsoncons_ext/cbor/cbor_parser.hpp>
namespace jsoncons { namespace cbor {
template <class Source,class Allocator=std::allocator<char>>
class basic_cbor_reader
{
using char_type = char;
basic_cbor_parser<Source,Allocator> parser_;
basic_item_event_visitor_to_json_visitor<char_type,Allocator> adaptor_;
item_event_visitor& visitor_;
public:
template <class Sourceable>
basic_cbor_reader(Sourceable&& source,
json_visitor& visitor,
const Allocator alloc)
: basic_cbor_reader(std::forward<Sourceable>(source),
visitor,
cbor_decode_options(),
alloc)
{
}
template <class Sourceable>
basic_cbor_reader(Sourceable&& source,
json_visitor& visitor,
const cbor_decode_options& options = cbor_decode_options(),
const Allocator alloc=Allocator())
: parser_(std::forward<Sourceable>(source), options, alloc),
adaptor_(visitor, alloc), visitor_(adaptor_)
{
}
template <class Sourceable>
basic_cbor_reader(Sourceable&& source,
item_event_visitor& visitor,
const Allocator alloc)
: basic_cbor_reader(std::forward<Sourceable>(source),
visitor,
cbor_decode_options(),
alloc)
{
}
template <class Sourceable>
basic_cbor_reader(Sourceable&& source,
item_event_visitor& visitor,
const cbor_decode_options& options = cbor_decode_options(),
const Allocator alloc=Allocator())
: parser_(std::forward<Sourceable>(source), options, alloc),
visitor_(visitor)
{
}
void read()
{
std::error_code ec;
read(ec);
if (ec)
{
JSONCONS_THROW(ser_error(ec,line(),column()));
}
}
void read(std::error_code& ec)
{
parser_.reset();
parser_.parse(visitor_, ec);
if (ec)
{
return;
}
}
std::size_t line() const
{
return parser_.line();
}
std::size_t column() const
{
return parser_.column();
}
};
using cbor_stream_reader = basic_cbor_reader<jsoncons::binary_stream_source>;
using cbor_bytes_reader = basic_cbor_reader<jsoncons::bytes_source>;
#if !defined(JSONCONS_NO_DEPRECATED)
JSONCONS_DEPRECATED_MSG("Instead, use cbor_stream_reader") typedef cbor_stream_reader cbor_reader;
JSONCONS_DEPRECATED_MSG("Instead, use cbor_bytes_reader") typedef cbor_bytes_reader cbor_buffer_reader;
#endif
}}
#endif

View file

@ -0,0 +1,203 @@
// Copyright 2017-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_CBOR_DECODE_CBOR_HPP
#define JSONCONS_CBOR_DECODE_CBOR_HPP
#include <string>
#include <vector>
#include <memory>
#include <type_traits> // std::enable_if
#include <istream> // std::basic_istream
#include <jsoncons/json.hpp>
#include <jsoncons/json_filter.hpp>
#include <jsoncons/decode_traits.hpp>
#include <jsoncons/config/jsoncons_config.hpp>
#include <jsoncons_ext/cbor/cbor_reader.hpp>
#include <jsoncons_ext/cbor/cbor_cursor.hpp>
namespace jsoncons {
namespace cbor {
template<class T, class Source>
typename std::enable_if<extension_traits::is_basic_json<T>::value &&
extension_traits::is_byte_sequence<Source>::value,T>::type
decode_cbor(const Source& v,
const cbor_decode_options& options = cbor_decode_options())
{
jsoncons::json_decoder<T> decoder;
auto adaptor = make_json_visitor_adaptor<json_visitor>(decoder);
basic_cbor_reader<jsoncons::bytes_source> reader(v, adaptor, options);
reader.read();
if (!decoder.is_valid())
{
JSONCONS_THROW(ser_error(conv_errc::conversion_failed, reader.line(), reader.column()));
}
return decoder.get_result();
}
template<class T, class Source>
typename std::enable_if<!extension_traits::is_basic_json<T>::value &&
extension_traits::is_byte_sequence<Source>::value,T>::type
decode_cbor(const Source& v,
const cbor_decode_options& options = cbor_decode_options())
{
basic_cbor_cursor<bytes_source> cursor(v, options);
json_decoder<basic_json<char,sorted_policy>> decoder{};
std::error_code ec;
T val = decode_traits<T,char>::decode(cursor, decoder, ec);
if (ec)
{
JSONCONS_THROW(ser_error(ec, cursor.context().line(), cursor.context().column()));
}
return val;
}
template<class T>
typename std::enable_if<extension_traits::is_basic_json<T>::value,T>::type
decode_cbor(std::istream& is,
const cbor_decode_options& options = cbor_decode_options())
{
jsoncons::json_decoder<T> decoder;
auto adaptor = make_json_visitor_adaptor<json_visitor>(decoder);
cbor_stream_reader reader(is, adaptor, options);
reader.read();
if (!decoder.is_valid())
{
JSONCONS_THROW(ser_error(conv_errc::conversion_failed, reader.line(), reader.column()));
}
return decoder.get_result();
}
template<class T>
typename std::enable_if<!extension_traits::is_basic_json<T>::value,T>::type
decode_cbor(std::istream& is,
const cbor_decode_options& options = cbor_decode_options())
{
basic_cbor_cursor<binary_stream_source> cursor(is, options);
json_decoder<basic_json<char,sorted_policy>> decoder{};
std::error_code ec;
T val = decode_traits<T,char>::decode(cursor, decoder, ec);
if (ec)
{
JSONCONS_THROW(ser_error(ec, cursor.context().line(), cursor.context().column()));
}
return val;
}
template<class T, class InputIt>
typename std::enable_if<extension_traits::is_basic_json<T>::value,T>::type
decode_cbor(InputIt first, InputIt last,
const cbor_decode_options& options = cbor_decode_options())
{
jsoncons::json_decoder<T> decoder;
auto adaptor = make_json_visitor_adaptor<json_visitor>(decoder);
basic_cbor_reader<binary_iterator_source<InputIt>> reader(binary_iterator_source<InputIt>(first, last), adaptor, options);
reader.read();
if (!decoder.is_valid())
{
JSONCONS_THROW(ser_error(conv_errc::conversion_failed, reader.line(), reader.column()));
}
return decoder.get_result();
}
template<class T, class InputIt>
typename std::enable_if<!extension_traits::is_basic_json<T>::value,T>::type
decode_cbor(InputIt first, InputIt last,
const cbor_decode_options& options = cbor_decode_options())
{
basic_cbor_cursor<binary_iterator_source<InputIt>> cursor(binary_iterator_source<InputIt>(first, last), options);
json_decoder<basic_json<char,sorted_policy>> decoder{};
std::error_code ec;
T val = decode_traits<T,char>::decode(cursor, decoder, ec);
if (ec)
{
JSONCONS_THROW(ser_error(ec, cursor.context().line(), cursor.context().column()));
}
return val;
}
// With leading allocator parameter
template<class T, class Source, class TempAllocator>
typename std::enable_if<extension_traits::is_basic_json<T>::value &&
extension_traits::is_byte_sequence<Source>::value,T>::type
decode_cbor(temp_allocator_arg_t, const TempAllocator& temp_alloc,
const Source& v,
const cbor_decode_options& options = cbor_decode_options())
{
json_decoder<T,TempAllocator> decoder(temp_alloc);
auto adaptor = make_json_visitor_adaptor<json_visitor>(decoder);
basic_cbor_reader<jsoncons::bytes_source,TempAllocator> reader(v, adaptor, options, temp_alloc);
reader.read();
if (!decoder.is_valid())
{
JSONCONS_THROW(ser_error(conv_errc::conversion_failed, reader.line(), reader.column()));
}
return decoder.get_result();
}
template<class T, class Source, class TempAllocator>
typename std::enable_if<!extension_traits::is_basic_json<T>::value &&
extension_traits::is_byte_sequence<Source>::value,T>::type
decode_cbor(temp_allocator_arg_t, const TempAllocator& temp_alloc,
const Source& v,
const cbor_decode_options& options = cbor_decode_options())
{
basic_cbor_cursor<bytes_source,TempAllocator> cursor(v, options, temp_alloc);
json_decoder<basic_json<char,sorted_policy,TempAllocator>,TempAllocator> decoder(temp_alloc, temp_alloc);
std::error_code ec;
T val = decode_traits<T,char>::decode(cursor, decoder, ec);
if (ec)
{
JSONCONS_THROW(ser_error(ec, cursor.context().line(), cursor.context().column()));
}
return val;
}
template<class T,class TempAllocator>
typename std::enable_if<extension_traits::is_basic_json<T>::value,T>::type
decode_cbor(temp_allocator_arg_t, const TempAllocator& temp_alloc,
std::istream& is,
const cbor_decode_options& options = cbor_decode_options())
{
json_decoder<T,TempAllocator> decoder(temp_alloc);
auto adaptor = make_json_visitor_adaptor<json_visitor>(decoder);
basic_cbor_reader<jsoncons::binary_stream_source,TempAllocator> reader(is, adaptor, options, temp_alloc);
reader.read();
if (!decoder.is_valid())
{
JSONCONS_THROW(ser_error(conv_errc::conversion_failed, reader.line(), reader.column()));
}
return decoder.get_result();
}
template<class T,class TempAllocator>
typename std::enable_if<!extension_traits::is_basic_json<T>::value,T>::type
decode_cbor(temp_allocator_arg_t, const TempAllocator& temp_alloc,
std::istream& is,
const cbor_decode_options& options = cbor_decode_options())
{
basic_cbor_cursor<binary_stream_source,TempAllocator> cursor(is, options, temp_alloc);
json_decoder<basic_json<char,sorted_policy,TempAllocator>,TempAllocator> decoder(temp_alloc, temp_alloc);
std::error_code ec;
T val = decode_traits<T,char>::decode(cursor, decoder, ec);
if (ec)
{
JSONCONS_THROW(ser_error(ec, cursor.context().line(), cursor.context().column()));
}
return val;
}
} // namespace cbor
} // namespace jsoncons
#endif

View file

@ -0,0 +1,151 @@
// Copyright 2017-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_CBOR_ENCODE_CBOR_HPP
#define JSONCONS_CBOR_ENCODE_CBOR_HPP
#include <string>
#include <vector>
#include <memory>
#include <type_traits> // std::enable_if
#include <istream> // std::basic_istream
#include <jsoncons/json.hpp>
#include <jsoncons/json_filter.hpp>
#include <jsoncons/config/jsoncons_config.hpp>
#include <jsoncons/encode_traits.hpp>
#include <jsoncons_ext/cbor/cbor_encoder.hpp>
namespace jsoncons {
namespace cbor {
// to bytes
template<class T, class Container>
typename std::enable_if<extension_traits::is_basic_json<T>::value &&
extension_traits::is_back_insertable_byte_container<Container>::value,void>::type
encode_cbor(const T& j,
Container& v,
const cbor_encode_options& options = cbor_encode_options())
{
using char_type = typename T::char_type;
basic_cbor_encoder<jsoncons::bytes_sink<Container>> encoder(v, options);
auto adaptor = make_json_visitor_adaptor<basic_json_visitor<char_type>>(encoder);
j.dump(adaptor);
}
template<class T, class Container>
typename std::enable_if<!extension_traits::is_basic_json<T>::value &&
extension_traits::is_back_insertable_byte_container<Container>::value,void>::type
encode_cbor(const T& val, Container& v,
const cbor_encode_options& options = cbor_encode_options())
{
basic_cbor_encoder<jsoncons::bytes_sink<Container>> encoder(v, options);
std::error_code ec;
encode_traits<T,char>::encode(val, encoder, json(), ec);
if (ec)
{
JSONCONS_THROW(ser_error(ec));
}
}
// stream
template<class T>
typename std::enable_if<extension_traits::is_basic_json<T>::value,void>::type
encode_cbor(const T& j,
std::ostream& os,
const cbor_encode_options& options = cbor_encode_options())
{
using char_type = typename T::char_type;
cbor_stream_encoder encoder(os, options);
auto adaptor = make_json_visitor_adaptor<basic_json_visitor<char_type>>(encoder);
j.dump(adaptor);
}
template<class T>
typename std::enable_if<!extension_traits::is_basic_json<T>::value,void>::type
encode_cbor(const T& val,
std::ostream& os,
const cbor_encode_options& options = cbor_encode_options())
{
cbor_stream_encoder encoder(os, options);
std::error_code ec;
encode_traits<T,char>::encode(val, encoder, json(), ec);
if (ec)
{
JSONCONS_THROW(ser_error(ec));
}
}
// temp_allocator_arg
// to bytes
template<class T, class Container, class TempAllocator>
typename std::enable_if<extension_traits::is_basic_json<T>::value &&
extension_traits::is_back_insertable_byte_container<Container>::value,void>::type
encode_cbor(temp_allocator_arg_t, const TempAllocator& temp_alloc,
const T& j,
Container& v,
const cbor_encode_options& options = cbor_encode_options())
{
using char_type = typename T::char_type;
basic_cbor_encoder<bytes_sink<Container>,TempAllocator> encoder(v, options, temp_alloc);
auto adaptor = make_json_visitor_adaptor<basic_json_visitor<char_type>>(encoder);
j.dump(adaptor);
}
template<class T, class Container, class TempAllocator>
typename std::enable_if<!extension_traits::is_basic_json<T>::value &&
extension_traits::is_back_insertable_byte_container<Container>::value,void>::type
encode_cbor(temp_allocator_arg_t, const TempAllocator& temp_alloc,
const T& val,
Container& v,
const cbor_encode_options& options = cbor_encode_options())
{
basic_cbor_encoder<jsoncons::bytes_sink<Container>,TempAllocator> encoder(v, options, temp_alloc);
std::error_code ec;
encode_traits<T,char>::encode(val, encoder, json(), ec);
if (ec)
{
JSONCONS_THROW(ser_error(ec));
}
}
// stream
template<class T,class TempAllocator>
typename std::enable_if<extension_traits::is_basic_json<T>::value,void>::type
encode_cbor(temp_allocator_arg_t, const TempAllocator& temp_alloc,
const T& j,
std::ostream& os,
const cbor_encode_options& options = cbor_encode_options())
{
using char_type = typename T::char_type;
basic_cbor_encoder<binary_stream_sink,TempAllocator> encoder(os, options, temp_alloc);
auto adaptor = make_json_visitor_adaptor<basic_json_visitor<char_type>>(encoder);
j.dump(adaptor);
}
template<class T,class TempAllocator>
typename std::enable_if<!extension_traits::is_basic_json<T>::value,void>::type
encode_cbor(temp_allocator_arg_t, const TempAllocator& temp_alloc,
const T& val,
std::ostream& os,
const cbor_encode_options& options = cbor_encode_options())
{
std::error_code ec;
encode_cbor(temp_allocator_arg, temp_alloc, val, os, options, ec);
if (ec)
{
JSONCONS_THROW(ser_error(ec));
}
}
} // namespace cbor
} // namespace jsoncons
#endif

View file

@ -0,0 +1,17 @@
/// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_CSV_CSV_HPP
#define JSONCONS_CSV_CSV_HPP
#include <jsoncons_ext/csv/csv_options.hpp>
#include <jsoncons_ext/csv/csv_reader.hpp>
#include <jsoncons_ext/csv/csv_encoder.hpp>
#include <jsoncons_ext/csv/csv_cursor.hpp>
#include <jsoncons_ext/csv/decode_csv.hpp>
#include <jsoncons_ext/csv/encode_csv.hpp>
#endif

View file

@ -0,0 +1,358 @@
// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_CSV_CSV_CURSOR_HPP
#define JSONCONS_CSV_CSV_CURSOR_HPP
#include <memory> // std::allocator
#include <string>
#include <vector>
#include <stdexcept>
#include <system_error>
#include <ios>
#include <istream> // std::basic_istream
#include <jsoncons/byte_string.hpp>
#include <jsoncons/config/jsoncons_config.hpp>
#include <jsoncons/json_visitor.hpp>
#include <jsoncons/json_exception.hpp>
#include <jsoncons_ext/csv/csv_parser.hpp>
#include <jsoncons/staj_cursor.hpp>
#include <jsoncons/source.hpp>
#include <jsoncons/source_adaptor.hpp>
namespace jsoncons { namespace csv {
template<class CharT,class Source=jsoncons::stream_source<CharT>,class Allocator=std::allocator<char>>
class basic_csv_cursor : public basic_staj_cursor<CharT>, private virtual ser_context
{
public:
using source_type = Source;
using char_type = CharT;
using allocator_type = Allocator;
private:
static constexpr size_t default_max_buffer_size = 16384;
typedef typename std::allocator_traits<allocator_type>:: template rebind_alloc<CharT> char_allocator_type;
text_source_adaptor<Source> source_;
basic_csv_parser<CharT,Allocator> parser_;
basic_staj_visitor<CharT> cursor_visitor_;
// Noncopyable and nonmoveable
basic_csv_cursor(const basic_csv_cursor&) = delete;
basic_csv_cursor& operator=(const basic_csv_cursor&) = delete;
public:
using string_view_type = jsoncons::basic_string_view<CharT>;
// Constructors that throw parse exceptions
template <class Sourceable>
basic_csv_cursor(Sourceable&& source,
const basic_csv_decode_options<CharT>& options = basic_csv_decode_options<CharT>(),
std::function<bool(csv_errc,const ser_context&)> err_handler = default_csv_parsing(),
const Allocator& alloc = Allocator(),
typename std::enable_if<!std::is_constructible<jsoncons::basic_string_view<CharT>,Sourceable>::value>::type* = 0)
: source_(std::forward<Sourceable>(source)),
parser_(options,err_handler,alloc),
cursor_visitor_(accept_all)
{
if (!done())
{
next();
}
}
template <class Sourceable>
basic_csv_cursor(Sourceable&& source,
const basic_csv_decode_options<CharT>& options = basic_csv_decode_options<CharT>(),
std::function<bool(csv_errc,const ser_context&)> err_handler = default_csv_parsing(),
const Allocator& alloc = Allocator(),
typename std::enable_if<std::is_constructible<jsoncons::basic_string_view<CharT>,Sourceable>::value>::type* = 0)
: source_(),
parser_(options,err_handler,alloc),
cursor_visitor_(accept_all)
{
jsoncons::basic_string_view<CharT> sv(std::forward<Sourceable>(source));
initialize_with_string_view(sv);
}
// Constructors that set parse error codes
template <class Sourceable>
basic_csv_cursor(Sourceable&& source,
std::error_code& ec)
: basic_csv_cursor(std::allocator_arg, Allocator(),
std::forward<Sourceable>(source),
basic_csv_decode_options<CharT>(),
default_csv_parsing(),
ec)
{
}
template <class Sourceable>
basic_csv_cursor(Sourceable&& source,
const basic_csv_decode_options<CharT>& options,
std::error_code& ec)
: basic_csv_cursor(std::allocator_arg, Allocator(),
std::forward<Sourceable>(source),
options,
default_csv_parsing(),
ec)
{
}
template <class Sourceable>
basic_csv_cursor(Sourceable&& source,
const basic_csv_decode_options<CharT>& options,
std::function<bool(csv_errc,const ser_context&)> err_handler,
std::error_code& ec)
: basic_csv_cursor(std::allocator_arg, Allocator(),
std::forward<Sourceable>(source),
options,
err_handler,
ec)
{
}
template <class Sourceable>
basic_csv_cursor(std::allocator_arg_t, const Allocator& alloc,
Sourceable&& source,
const basic_csv_decode_options<CharT>& options,
std::function<bool(csv_errc,const ser_context&)> err_handler,
std::error_code& ec,
typename std::enable_if<!std::is_constructible<jsoncons::basic_string_view<CharT>,Sourceable>::value>::type* = 0)
: source_(std::forward<Sourceable>(source)),
parser_(options,err_handler,alloc),
cursor_visitor_(accept_all)
{
if (!done())
{
next(ec);
}
}
template <class Sourceable>
basic_csv_cursor(std::allocator_arg_t, const Allocator& alloc,
Sourceable&& source,
const basic_csv_decode_options<CharT>& options,
std::function<bool(csv_errc,const ser_context&)> err_handler,
std::error_code& ec,
typename std::enable_if<std::is_constructible<jsoncons::basic_string_view<CharT>,Sourceable>::value>::type* = 0)
: source_(),
parser_(options,err_handler,alloc),
cursor_visitor_(accept_all)
{
jsoncons::basic_string_view<CharT> sv(std::forward<Sourceable>(source));
initialize_with_string_view(sv, ec);
}
template <class Sourceable>
typename std::enable_if<!std::is_constructible<jsoncons::basic_string_view<CharT>,Sourceable>::value>::type
reset(Sourceable&& source)
{
source_ = std::forward<Sourceable>(source);
parser_.reinitialize();
cursor_visitor_.reset();
if (!done())
{
next();
}
}
template <class Sourceable>
typename std::enable_if<std::is_constructible<jsoncons::basic_string_view<CharT>,Sourceable>::value>::type
reset(Sourceable&& source)
{
source_ = {};
parser_.reinitialize();
cursor_visitor_.reset();
initialize_with_string_view(std::forward<Sourceable>(source));
}
template <class Sourceable>
typename std::enable_if<!std::is_constructible<jsoncons::basic_string_view<CharT>,Sourceable>::value>::type
reset(Sourceable&& source, std::error_code& ec)
{
source_ = std::forward<Sourceable>(source);
parser_.reinitialize();
cursor_visitor_.reset();
if (!done())
{
next(ec);
}
}
template <class Sourceable>
typename std::enable_if<std::is_constructible<jsoncons::basic_string_view<CharT>,Sourceable>::value>::type
reset(Sourceable&& source, std::error_code& ec)
{
source_ = {};
parser_.reinitialize();
initialize_with_string_view(std::forward<Sourceable>(source), ec);
}
bool done() const override
{
return parser_.done();
}
const basic_staj_event<CharT>& current() const override
{
return cursor_visitor_.event();
}
void read_to(basic_json_visitor<CharT>& visitor) override
{
std::error_code ec;
read_to(visitor, ec);
if (ec)
{
JSONCONS_THROW(ser_error(ec,parser_.line(),parser_.column()));
}
}
void read_to(basic_json_visitor<CharT>& visitor,
std::error_code& ec) override
{
if (send_json_event(cursor_visitor_.event(), visitor, *this, ec))
{
read_next(visitor, ec);
}
}
void next() override
{
std::error_code ec;
next(ec);
if (ec)
{
JSONCONS_THROW(ser_error(ec,parser_.line(),parser_.column()));
}
}
void next(std::error_code& ec) override
{
read_next(ec);
}
static bool accept_all(const basic_staj_event<CharT>&, const ser_context&)
{
return true;
}
const ser_context& context() const override
{
return *this;
}
bool eof() const
{
return parser_.source_exhausted() && source_.eof();
}
std::size_t line() const override
{
return parser_.line();
}
std::size_t column() const override
{
return parser_.column();
}
friend
basic_staj_filter_view<CharT> operator|(basic_csv_cursor& cursor,
std::function<bool(const basic_staj_event<CharT>&, const ser_context&)> pred)
{
return basic_staj_filter_view<CharT>(cursor, pred);
}
#if !defined(JSONCONS_NO_DEPRECATED)
JSONCONS_DEPRECATED_MSG("Instead, use read_to(basic_json_visitor<CharT>&)")
void read(basic_json_visitor<CharT>& visitor)
{
read_to(visitor);
}
JSONCONS_DEPRECATED_MSG("Instead, use read_to(basic_json_visitor<CharT>&, std::error_code&)")
void read(basic_json_visitor<CharT>& visitor,
std::error_code& ec)
{
read_to(visitor, ec);
}
#endif
private:
void initialize_with_string_view(string_view_type sv)
{
auto r = unicode_traits::detect_json_encoding(sv.data(), sv.size());
if (!(r.encoding == unicode_traits::encoding_kind::utf8 || r.encoding == unicode_traits::encoding_kind::undetected))
{
JSONCONS_THROW(ser_error(json_errc::illegal_unicode_character,parser_.line(),parser_.column()));
}
std::size_t offset = (r.ptr - sv.data());
parser_.update(sv.data()+offset,sv.size()-offset);
if (!done())
{
next();
}
}
void initialize_with_string_view(string_view_type sv, std::error_code& ec)
{
auto r = unicode_traits::detect_encoding_from_bom(sv.data(), sv.size());
if (!(r.encoding == unicode_traits::encoding_kind::utf8 || r.encoding == unicode_traits::encoding_kind::undetected))
{
ec = json_errc::illegal_unicode_character;
return;
}
std::size_t offset = (r.ptr - sv.data());
parser_.update(sv.data()+offset,sv.size()-offset);
if (!done())
{
next(ec);
}
}
void read_next(std::error_code& ec)
{
read_next(cursor_visitor_, ec);
}
void read_next(basic_json_visitor<CharT>& visitor, std::error_code& ec)
{
parser_.restart();
while (!parser_.stopped())
{
if (parser_.source_exhausted())
{
auto s = source_.read_buffer(ec);
if (ec) return;
if (s.size() > 0)
{
parser_.update(s.data(),s.size());
}
}
parser_.parse_some(visitor, ec);
if (ec) return;
}
}
};
using csv_stream_cursor = basic_csv_cursor<char,jsoncons::stream_source<char>>;
using csv_string_cursor = basic_csv_cursor<char,jsoncons::string_source<char>>;
using wcsv_stream_cursor = basic_csv_cursor<wchar_t,jsoncons::stream_source<wchar_t>>;
using wcsv_string_cursor = basic_csv_cursor<wchar_t,jsoncons::string_source<wchar_t>>;
using csv_cursor = basic_csv_cursor<char>;
using wcsv_cursor = basic_csv_cursor<wchar_t>;
}}
#endif

View file

@ -0,0 +1,954 @@
// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_CSV_CSV_ENCODER_HPP
#define JSONCONS_CSV_CSV_ENCODER_HPP
#include <array> // std::array
#include <string>
#include <vector>
#include <ostream>
#include <utility> // std::move
#include <unordered_map> // std::unordered_map
#include <memory> // std::allocator
#include <limits> // std::numeric_limits
#include <jsoncons/json_exception.hpp>
#include <jsoncons/json_visitor.hpp>
#include <jsoncons/detail/write_number.hpp>
#include <jsoncons_ext/csv/csv_options.hpp>
#include <jsoncons/sink.hpp>
namespace jsoncons { namespace csv {
template<class CharT,class Sink=jsoncons::stream_sink<CharT>,class Allocator=std::allocator<char>>
class basic_csv_encoder final : public basic_json_visitor<CharT>
{
public:
using char_type = CharT;
using typename basic_json_visitor<CharT>::string_view_type;
using sink_type = Sink;
using allocator_type = Allocator;
using char_allocator_type = typename std::allocator_traits<allocator_type>:: template rebind_alloc<CharT>;
using string_type = std::basic_string<CharT, std::char_traits<CharT>, char_allocator_type>;
using string_allocator_type = typename std::allocator_traits<allocator_type>:: template rebind_alloc<string_type>;
using string_string_allocator_type = typename std::allocator_traits<allocator_type>:: template rebind_alloc<std::pair<const string_type,string_type>>;
private:
static jsoncons::basic_string_view<CharT> null_constant()
{
static jsoncons::basic_string_view<CharT> k = JSONCONS_STRING_VIEW_CONSTANT(CharT,"null");
return k;
}
static jsoncons::basic_string_view<CharT> true_constant()
{
static jsoncons::basic_string_view<CharT> k = JSONCONS_STRING_VIEW_CONSTANT(CharT,"true");
return k;
}
static jsoncons::basic_string_view<CharT> false_constant()
{
static jsoncons::basic_string_view<CharT> k = JSONCONS_STRING_VIEW_CONSTANT(CharT,"false");
return k;
}
enum class stack_item_kind
{
row_mapping,
column_mapping,
object,
row,
column,
object_multi_valued_field,
row_multi_valued_field,
column_multi_valued_field
};
struct stack_item
{
stack_item_kind item_kind_;
std::size_t count_;
stack_item(stack_item_kind item_kind) noexcept
: item_kind_(item_kind), count_(0)
{
}
bool is_object() const
{
return item_kind_ == stack_item_kind::object;
}
stack_item_kind item_kind() const
{
return item_kind_;
}
};
Sink sink_;
const basic_csv_encode_options<CharT> options_;
allocator_type alloc_;
std::vector<stack_item> stack_;
jsoncons::detail::write_double fp_;
std::vector<string_type,string_allocator_type> strings_buffer_;
std::unordered_map<string_type,string_type, std::hash<string_type>,std::equal_to<string_type>,string_string_allocator_type> buffered_line_;
string_type name_;
std::size_t column_index_;
std::vector<std::size_t> row_counts_;
// Noncopyable and nonmoveable
basic_csv_encoder(const basic_csv_encoder&) = delete;
basic_csv_encoder& operator=(const basic_csv_encoder&) = delete;
public:
basic_csv_encoder(Sink&& sink,
const Allocator& alloc = Allocator())
: basic_csv_encoder(std::forward<Sink>(sink), basic_csv_encode_options<CharT>(), alloc)
{
}
basic_csv_encoder(Sink&& sink,
const basic_csv_encode_options<CharT>& options,
const Allocator& alloc = Allocator())
: sink_(std::forward<Sink>(sink)),
options_(options),
alloc_(alloc),
stack_(),
fp_(options.float_format(), options.precision()),
column_index_(0)
{
jsoncons::csv::detail::parse_column_names(options.column_names(), strings_buffer_);
}
~basic_csv_encoder() noexcept
{
JSONCONS_TRY
{
sink_.flush();
}
JSONCONS_CATCH(...)
{
}
}
void reset()
{
stack_.clear();
strings_buffer_.clear();
buffered_line_.clear();
name_.clear();
column_index_ = 0;
row_counts_.clear();
}
void reset(Sink&& sink)
{
sink_ = std::move(sink);
reset();
}
private:
template<class AnyWriter>
void escape_string(const CharT* s,
std::size_t length,
CharT quote_char, CharT quote_escape_char,
AnyWriter& sink)
{
const CharT* begin = s;
const CharT* end = s + length;
for (const CharT* it = begin; it != end; ++it)
{
CharT c = *it;
if (c == quote_char)
{
sink.push_back(quote_escape_char);
sink.push_back(quote_char);
}
else
{
sink.push_back(c);
}
}
}
void visit_flush() override
{
sink_.flush();
}
bool visit_begin_object(semantic_tag, const ser_context&, std::error_code& ec) override
{
if (stack_.empty())
{
stack_.emplace_back(stack_item_kind::column_mapping);
return true;
}
switch (stack_.back().item_kind_)
{
case stack_item_kind::row_mapping:
stack_.emplace_back(stack_item_kind::object);
return true;
default: // error
ec = csv_errc::source_error;
return false;
}
}
bool visit_end_object(const ser_context&, std::error_code&) override
{
JSONCONS_ASSERT(!stack_.empty());
switch (stack_.back().item_kind_)
{
case stack_item_kind::object:
if (stack_[0].count_ == 0)
{
for (std::size_t i = 0; i < strings_buffer_.size(); ++i)
{
if (i > 0)
{
sink_.push_back(options_.field_delimiter());
}
sink_.append(strings_buffer_[i].data(),
strings_buffer_[i].length());
}
sink_.append(options_.line_delimiter().data(),
options_.line_delimiter().length());
}
for (std::size_t i = 0; i < strings_buffer_.size(); ++i)
{
if (i > 0)
{
sink_.push_back(options_.field_delimiter());
}
auto it = buffered_line_.find(strings_buffer_[i]);
if (it != buffered_line_.end())
{
sink_.append(it->second.data(),it->second.length());
it->second.clear();
}
}
sink_.append(options_.line_delimiter().data(), options_.line_delimiter().length());
break;
case stack_item_kind::column_mapping:
{
for (const auto& item : strings_buffer_)
{
sink_.append(item.data(), item.size());
sink_.append(options_.line_delimiter().data(), options_.line_delimiter().length());
}
break;
}
default:
break;
}
stack_.pop_back();
if (!stack_.empty())
{
end_value();
}
return true;
}
bool visit_begin_array(semantic_tag, const ser_context&, std::error_code& ec) override
{
if (stack_.empty())
{
stack_.emplace_back(stack_item_kind::row_mapping);
return true;
}
switch (stack_.back().item_kind_)
{
case stack_item_kind::row_mapping:
stack_.emplace_back(stack_item_kind::row);
if (stack_[0].count_ == 0)
{
for (std::size_t i = 0; i < strings_buffer_.size(); ++i)
{
if (i > 0)
{
sink_.push_back(options_.field_delimiter());
}
sink_.append(strings_buffer_[i].data(),strings_buffer_[i].length());
}
if (strings_buffer_.size() > 0)
{
sink_.append(options_.line_delimiter().data(),
options_.line_delimiter().length());
}
}
return true;
case stack_item_kind::object:
stack_.emplace_back(stack_item_kind::object_multi_valued_field);
return true;
case stack_item_kind::column_mapping:
stack_.emplace_back(stack_item_kind::column);
row_counts_.push_back(1);
if (strings_buffer_.size() <= row_counts_.back())
{
strings_buffer_.emplace_back();
}
return true;
case stack_item_kind::column:
{
if (strings_buffer_.size() <= row_counts_.back())
{
strings_buffer_.emplace_back();
}
jsoncons::string_sink<std::basic_string<CharT>> bo(strings_buffer_[row_counts_.back()]);
begin_value(bo);
stack_.emplace_back(stack_item_kind::column_multi_valued_field);
return true;
}
case stack_item_kind::row:
begin_value(sink_);
stack_.emplace_back(stack_item_kind::row_multi_valued_field);
return true;
default: // error
ec = csv_errc::source_error;
return false;
}
}
bool visit_end_array(const ser_context&, std::error_code&) override
{
JSONCONS_ASSERT(!stack_.empty());
switch (stack_.back().item_kind_)
{
case stack_item_kind::row:
sink_.append(options_.line_delimiter().data(),
options_.line_delimiter().length());
break;
case stack_item_kind::column:
++column_index_;
break;
default:
break;
}
stack_.pop_back();
if (!stack_.empty())
{
end_value();
}
return true;
}
bool visit_key(const string_view_type& name, const ser_context&, std::error_code&) override
{
JSONCONS_ASSERT(!stack_.empty());
switch (stack_.back().item_kind_)
{
case stack_item_kind::object:
{
name_ = string_type(name);
buffered_line_[string_type(name)] = std::basic_string<CharT>();
if (stack_[0].count_ == 0 && options_.column_names().size() == 0)
{
strings_buffer_.emplace_back(name);
}
break;
}
case stack_item_kind::column_mapping:
{
if (strings_buffer_.empty())
{
strings_buffer_.emplace_back(name);
}
else
{
strings_buffer_[0].push_back(options_.field_delimiter());
strings_buffer_[0].append(string_type(name));
}
break;
}
default:
break;
}
return true;
}
bool visit_null(semantic_tag, const ser_context&, std::error_code&) override
{
JSONCONS_ASSERT(!stack_.empty());
switch (stack_.back().item_kind_)
{
case stack_item_kind::object:
case stack_item_kind::object_multi_valued_field:
{
auto it = buffered_line_.find(name_);
if (it != buffered_line_.end())
{
std::basic_string<CharT> s;
jsoncons::string_sink<std::basic_string<CharT>> bo(s);
write_null_value(bo);
bo.flush();
if (!it->second.empty() && options_.subfield_delimiter() != char_type())
{
it->second.push_back(options_.subfield_delimiter());
}
it->second.append(s);
}
break;
}
case stack_item_kind::row:
case stack_item_kind::row_multi_valued_field:
write_null_value(sink_);
break;
case stack_item_kind::column:
{
if (strings_buffer_.size() <= row_counts_.back())
{
strings_buffer_.emplace_back();
}
jsoncons::string_sink<std::basic_string<CharT>> bo(strings_buffer_[row_counts_.back()]);
write_null_value(bo);
break;
}
case stack_item_kind::column_multi_valued_field:
{
jsoncons::string_sink<std::basic_string<CharT>> bo(strings_buffer_[row_counts_.back()]);
write_null_value(bo);
break;
}
default:
break;
}
return true;
}
bool visit_string(const string_view_type& sv, semantic_tag, const ser_context&, std::error_code&) override
{
JSONCONS_ASSERT(!stack_.empty());
switch (stack_.back().item_kind_)
{
case stack_item_kind::object:
case stack_item_kind::object_multi_valued_field:
{
auto it = buffered_line_.find(name_);
if (it != buffered_line_.end())
{
std::basic_string<CharT> s;
jsoncons::string_sink<std::basic_string<CharT>> bo(s);
write_string_value(sv,bo);
bo.flush();
if (!it->second.empty() && options_.subfield_delimiter() != char_type())
{
it->second.push_back(options_.subfield_delimiter());
}
it->second.append(s);
}
break;
}
case stack_item_kind::row:
case stack_item_kind::row_multi_valued_field:
write_string_value(sv,sink_);
break;
case stack_item_kind::column:
{
if (strings_buffer_.size() <= row_counts_.back())
{
strings_buffer_.emplace_back();
}
jsoncons::string_sink<std::basic_string<CharT>> bo(strings_buffer_[row_counts_.back()]);
write_string_value(sv,bo);
break;
}
case stack_item_kind::column_multi_valued_field:
{
jsoncons::string_sink<std::basic_string<CharT>> bo(strings_buffer_[row_counts_.back()]);
write_string_value(sv,bo);
break;
}
default:
break;
}
return true;
}
bool visit_byte_string(const byte_string_view& b,
semantic_tag tag,
const ser_context& context,
std::error_code& ec) override
{
byte_string_chars_format encoding_hint;
switch (tag)
{
case semantic_tag::base16:
encoding_hint = byte_string_chars_format::base16;
break;
case semantic_tag::base64:
encoding_hint = byte_string_chars_format::base64;
break;
case semantic_tag::base64url:
encoding_hint = byte_string_chars_format::base64url;
break;
default:
encoding_hint = byte_string_chars_format::none;
break;
}
byte_string_chars_format format = jsoncons::detail::resolve_byte_string_chars_format(encoding_hint,byte_string_chars_format::none,byte_string_chars_format::base64url);
std::basic_string<CharT> s;
switch (format)
{
case byte_string_chars_format::base16:
{
encode_base16(b.begin(),b.end(),s);
visit_string(s, semantic_tag::none, context, ec);
break;
}
case byte_string_chars_format::base64:
{
encode_base64(b.begin(),b.end(),s);
visit_string(s, semantic_tag::none, context, ec);
break;
}
case byte_string_chars_format::base64url:
{
encode_base64url(b.begin(),b.end(),s);
visit_string(s, semantic_tag::none, context, ec);
break;
}
default:
{
JSONCONS_UNREACHABLE();
}
}
return true;
}
bool visit_double(double val,
semantic_tag,
const ser_context& context,
std::error_code& ec) override
{
JSONCONS_ASSERT(!stack_.empty());
switch (stack_.back().item_kind_)
{
case stack_item_kind::object:
case stack_item_kind::object_multi_valued_field:
{
auto it = buffered_line_.find(name_);
if (it != buffered_line_.end())
{
std::basic_string<CharT> s;
jsoncons::string_sink<std::basic_string<CharT>> bo(s);
write_double_value(val, context, bo, ec);
bo.flush();
if (!it->second.empty() && options_.subfield_delimiter() != char_type())
{
it->second.push_back(options_.subfield_delimiter());
}
it->second.append(s);
}
break;
}
case stack_item_kind::row:
case stack_item_kind::row_multi_valued_field:
write_double_value(val, context, sink_, ec);
break;
case stack_item_kind::column:
{
if (strings_buffer_.size() <= row_counts_.back())
{
strings_buffer_.emplace_back();
}
jsoncons::string_sink<std::basic_string<CharT>> bo(strings_buffer_[row_counts_.back()]);
write_double_value(val, context, bo, ec);
break;
}
case stack_item_kind::column_multi_valued_field:
{
jsoncons::string_sink<std::basic_string<CharT>> bo(strings_buffer_[row_counts_.back()]);
write_double_value(val, context, bo, ec);
break;
}
default:
break;
}
return true;
}
bool visit_int64(int64_t val,
semantic_tag,
const ser_context&,
std::error_code&) override
{
JSONCONS_ASSERT(!stack_.empty());
switch (stack_.back().item_kind_)
{
case stack_item_kind::object:
case stack_item_kind::object_multi_valued_field:
{
auto it = buffered_line_.find(name_);
if (it != buffered_line_.end())
{
std::basic_string<CharT> s;
jsoncons::string_sink<std::basic_string<CharT>> bo(s);
write_int64_value(val,bo);
bo.flush();
if (!it->second.empty() && options_.subfield_delimiter() != char_type())
{
it->second.push_back(options_.subfield_delimiter());
}
it->second.append(s);
}
break;
}
case stack_item_kind::row:
case stack_item_kind::row_multi_valued_field:
write_int64_value(val,sink_);
break;
case stack_item_kind::column:
{
if (strings_buffer_.size() <= row_counts_.back())
{
strings_buffer_.emplace_back();
}
jsoncons::string_sink<std::basic_string<CharT>> bo(strings_buffer_[row_counts_.back()]);
write_int64_value(val, bo);
break;
}
case stack_item_kind::column_multi_valued_field:
{
jsoncons::string_sink<std::basic_string<CharT>> bo(strings_buffer_[row_counts_.back()]);
write_int64_value(val, bo);
break;
}
default:
break;
}
return true;
}
bool visit_uint64(uint64_t val,
semantic_tag,
const ser_context&,
std::error_code&) override
{
JSONCONS_ASSERT(!stack_.empty());
switch (stack_.back().item_kind_)
{
case stack_item_kind::object:
case stack_item_kind::object_multi_valued_field:
{
auto it = buffered_line_.find(name_);
if (it != buffered_line_.end())
{
std::basic_string<CharT> s;
jsoncons::string_sink<std::basic_string<CharT>> bo(s);
write_uint64_value(val, bo);
bo.flush();
if (!it->second.empty() && options_.subfield_delimiter() != char_type())
{
it->second.push_back(options_.subfield_delimiter());
}
it->second.append(s);
}
break;
}
case stack_item_kind::row:
case stack_item_kind::row_multi_valued_field:
write_uint64_value(val,sink_);
break;
case stack_item_kind::column:
{
if (strings_buffer_.size() <= row_counts_.back())
{
strings_buffer_.emplace_back();
}
jsoncons::string_sink<std::basic_string<CharT>> bo(strings_buffer_[row_counts_.back()]);
write_uint64_value(val, bo);
break;
}
case stack_item_kind::column_multi_valued_field:
{
jsoncons::string_sink<std::basic_string<CharT>> bo(strings_buffer_[row_counts_.back()]);
write_uint64_value(val, bo);
break;
}
default:
break;
}
return true;
}
bool visit_bool(bool val, semantic_tag, const ser_context&, std::error_code&) override
{
JSONCONS_ASSERT(!stack_.empty());
switch (stack_.back().item_kind_)
{
case stack_item_kind::object:
case stack_item_kind::object_multi_valued_field:
{
auto it = buffered_line_.find(name_);
if (it != buffered_line_.end())
{
std::basic_string<CharT> s;
jsoncons::string_sink<std::basic_string<CharT>> bo(s);
write_bool_value(val,bo);
bo.flush();
if (!it->second.empty() && options_.subfield_delimiter() != char_type())
{
it->second.push_back(options_.subfield_delimiter());
}
it->second.append(s);
}
break;
}
case stack_item_kind::row:
case stack_item_kind::row_multi_valued_field:
write_bool_value(val,sink_);
break;
case stack_item_kind::column:
{
if (strings_buffer_.size() <= row_counts_.back())
{
strings_buffer_.emplace_back();
}
jsoncons::string_sink<std::basic_string<CharT>> bo(strings_buffer_[row_counts_.back()]);
write_bool_value(val, bo);
break;
}
case stack_item_kind::column_multi_valued_field:
{
jsoncons::string_sink<std::basic_string<CharT>> bo(strings_buffer_[row_counts_.back()]);
write_bool_value(val, bo);
break;
}
default:
break;
}
return true;
}
template <class AnyWriter>
bool do_string_value(const CharT* s, std::size_t length, AnyWriter& sink)
{
bool quote = false;
if (options_.quote_style() == quote_style_kind::all || options_.quote_style() == quote_style_kind::nonnumeric ||
(options_.quote_style() == quote_style_kind::minimal &&
(std::char_traits<CharT>::find(s, length, options_.field_delimiter()) != nullptr || std::char_traits<CharT>::find(s, length, options_.quote_char()) != nullptr)))
{
quote = true;
sink.push_back(options_.quote_char());
}
escape_string(s, length, options_.quote_char(), options_.quote_escape_char(), sink);
if (quote)
{
sink.push_back(options_.quote_char());
}
return true;
}
template <class AnyWriter>
void write_string_value(const string_view_type& value, AnyWriter& sink)
{
begin_value(sink);
do_string_value(value.data(),value.length(),sink);
end_value();
}
template <class AnyWriter>
void write_double_value(double val, const ser_context& context, AnyWriter& sink, std::error_code& ec)
{
begin_value(sink);
if (!std::isfinite(val))
{
if ((std::isnan)(val))
{
if (options_.enable_nan_to_num())
{
sink.append(options_.nan_to_num().data(), options_.nan_to_num().length());
}
else if (options_.enable_nan_to_str())
{
visit_string(options_.nan_to_str(), semantic_tag::none, context, ec);
}
else
{
sink.append(null_constant().data(), null_constant().size());
}
}
else if (val == std::numeric_limits<double>::infinity())
{
if (options_.enable_inf_to_num())
{
sink.append(options_.inf_to_num().data(), options_.inf_to_num().length());
}
else if (options_.enable_inf_to_str())
{
visit_string(options_.inf_to_str(), semantic_tag::none, context, ec);
}
else
{
sink.append(null_constant().data(), null_constant().size());
}
}
else
{
if (options_.enable_neginf_to_num())
{
sink.append(options_.neginf_to_num().data(), options_.neginf_to_num().length());
}
else if (options_.enable_neginf_to_str())
{
visit_string(options_.neginf_to_str(), semantic_tag::none, context, ec);
}
else
{
sink.append(null_constant().data(), null_constant().size());
}
}
}
else
{
fp_(val, sink);
}
end_value();
}
template <class AnyWriter>
void write_int64_value(int64_t val, AnyWriter& sink)
{
begin_value(sink);
jsoncons::detail::from_integer(val,sink);
end_value();
}
template <class AnyWriter>
void write_uint64_value(uint64_t val, AnyWriter& sink)
{
begin_value(sink);
jsoncons::detail::from_integer(val,sink);
end_value();
}
template <class AnyWriter>
void write_bool_value(bool val, AnyWriter& sink)
{
begin_value(sink);
if (val)
{
sink.append(true_constant().data(), true_constant().size());
}
else
{
sink.append(false_constant().data(), false_constant().size());
}
end_value();
}
template <class AnyWriter>
bool write_null_value(AnyWriter& sink)
{
begin_value(sink);
sink.append(null_constant().data(), null_constant().size());
end_value();
return true;
}
template <class AnyWriter>
void begin_value(AnyWriter& sink)
{
JSONCONS_ASSERT(!stack_.empty());
switch (stack_.back().item_kind_)
{
case stack_item_kind::row:
if (stack_.back().count_ > 0)
{
sink.push_back(options_.field_delimiter());
}
break;
case stack_item_kind::column:
{
if (row_counts_.size() >= 3)
{
for (std::size_t i = row_counts_.size()-2; i-- > 0;)
{
if (row_counts_[i] <= row_counts_.back())
{
sink.push_back(options_.field_delimiter());
}
else
{
break;
}
}
}
if (column_index_ > 0)
{
sink.push_back(options_.field_delimiter());
}
break;
}
case stack_item_kind::row_multi_valued_field:
case stack_item_kind::column_multi_valued_field:
if (stack_.back().count_ > 0 && options_.subfield_delimiter() != char_type())
{
sink.push_back(options_.subfield_delimiter());
}
break;
default:
break;
}
}
void end_value()
{
JSONCONS_ASSERT(!stack_.empty());
switch(stack_.back().item_kind_)
{
case stack_item_kind::row:
{
++stack_.back().count_;
break;
}
case stack_item_kind::column:
{
++row_counts_.back();
break;
}
default:
++stack_.back().count_;
break;
}
}
};
using csv_stream_encoder = basic_csv_encoder<char>;
using csv_string_encoder = basic_csv_encoder<char,jsoncons::string_sink<std::string>>;
using csv_wstream_encoder = basic_csv_encoder<wchar_t>;
using wcsv_string_encoder = basic_csv_encoder<wchar_t,jsoncons::string_sink<std::wstring>>;
#if !defined(JSONCONS_NO_DEPRECATED)
template<class CharT, class Sink = jsoncons::stream_sink<CharT>, class Allocator = std::allocator<CharT>>
using basic_csv_serializer = basic_csv_encoder<CharT,Sink,Allocator>;
JSONCONS_DEPRECATED_MSG("Instead, use csv_stream_encoder") typedef csv_stream_encoder csv_serializer;
JSONCONS_DEPRECATED_MSG("Instead, use csv_string_encoder") typedef csv_string_encoder csv_string_serializer;
JSONCONS_DEPRECATED_MSG("Instead, use csv_stream_encoder") typedef csv_stream_encoder csv_serializer;
JSONCONS_DEPRECATED_MSG("Instead, use csv_string_encoder") typedef csv_string_encoder csv_string_serializer;
JSONCONS_DEPRECATED_MSG("Instead, use csv_stream_encoder") typedef csv_stream_encoder csv_encoder;
JSONCONS_DEPRECATED_MSG("Instead, use wcsv_stream_encoder") typedef csv_stream_encoder wcsv_encoder;
#endif
}}
#endif

View file

@ -0,0 +1,85 @@
/// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_CSV_CSV_ERROR_HPP
#define JSONCONS_CSV_CSV_ERROR_HPP
#include <system_error>
#include <jsoncons/json_exception.hpp>
namespace jsoncons { namespace csv {
enum class csv_errc : int
{
success = 0,
unexpected_eof = 1,
source_error,
expected_quote,
syntax_error,
invalid_parse_state,
invalid_escaped_char,
unexpected_char_between_fields
};
#if !defined(JSONCONS_NO_DEPRECATED)
JSONCONS_DEPRECATED_MSG("Instead, use csv_errc") typedef csv_errc csv_parser_errc;
#endif
class csv_error_category_impl
: public std::error_category
{
public:
const char* name() const noexcept override
{
return "jsoncons/csv";
}
std::string message(int ev) const override
{
switch (static_cast<csv_errc>(ev))
{
case csv_errc::unexpected_eof:
return "Unexpected end of file";
case csv_errc::source_error:
return "Source error";
case csv_errc::expected_quote:
return "Expected quote character";
case csv_errc::syntax_error:
return "CSV syntax error";
case csv_errc::invalid_parse_state:
return "Invalid CSV parser state";
case csv_errc::invalid_escaped_char:
return "Invalid character following quote escape character";
case csv_errc::unexpected_char_between_fields:
return "Unexpected character between fields";
default:
return "Unknown CSV parser error";
}
}
};
inline
const std::error_category& csv_error_category()
{
static csv_error_category_impl instance;
return instance;
}
inline
std::error_code make_error_code(csv_errc result)
{
return std::error_code(static_cast<int>(result),csv_error_category());
}
}}
namespace std {
template<>
struct is_error_code_enum<jsoncons::csv::csv_errc> : public true_type
{
};
}
#endif

View file

@ -0,0 +1,973 @@
// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_CSV_CSV_OPTIONS_HPP
#define JSONCONS_CSV_CSV_OPTIONS_HPP
#include <string>
#include <vector>
#include <utility> // std::pair
#include <unordered_map> // std::unordered_map
#include <map>
#include <limits> // std::numeric_limits
#include <cwchar>
#include <jsoncons/json_options.hpp>
namespace jsoncons { namespace csv {
enum class csv_column_type : uint8_t
{
string_t,integer_t,float_t,boolean_t,repeat_t
};
enum class quote_style_kind : uint8_t
{
minimal,all,nonnumeric,none
};
enum class csv_mapping_kind : uint8_t
{
n_rows = 1,
n_objects,
m_columns
};
#if !defined(JSONCONS_NO_DEPRECATED)
using mapping_kind = csv_mapping_kind;
JSONCONS_DEPRECATED_MSG("Instead, use quote_style_kind") typedef quote_style_kind quote_styles;
JSONCONS_DEPRECATED_MSG("Instead, use quote_style_kind") typedef quote_style_kind quote_style_type;
JSONCONS_DEPRECATED_MSG("Instead, use csv_mapping_kind") typedef csv_mapping_kind mapping_type;
#endif
enum class column_state {sequence,label};
struct csv_type_info
{
csv_type_info() = default;
csv_type_info(const csv_type_info&) = default;
csv_type_info(csv_type_info&&) = default;
csv_type_info(csv_column_type ctype, std::size_t lev, std::size_t repcount = 0) noexcept
{
col_type = ctype;
level = lev;
rep_count = repcount;
}
csv_column_type col_type;
std::size_t level;
std::size_t rep_count;
};
namespace detail {
template <class CharT,class Container>
void parse_column_names(const std::basic_string<CharT>& names,
Container& cont)
{
column_state state = column_state::sequence;
typename Container::value_type buffer(cont.get_allocator());
auto p = names.begin();
while (p != names.end())
{
switch (state)
{
case column_state::sequence:
{
switch (*p)
{
case ' ': case '\t':case '\r': case '\n':
++p;
break;
default:
buffer.clear();
state = column_state::label;
break;
}
break;
}
case column_state::label:
{
switch (*p)
{
case ',':
cont.push_back(buffer);
buffer.clear();
++p;
state = column_state::sequence;
break;
default:
buffer.push_back(*p);
++p;
break;
}
break;
}
}
}
if (state == column_state::label)
{
cont.push_back(buffer);
buffer.clear();
}
}
template <class CharT,class Container>
void parse_column_types(const std::basic_string<CharT>& types,
Container& column_types)
{
const std::map<jsoncons::basic_string_view<CharT>,csv_column_type> type_dictionary =
{
{JSONCONS_STRING_VIEW_CONSTANT(CharT,"string"),csv_column_type::string_t},
{JSONCONS_STRING_VIEW_CONSTANT(CharT,"integer"),csv_column_type::integer_t},
{JSONCONS_STRING_VIEW_CONSTANT(CharT,"float"),csv_column_type::float_t},
{JSONCONS_STRING_VIEW_CONSTANT(CharT,"boolean"),csv_column_type::boolean_t}
};
column_state state = column_state::sequence;
int depth = 0;
std::basic_string<CharT> buffer;
auto p = types.begin();
while (p != types.end())
{
switch (state)
{
case column_state::sequence:
{
switch (*p)
{
case ' ': case '\t':case '\r': case '\n':
++p;
break;
case '[':
++depth;
++p;
break;
case ']':
JSONCONS_ASSERT(depth > 0);
--depth;
++p;
break;
case '*':
{
JSONCONS_ASSERT(column_types.size() != 0);
std::size_t offset = 0;
std::size_t level = column_types.size() > 0 ? column_types.back().level: 0;
if (level > 0)
{
for (auto it = column_types.rbegin();
it != column_types.rend() && level == it->level;
++it)
{
++offset;
}
}
else
{
offset = 1;
}
column_types.emplace_back(csv_column_type::repeat_t,depth,offset);
++p;
break;
}
default:
buffer.clear();
state = column_state::label;
break;
}
break;
}
case column_state::label:
{
switch (*p)
{
case '*':
{
auto it = type_dictionary.find(buffer);
if (it != type_dictionary.end())
{
column_types.emplace_back(it->second,depth);
buffer.clear();
}
else
{
JSONCONS_ASSERT(false);
}
state = column_state::sequence;
break;
}
case ',':
{
auto it = type_dictionary.find(buffer);
if (it != type_dictionary.end())
{
column_types.emplace_back(it->second,depth);
buffer.clear();
}
else
{
JSONCONS_ASSERT(false);
}
++p;
state = column_state::sequence;
break;
}
case ']':
{
JSONCONS_ASSERT(depth > 0);
auto it = type_dictionary.find(buffer);
if (it != type_dictionary.end())
{
column_types.emplace_back(it->second,depth);
buffer.clear();
}
else
{
JSONCONS_ASSERT(false);
}
--depth;
++p;
state = column_state::sequence;
break;
}
default:
{
buffer.push_back(*p);
++p;
break;
}
}
break;
}
}
}
if (state == column_state::label)
{
auto it = type_dictionary.find(buffer);
if (it != type_dictionary.end())
{
column_types.emplace_back(it->second,depth);
buffer.clear();
}
else
{
JSONCONS_ASSERT(false);
}
}
}
} // detail
template <class CharT>
class basic_csv_options;
template <class CharT>
class basic_csv_options_common
{
friend class basic_csv_options<CharT>;
public:
using char_type = CharT;
using string_type = std::basic_string<CharT>;
private:
char_type field_delimiter_;
char_type quote_char_;
char_type quote_escape_char_;
char_type subfield_delimiter_;
bool enable_nan_to_num_:1;
bool enable_inf_to_num_:1;
bool enable_neginf_to_num_:1;
bool enable_nan_to_str_:1;
bool enable_inf_to_str_:1;
bool enable_neginf_to_str_:1;
bool enable_str_to_nan_:1;
bool enable_str_to_inf_:1;
bool enable_str_to_neginf_:1;
string_type nan_to_num_;
string_type inf_to_num_;
string_type neginf_to_num_;
string_type nan_to_str_;
string_type inf_to_str_;
string_type neginf_to_str_;
string_type column_names_;
protected:
basic_csv_options_common()
: field_delimiter_(','),
quote_char_('\"'),
quote_escape_char_('\"'),
subfield_delimiter_(char_type()),
enable_nan_to_num_(false),
enable_inf_to_num_(false),
enable_neginf_to_num_(false),
enable_nan_to_str_(false),
enable_inf_to_str_(false),
enable_neginf_to_str_(false),
enable_str_to_nan_(false),
enable_str_to_inf_(false),
enable_str_to_neginf_(false)
{
}
basic_csv_options_common(const basic_csv_options_common&) = default;
basic_csv_options_common& operator=(const basic_csv_options_common&) = default;
virtual ~basic_csv_options_common() noexcept = default;
public:
char_type field_delimiter() const
{
return field_delimiter_;
}
const char_type subfield_delimiter() const
{
return subfield_delimiter_;
}
char_type quote_char() const
{
return quote_char_;
}
char_type quote_escape_char() const
{
return quote_escape_char_;
}
string_type column_names() const
{
return column_names_;
}
bool enable_nan_to_num() const
{
return enable_nan_to_num_;
}
bool enable_inf_to_num() const
{
return enable_inf_to_num_;
}
bool enable_neginf_to_num() const
{
return enable_neginf_to_num_ || enable_inf_to_num_;
}
bool enable_nan_to_str() const
{
return enable_nan_to_str_;
}
bool enable_str_to_nan() const
{
return enable_str_to_nan_;
}
bool enable_inf_to_str() const
{
return enable_inf_to_str_;
}
bool enable_str_to_inf() const
{
return enable_str_to_inf_;
}
bool enable_neginf_to_str() const
{
return enable_neginf_to_str_ || enable_inf_to_str_;
}
bool enable_str_to_neginf() const
{
return enable_str_to_neginf_ || enable_str_to_inf_;
}
string_type nan_to_num() const
{
return nan_to_num_;
}
string_type inf_to_num() const
{
return inf_to_num_;
}
string_type neginf_to_num() const
{
if (enable_neginf_to_num_)
{
return neginf_to_num_;
}
else if (enable_inf_to_num_)
{
string_type s;
s.push_back('-');
s.append(inf_to_num_);
return s;
}
else
{
return neginf_to_num_;
}
}
string_type nan_to_str() const
{
return nan_to_str_;
}
string_type inf_to_str() const
{
return inf_to_str_;
}
string_type neginf_to_str() const
{
if (enable_neginf_to_str_)
{
return neginf_to_str_;
}
else if (enable_inf_to_str_)
{
string_type s;
s.push_back('-');
s.append(inf_to_str_);
return s;
}
else
{
return neginf_to_str_; // empty string
}
}
};
template <class CharT>
class basic_csv_decode_options : public virtual basic_csv_options_common<CharT>
{
friend class basic_csv_options<CharT>;
using super_type = basic_csv_options_common<CharT>;
public:
using typename super_type::char_type;
using typename super_type::string_type;
private:
bool assume_header_:1;
bool ignore_empty_values_:1;
bool ignore_empty_lines_:1;
bool trim_leading_:1;
bool trim_trailing_:1;
bool trim_leading_inside_quotes_:1;
bool trim_trailing_inside_quotes_:1;
bool unquoted_empty_value_is_null_:1;
bool infer_types_:1;
bool lossless_number_:1;
char_type comment_starter_;
csv_mapping_kind mapping_;
std::size_t header_lines_;
std::size_t max_lines_;
string_type column_types_;
string_type column_defaults_;
public:
basic_csv_decode_options()
: assume_header_(false),
ignore_empty_values_(false),
ignore_empty_lines_(true),
trim_leading_(false),
trim_trailing_(false),
trim_leading_inside_quotes_(false),
trim_trailing_inside_quotes_(false),
unquoted_empty_value_is_null_(false),
infer_types_(true),
lossless_number_(false),
comment_starter_('\0'),
mapping_(),
header_lines_(0),
max_lines_((std::numeric_limits<std::size_t>::max)())
{}
basic_csv_decode_options(const basic_csv_decode_options& other) = default;
basic_csv_decode_options(basic_csv_decode_options&& other)
: super_type(std::forward<basic_csv_decode_options>(other)),
assume_header_(other.assume_header_),
ignore_empty_values_(other.ignore_empty_values_),
ignore_empty_lines_(other.ignore_empty_lines_),
trim_leading_(other.trim_leading_),
trim_trailing_(other.trim_trailing_),
trim_leading_inside_quotes_(other.trim_leading_inside_quotes_),
trim_trailing_inside_quotes_(other.trim_trailing_inside_quotes_),
unquoted_empty_value_is_null_(other.unquoted_empty_value_is_null_),
infer_types_(other.infer_types_),
lossless_number_(other.lossless_number_),
comment_starter_(other.comment_starter_),
mapping_(other.mapping_),
header_lines_(other.header_lines_),
max_lines_(other.max_lines_),
column_types_(std::move(other.column_types_)),
column_defaults_(std::move(other.column_defaults_))
{}
std::size_t header_lines() const
{
return (assume_header_ && header_lines_ <= 1) ? 1 : header_lines_;
}
bool assume_header() const
{
return assume_header_;
}
bool ignore_empty_values() const
{
return ignore_empty_values_;
}
bool ignore_empty_lines() const
{
return ignore_empty_lines_;
}
bool trim_leading() const
{
return trim_leading_;
}
bool trim_trailing() const
{
return trim_trailing_;
}
bool trim_leading_inside_quotes() const
{
return trim_leading_inside_quotes_;
}
bool trim_trailing_inside_quotes() const
{
return trim_trailing_inside_quotes_;
}
bool trim() const
{
return trim_leading_ && trim_trailing_;
}
bool trim_inside_quotes() const
{
return trim_leading_inside_quotes_ && trim_trailing_inside_quotes_;
}
bool unquoted_empty_value_is_null() const
{
return unquoted_empty_value_is_null_;
}
bool infer_types() const
{
return infer_types_;
}
bool lossless_number() const
{
return lossless_number_;
}
char_type comment_starter() const
{
return comment_starter_;
}
csv_mapping_kind mapping_kind() const
{
return mapping_ != csv_mapping_kind() ? mapping_ : (assume_header() || this->column_names().size() > 0 ? csv_mapping_kind::n_objects : csv_mapping_kind::n_rows);
}
#if !defined(JSONCONS_NO_DEPRECATED)
csv_mapping_kind mapping() const
{
return mapping_kind();
}
#endif
std::size_t max_lines() const
{
return max_lines_;
}
string_type column_types() const
{
return column_types_;
}
string_type column_defaults() const
{
return column_defaults_;
}
};
template <class CharT>
class basic_csv_encode_options : public virtual basic_csv_options_common<CharT>
{
friend class basic_csv_options<CharT>;
using super_type = basic_csv_options_common<CharT>;
public:
using typename super_type::char_type;
using typename super_type::string_type;
private:
quote_style_kind quote_style_;
float_chars_format float_format_;
int8_t precision_;
string_type line_delimiter_;
public:
basic_csv_encode_options()
: quote_style_(quote_style_kind::minimal),
float_format_(float_chars_format::general),
precision_(0)
{
line_delimiter_.push_back('\n');
}
basic_csv_encode_options(const basic_csv_encode_options& other) = default;
basic_csv_encode_options(basic_csv_encode_options&& other)
: super_type(std::forward<basic_csv_encode_options>(other)),
quote_style_(other.quote_style_),
float_format_(other.float_format_),
precision_(other.precision_),
line_delimiter_(std::move(other.line_delimiter_))
{
}
quote_style_kind quote_style() const
{
return quote_style_;
}
float_chars_format float_format() const
{
return float_format_;
}
int8_t precision() const
{
return precision_;
}
string_type line_delimiter() const
{
return line_delimiter_;
}
};
template <class CharT>
class basic_csv_options final : public basic_csv_decode_options<CharT>, public basic_csv_encode_options<CharT>
{
using char_type = CharT;
using string_type = std::basic_string<CharT>;
public:
using basic_csv_decode_options<CharT>::enable_str_to_nan;
using basic_csv_decode_options<CharT>::enable_str_to_inf;
using basic_csv_decode_options<CharT>::enable_str_to_neginf;
using basic_csv_decode_options<CharT>::nan_to_str;
using basic_csv_decode_options<CharT>::inf_to_str;
using basic_csv_decode_options<CharT>::neginf_to_str;
using basic_csv_decode_options<CharT>::nan_to_num;
using basic_csv_decode_options<CharT>::inf_to_num;
using basic_csv_decode_options<CharT>::neginf_to_num;
using basic_csv_decode_options<CharT>::field_delimiter;
using basic_csv_decode_options<CharT>::subfield_delimiter;
using basic_csv_decode_options<CharT>::quote_char;
using basic_csv_decode_options<CharT>::quote_escape_char;
using basic_csv_decode_options<CharT>::column_names;
using basic_csv_decode_options<CharT>::header_lines;
using basic_csv_decode_options<CharT>::assume_header;
using basic_csv_decode_options<CharT>::ignore_empty_values;
using basic_csv_decode_options<CharT>::ignore_empty_lines;
using basic_csv_decode_options<CharT>::trim_leading;
using basic_csv_decode_options<CharT>::trim_trailing;
using basic_csv_decode_options<CharT>::trim_leading_inside_quotes;
using basic_csv_decode_options<CharT>::trim_trailing_inside_quotes;
using basic_csv_decode_options<CharT>::trim;
using basic_csv_decode_options<CharT>::trim_inside_quotes;
using basic_csv_decode_options<CharT>::unquoted_empty_value_is_null;
using basic_csv_decode_options<CharT>::infer_types;
using basic_csv_decode_options<CharT>::lossless_number;
using basic_csv_decode_options<CharT>::comment_starter;
using basic_csv_decode_options<CharT>::mapping;
using basic_csv_decode_options<CharT>::max_lines;
using basic_csv_decode_options<CharT>::column_types;
using basic_csv_decode_options<CharT>::column_defaults;
using basic_csv_encode_options<CharT>::float_format;
using basic_csv_encode_options<CharT>::precision;
using basic_csv_encode_options<CharT>::line_delimiter;
using basic_csv_encode_options<CharT>::quote_style;
static constexpr size_t default_indent = 4;
// Constructors
basic_csv_options() = default;
basic_csv_options(const basic_csv_options&) = default;
basic_csv_options(basic_csv_options&&) = default;
basic_csv_options& operator=(const basic_csv_options&) = default;
basic_csv_options& operator=(basic_csv_options&&) = default;
basic_csv_options& float_format(float_chars_format value)
{
this->float_format_ = value;
return *this;
}
basic_csv_options& precision(int8_t value)
{
this->precision_ = value;
return *this;
}
basic_csv_options& header_lines(std::size_t value)
{
this->header_lines_ = value;
return *this;
}
basic_csv_options& assume_header(bool value)
{
this->assume_header_ = value;
return *this;
}
basic_csv_options& ignore_empty_values(bool value)
{
this->ignore_empty_values_ = value;
return *this;
}
basic_csv_options& ignore_empty_lines(bool value)
{
this->ignore_empty_lines_ = value;
return *this;
}
basic_csv_options& trim_leading(bool value)
{
this->trim_leading_ = value;
return *this;
}
basic_csv_options& trim_trailing(bool value)
{
this->trim_trailing_ = value;
return *this;
}
basic_csv_options& trim_leading_inside_quotes(bool value)
{
this->trim_leading_inside_quotes_ = value;
return *this;
}
basic_csv_options& trim_trailing_inside_quotes(bool value)
{
this->trim_trailing_inside_quotes_ = value;
return *this;
}
basic_csv_options& trim(bool value)
{
this->trim_leading_ = value;
this->trim_trailing_ = value;
return *this;
}
basic_csv_options& trim_inside_quotes(bool value)
{
this->trim_leading_inside_quotes_ = value;
this->trim_trailing_inside_quotes_ = value;
return *this;
}
basic_csv_options& unquoted_empty_value_is_null(bool value)
{
this->unquoted_empty_value_is_null_ = value;
return *this;
}
basic_csv_options& column_names(const string_type& value)
{
this->column_names_ = value;
return *this;
}
basic_csv_options& column_types(const string_type& value)
{
this->column_types_ = value;
return *this;
}
basic_csv_options& column_defaults(const string_type& value)
{
this->column_defaults_ = value;
return *this;
}
basic_csv_options& field_delimiter(char_type value)
{
this->field_delimiter_ = value;
return *this;
}
basic_csv_options& subfield_delimiter(char_type value)
{
this->subfield_delimiter_ = value;
return *this;
}
basic_csv_options& line_delimiter(const string_type& value)
{
this->line_delimiter_ = value;
return *this;
}
basic_csv_options& quote_char(char_type value)
{
this->quote_char_ = value;
return *this;
}
basic_csv_options& infer_types(bool value)
{
this->infer_types_ = value;
return *this;
}
basic_csv_options& lossless_number(bool value)
{
this->lossless_number_ = value;
return *this;
}
basic_csv_options& quote_escape_char(char_type value)
{
this->quote_escape_char_ = value;
return *this;
}
basic_csv_options& comment_starter(char_type value)
{
this->comment_starter_ = value;
return *this;
}
basic_csv_options& quote_style(quote_style_kind value)
{
this->quote_style_ = value;
return *this;
}
//#if !defined(JSONCONS_NO_DEPRECATED)
basic_csv_options& mapping(csv_mapping_kind value)
{
this->mapping_ = value;
return *this;
}
//#endif
basic_csv_options& mapping_kind(csv_mapping_kind value)
{
this->mapping_ = value;
return *this;
}
basic_csv_options& max_lines(std::size_t value)
{
this->max_lines_ = value;
return *this;
}
basic_csv_options& nan_to_num(const string_type& value)
{
this->enable_nan_to_num_ = true;
this->nan_to_str_.clear();
this->nan_to_num_ = value;
return *this;
}
basic_csv_options& inf_to_num(const string_type& value)
{
this->enable_inf_to_num_ = true;
this->inf_to_str_.clear();
this->inf_to_num_ = value;
return *this;
}
basic_csv_options& neginf_to_num(const string_type& value)
{
this->enable_neginf_to_num_ = true;
this->neginf_to_str_.clear();
this->neginf_to_num_ = value;
return *this;
}
basic_csv_options& nan_to_str(const string_type& value, bool enable_inverse = true)
{
this->enable_nan_to_str_ = true;
this->enable_str_to_nan_ = enable_inverse;
this->nan_to_num_.clear();
this->nan_to_str_ = value;
return *this;
}
basic_csv_options& inf_to_str(const string_type& value, bool enable_inverse = true)
{
this->enable_inf_to_str_ = true;
this->enable_inf_to_str_ = enable_inverse;
this->inf_to_num_.clear();
this->inf_to_str_ = value;
return *this;
}
basic_csv_options& neginf_to_str(const string_type& value, bool enable_inverse = true)
{
this->enable_neginf_to_str_ = true;
this->enable_neginf_to_str_ = enable_inverse;
this->neginf_to_num_.clear();
this->neginf_to_str_ = value;
return *this;
}
#if !defined(JSONCONS_NO_DEPRECATED)
JSONCONS_DEPRECATED_MSG("Instead, use float_format(float_chars_format)")
basic_csv_options& floating_point_format(float_chars_format value)
{
this->float_format_ = value;
return *this;
}
#endif
};
using csv_options = basic_csv_options<char>;
using wcsv_options = basic_csv_options<wchar_t>;
#if !defined(JSONCONS_NO_DEPRECATED)
JSONCONS_DEPRECATED_MSG("Instead, use csv_options") typedef csv_options csv_parameters;
JSONCONS_DEPRECATED_MSG("Instead, use wcsv_options") typedef wcsv_options wcsv_parameters;
JSONCONS_DEPRECATED_MSG("Instead, use csv_options") typedef csv_options csv_serializing_options;
JSONCONS_DEPRECATED_MSG("Instead, use wcsv_options") typedef wcsv_options wcsv_serializing_options;
#endif
}}
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,348 @@
// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_CSV_CSV_READER_HPP
#define JSONCONS_CSV_CSV_READER_HPP
#include <string>
#include <vector>
#include <stdexcept>
#include <memory> // std::allocator
#include <utility> // std::move
#include <istream> // std::basic_istream
#include <jsoncons/source.hpp>
#include <jsoncons/json_exception.hpp>
#include <jsoncons/json_visitor.hpp>
#include <jsoncons_ext/csv/csv_error.hpp>
#include <jsoncons_ext/csv/csv_parser.hpp>
#include <jsoncons/json.hpp>
#include <jsoncons/json_reader.hpp>
#include <jsoncons/json_decoder.hpp>
#include <jsoncons/source_adaptor.hpp>
#include <jsoncons_ext/csv/csv_options.hpp>
namespace jsoncons { namespace csv {
template<class CharT,class Source=jsoncons::stream_source<CharT>,class Allocator=std::allocator<char>>
class basic_csv_reader
{
struct stack_item
{
stack_item() noexcept
: array_begun_(false)
{
}
bool array_begun_;
};
using char_type = CharT;
using temp_allocator_type = Allocator;
typedef typename std::allocator_traits<temp_allocator_type>:: template rebind_alloc<CharT> char_allocator_type;
basic_csv_reader(const basic_csv_reader&) = delete;
basic_csv_reader& operator = (const basic_csv_reader&) = delete;
basic_default_json_visitor<CharT> default_visitor_;
text_source_adaptor<Source> source_;
basic_json_visitor<CharT>& visitor_;
basic_csv_parser<CharT,Allocator> parser_;
public:
// Structural characters
static constexpr size_t default_max_buffer_size = 16384;
//! Parse an input stream of CSV text into a json object
/*!
\param is The input stream to read from
*/
template <class Sourceable>
basic_csv_reader(Sourceable&& source,
basic_json_visitor<CharT>& visitor,
const Allocator& alloc = Allocator())
: basic_csv_reader(std::forward<Sourceable>(source),
visitor,
basic_csv_decode_options<CharT>(),
default_csv_parsing(),
alloc)
{
}
template <class Sourceable>
basic_csv_reader(Sourceable&& source,
basic_json_visitor<CharT>& visitor,
const basic_csv_decode_options<CharT>& options,
const Allocator& alloc = Allocator())
: basic_csv_reader(std::forward<Sourceable>(source),
visitor,
options,
default_csv_parsing(),
alloc)
{
}
template <class Sourceable>
basic_csv_reader(Sourceable&& source,
basic_json_visitor<CharT>& visitor,
std::function<bool(csv_errc,const ser_context&)> err_handler,
const Allocator& alloc = Allocator())
: basic_csv_reader(std::forward<Sourceable>(source),
visitor,
basic_csv_decode_options<CharT>(),
err_handler,
alloc)
{
}
template <class Sourceable>
basic_csv_reader(Sourceable&& source,
basic_json_visitor<CharT>& visitor,
const basic_csv_decode_options<CharT>& options,
std::function<bool(csv_errc,const ser_context&)> err_handler,
const Allocator& alloc = Allocator())
: source_(std::forward<Sourceable>(source)),
visitor_(visitor),
parser_(options, err_handler, alloc)
{
}
~basic_csv_reader() noexcept = default;
void read()
{
std::error_code ec;
read(ec);
if (ec)
{
JSONCONS_THROW(ser_error(ec,parser_.line(),parser_.column()));
}
}
void read(std::error_code& ec)
{
read_internal(ec);
}
std::size_t line() const
{
return parser_.line();
}
std::size_t column() const
{
return parser_.column();
}
bool eof() const
{
return parser_.source_exhausted() && source_.eof();
}
private:
void read_internal(std::error_code& ec)
{
if (source_.is_error())
{
ec = csv_errc::source_error;
return;
}
while (!parser_.stopped())
{
if (parser_.source_exhausted())
{
auto s = source_.read_buffer(ec);
if (ec) return;
if (s.size() > 0)
{
parser_.update(s.data(),s.size());
}
}
parser_.parse_some(visitor_, ec);
if (ec) return;
}
}
};
template<class CharT,class Source=jsoncons::stream_source<CharT>,class Allocator=std::allocator<char>>
class legacy_basic_csv_reader
{
struct stack_item
{
stack_item() noexcept
: array_begun_(false)
{
}
bool array_begun_;
};
using char_type = CharT;
using temp_allocator_type = Allocator;
typedef typename std::allocator_traits<temp_allocator_type>:: template rebind_alloc<CharT> char_allocator_type;
legacy_basic_csv_reader(const legacy_basic_csv_reader&) = delete;
legacy_basic_csv_reader& operator = (const legacy_basic_csv_reader&) = delete;
basic_default_json_visitor<CharT> default_visitor_;
text_source_adaptor<Source> source_;
basic_json_visitor<CharT>& visitor_;
basic_csv_parser<CharT,Allocator> parser_;
public:
// Structural characters
static constexpr size_t default_max_buffer_size = 16384;
//! Parse an input stream of CSV text into a json object
/*!
\param is The input stream to read from
*/
template <class Sourceable>
legacy_basic_csv_reader(Sourceable&& source,
basic_json_visitor<CharT>& visitor,
const Allocator& alloc = Allocator())
: legacy_basic_csv_reader(std::forward<Sourceable>(source),
visitor,
basic_csv_decode_options<CharT>(),
default_csv_parsing(),
alloc)
{
}
template <class Sourceable>
legacy_basic_csv_reader(Sourceable&& source,
basic_json_visitor<CharT>& visitor,
const basic_csv_decode_options<CharT>& options,
const Allocator& alloc = Allocator())
: legacy_basic_csv_reader(std::forward<Sourceable>(source),
visitor,
options,
default_csv_parsing(),
alloc)
{
}
template <class Sourceable>
legacy_basic_csv_reader(Sourceable&& source,
basic_json_visitor<CharT>& visitor,
std::function<bool(csv_errc,const ser_context&)> err_handler,
const Allocator& alloc = Allocator())
: legacy_basic_csv_reader(std::forward<Sourceable>(source),
visitor,
basic_csv_decode_options<CharT>(),
err_handler,
alloc)
{
}
template <class Sourceable>
legacy_basic_csv_reader(Sourceable&& source,
basic_json_visitor<CharT>& visitor,
const basic_csv_decode_options<CharT>& options,
std::function<bool(csv_errc,const ser_context&)> err_handler,
const Allocator& alloc = Allocator(),
typename std::enable_if<!std::is_constructible<jsoncons::basic_string_view<CharT>,Sourceable>::value>::type* = 0)
: source_(std::forward<Sourceable>(source)),
visitor_(visitor),
parser_(options, err_handler, alloc)
{
}
template <class Sourceable>
legacy_basic_csv_reader(Sourceable&& source,
basic_json_visitor<CharT>& visitor,
const basic_csv_decode_options<CharT>& options,
std::function<bool(csv_errc,const ser_context&)> err_handler,
const Allocator& alloc = Allocator(),
typename std::enable_if<std::is_constructible<jsoncons::basic_string_view<CharT>,Sourceable>::value>::type* = 0)
: source_(),
visitor_(visitor),
parser_(options, err_handler, alloc)
{
jsoncons::basic_string_view<CharT> sv(std::forward<Sourceable>(source));
auto r = unicode_traits::detect_encoding_from_bom(sv.data(), sv.size());
if (!(r.encoding == unicode_traits::encoding_kind::utf8 || r.encoding == unicode_traits::encoding_kind::undetected))
{
JSONCONS_THROW(ser_error(json_errc::illegal_unicode_character,parser_.line(),parser_.column()));
}
std::size_t offset = (r.ptr - sv.data());
parser_.update(sv.data()+offset,sv.size()-offset);
}
~legacy_basic_csv_reader() noexcept = default;
void read()
{
std::error_code ec;
read(ec);
if (ec)
{
JSONCONS_THROW(ser_error(ec,parser_.line(),parser_.column()));
}
}
void read(std::error_code& ec)
{
read_internal(ec);
}
std::size_t line() const
{
return parser_.line();
}
std::size_t column() const
{
return parser_.column();
}
bool eof() const
{
return parser_.source_exhausted() && source_.eof();
}
private:
void read_internal(std::error_code& ec)
{
if (source_.is_error())
{
ec = csv_errc::source_error;
return;
}
while (!parser_.stopped())
{
if (parser_.source_exhausted())
{
auto s = source_.read_buffer(ec);
if (ec) return;
if (s.size() > 0)
{
parser_.update(s.data(),s.size());
}
}
parser_.parse_some(visitor_, ec);
if (ec) return;
}
}
};
#if !defined(JSONCONS_NO_DEPRECATED)
using csv_reader = legacy_basic_csv_reader<char>;
using wcsv_reader = legacy_basic_csv_reader<wchar_t>;
#endif
using csv_string_reader = basic_csv_reader<char,string_source<char>>;
using wcsv_string_reader = basic_csv_reader<wchar_t,string_source<wchar_t>>;
using csv_stream_reader = basic_csv_reader<char,stream_source<char>>;
using wcsv_stream_reader = basic_csv_reader<wchar_t,stream_source<wchar_t>>;
}}
#endif

View file

@ -0,0 +1,12 @@
// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_CSV_CSV_SERIALIZER_HPP
#define JSONCONS_CSV_CSV_SERIALIZER_HPP
#include <jsoncons_ext/csv/csv_encoder.hpp>
#endif

View file

@ -0,0 +1,208 @@
/// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_CSV_DECODE_CSV_HPP
#define JSONCONS_CSV_DECODE_CSV_HPP
#include <jsoncons_ext/csv/csv_options.hpp>
#include <jsoncons_ext/csv/csv_reader.hpp>
#include <jsoncons_ext/csv/csv_encoder.hpp>
#include <jsoncons_ext/csv/csv_cursor.hpp>
namespace jsoncons {
namespace csv {
template <class T,class Source>
typename std::enable_if<extension_traits::is_basic_json<T>::value &&
extension_traits::is_sequence_of<Source,typename T::char_type>::value,T>::type
decode_csv(const Source& s, const basic_csv_decode_options<typename Source::value_type>& options = basic_csv_decode_options<typename Source::value_type>())
{
using char_type = typename Source::value_type;
json_decoder<T> decoder;
basic_csv_reader<char_type,jsoncons::string_source<char_type>> reader(s,decoder,options);
reader.read();
if (!decoder.is_valid())
{
JSONCONS_THROW(ser_error(conv_errc::conversion_failed, reader.line(), reader.column()));
}
return decoder.get_result();
}
template <class T,class Source>
typename std::enable_if<!extension_traits::is_basic_json<T>::value &&
extension_traits::is_char_sequence<Source>::value,T>::type
decode_csv(const Source& s, const basic_csv_decode_options<typename Source::value_type>& options = basic_csv_decode_options<typename Source::value_type>())
{
using char_type = typename Source::value_type;
basic_csv_cursor<char_type> cursor(s, options);
jsoncons::json_decoder<basic_json<char_type>> decoder;
std::error_code ec;
T val = decode_traits<T,char_type>::decode(cursor, decoder, ec);
if (ec)
{
JSONCONS_THROW(ser_error(ec, cursor.context().line(), cursor.context().column()));
}
return val;
}
template <class T,class CharT>
typename std::enable_if<extension_traits::is_basic_json<T>::value,T>::type
decode_csv(std::basic_istream<CharT>& is, const basic_csv_decode_options<CharT>& options = basic_csv_decode_options<CharT>())
{
using char_type = CharT;
json_decoder<T> decoder;
basic_csv_reader<char_type,jsoncons::stream_source<char_type>> reader(is,decoder,options);
reader.read();
if (!decoder.is_valid())
{
JSONCONS_THROW(ser_error(conv_errc::conversion_failed, reader.line(), reader.column()));
}
return decoder.get_result();
}
template <class T,class CharT>
typename std::enable_if<!extension_traits::is_basic_json<T>::value,T>::type
decode_csv(std::basic_istream<CharT>& is, const basic_csv_decode_options<CharT>& options = basic_csv_decode_options<CharT>())
{
basic_csv_cursor<CharT> cursor(is, options);
jsoncons::json_decoder<basic_json<CharT>> decoder;
std::error_code ec;
T val = decode_traits<T,CharT>::decode(cursor, decoder, ec);
if (ec)
{
JSONCONS_THROW(ser_error(ec, cursor.context().line(), cursor.context().column()));
}
return val;
}
template <class T, class InputIt>
typename std::enable_if<extension_traits::is_basic_json<T>::value,T>::type
decode_csv(InputIt first, InputIt last,
const basic_csv_decode_options<typename std::iterator_traits<InputIt>::value_type>& options =
basic_csv_decode_options<typename std::iterator_traits<InputIt>::value_type>())
{
using char_type = typename std::iterator_traits<InputIt>::value_type;
jsoncons::json_decoder<T> decoder;
basic_csv_reader<char_type, iterator_source<InputIt>> reader(iterator_source<InputIt>(first,last), decoder, options);
reader.read();
if (!decoder.is_valid())
{
JSONCONS_THROW(ser_error(conv_errc::conversion_failed, reader.line(), reader.column()));
}
return decoder.get_result();
}
template <class T, class InputIt>
typename std::enable_if<!extension_traits::is_basic_json<T>::value,T>::type
decode_csv(InputIt first, InputIt last,
const basic_csv_decode_options<typename std::iterator_traits<InputIt>::value_type>& options =
basic_csv_decode_options<typename std::iterator_traits<InputIt>::value_type>())
{
using char_type = typename std::iterator_traits<InputIt>::value_type;
basic_csv_cursor<char_type,iterator_source<InputIt>> cursor(iterator_source<InputIt>(first, last), options);
jsoncons::json_decoder<basic_json<char_type>> decoder;
std::error_code ec;
T val = decode_traits<T,char_type>::decode(cursor, decoder, ec);
if (ec)
{
JSONCONS_THROW(ser_error(ec, cursor.context().line(), cursor.context().column()));
}
return val;
}
// With leading allocator parameter
template <class T,class Source,class TempAllocator>
typename std::enable_if<extension_traits::is_basic_json<T>::value &&
extension_traits::is_sequence_of<Source,typename T::char_type>::value,T>::type
decode_csv(temp_allocator_arg_t, const TempAllocator& temp_alloc,
const Source& s,
const basic_csv_decode_options<typename Source::value_type>& options = basic_csv_decode_options<typename Source::value_type>())
{
using char_type = typename Source::value_type;
json_decoder<T,TempAllocator> decoder(temp_alloc);
basic_csv_reader<char_type,jsoncons::string_source<char_type>,TempAllocator> reader(s,decoder,options,temp_alloc);
reader.read();
if (!decoder.is_valid())
{
JSONCONS_THROW(ser_error(conv_errc::conversion_failed, reader.line(), reader.column()));
}
return decoder.get_result();
}
template <class T,class Source,class TempAllocator>
typename std::enable_if<!extension_traits::is_basic_json<T>::value &&
extension_traits::is_char_sequence<Source>::value,T>::type
decode_csv(temp_allocator_arg_t, const TempAllocator& temp_alloc,
const Source& s,
const basic_csv_decode_options<typename Source::value_type>& options = basic_csv_decode_options<typename Source::value_type>())
{
using char_type = typename Source::value_type;
basic_csv_cursor<char_type,stream_source<char_type>,TempAllocator> cursor(s, options, temp_alloc);
json_decoder<basic_json<char_type,sorted_policy,TempAllocator>,TempAllocator> decoder(temp_alloc, temp_alloc);
std::error_code ec;
T val = decode_traits<T,char_type>::decode(cursor, decoder, ec);
if (ec)
{
JSONCONS_THROW(ser_error(ec, cursor.context().line(), cursor.context().column()));
}
return val;
}
template <class T,class CharT,class TempAllocator>
typename std::enable_if<extension_traits::is_basic_json<T>::value,T>::type
decode_csv(temp_allocator_arg_t, const TempAllocator& temp_alloc,
std::basic_istream<CharT>& is,
const basic_csv_decode_options<CharT>& options = basic_csv_decode_options<CharT>())
{
using char_type = CharT;
json_decoder<T,TempAllocator> decoder(temp_alloc);
basic_csv_reader<char_type,jsoncons::string_source<char_type>,TempAllocator> reader(is,decoder,options,temp_alloc);
reader.read();
if (!decoder.is_valid())
{
JSONCONS_THROW(ser_error(conv_errc::conversion_failed, reader.line(), reader.column()));
}
return decoder.get_result();
}
template <class T,class CharT,class TempAllocator>
typename std::enable_if<!extension_traits::is_basic_json<T>::value,T>::type
decode_csv(temp_allocator_arg_t, const TempAllocator& temp_alloc,
std::basic_istream<CharT>& is,
const basic_csv_decode_options<CharT>& options = basic_csv_decode_options<CharT>())
{
basic_csv_cursor<CharT,stream_source<CharT>,TempAllocator> cursor(is, options, temp_alloc);
json_decoder<basic_json<CharT,sorted_policy,TempAllocator>,TempAllocator> decoder(temp_alloc, temp_alloc);
std::error_code ec;
T val = decode_traits<T,CharT>::decode(cursor, decoder, ec);
if (ec)
{
JSONCONS_THROW(ser_error(ec, cursor.context().line(), cursor.context().column()));
}
return val;
}
} // namespace csv
} // namespace jsoncons
#endif

View file

@ -0,0 +1,122 @@
/// Copyright 2013-2023 Daniel Parker
// Distributed under the Boost license, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// See https://github.com/danielaparker/jsoncons for latest version
#ifndef JSONCONS_CSV_ENCODE_CSV_HPP
#define JSONCONS_CSV_ENCODE_CSV_HPP
#include <jsoncons_ext/csv/csv_options.hpp>
#include <jsoncons_ext/csv/csv_reader.hpp>
#include <jsoncons_ext/csv/csv_encoder.hpp>
namespace jsoncons {
namespace csv {
template <class T,class Container>
typename std::enable_if<extension_traits::is_basic_json<T>::value &&
extension_traits::is_back_insertable_char_container<Container>::value>::type
encode_csv(const T& j, Container& s, const basic_csv_encode_options<typename Container::value_type>& options = basic_csv_encode_options<typename Container::value_type>())
{
using char_type = typename Container::value_type;
basic_csv_encoder<char_type,jsoncons::string_sink<std::basic_string<char_type>>> encoder(s,options);
j.dump(encoder);
}
template <class T,class Container>
typename std::enable_if<!extension_traits::is_basic_json<T>::value &&
extension_traits::is_back_insertable_char_container<Container>::value>::type
encode_csv(const T& val, Container& s, const basic_csv_encode_options<typename Container::value_type>& options = basic_csv_encode_options<typename Container::value_type>())
{
using char_type = typename Container::value_type;
basic_csv_encoder<char_type,jsoncons::string_sink<std::basic_string<char_type>>> encoder(s,options);
std::error_code ec;
encode_traits<T,char_type>::encode(val, encoder, json(), ec);
if (ec)
{
JSONCONS_THROW(ser_error(ec));
}
}
template <class T, class CharT>
typename std::enable_if<extension_traits::is_basic_json<T>::value,void>::type
encode_csv(const T& j, std::basic_ostream<CharT>& os, const basic_csv_encode_options<CharT>& options = basic_csv_encode_options<CharT>())
{
using char_type = CharT;
basic_csv_encoder<char_type,jsoncons::stream_sink<char_type>> encoder(os,options);
j.dump(encoder);
}
template <class T, class CharT>
typename std::enable_if<!extension_traits::is_basic_json<T>::value,void>::type
encode_csv(const T& val, std::basic_ostream<CharT>& os, const basic_csv_encode_options<CharT>& options = basic_csv_encode_options<CharT>())
{
using char_type = CharT;
basic_csv_encoder<char_type,jsoncons::stream_sink<char_type>> encoder(os,options);
std::error_code ec;
encode_traits<T,CharT>::encode(val, encoder, json(), ec);
if (ec)
{
JSONCONS_THROW(ser_error(ec));
}
}
// with temp_allocator_arg_t
template <class T, class Container, class TempAllocator>
typename std::enable_if<extension_traits::is_basic_json<T>::value &&
extension_traits::is_back_insertable_char_container<Container>::value>::type
encode_csv(temp_allocator_arg_t, const TempAllocator& temp_alloc,
const T& j, Container& s, const basic_csv_encode_options<typename Container::value_type>& options = basic_csv_encode_options<typename Container::value_type>())
{
using char_type = typename Container::value_type;
basic_csv_encoder<char_type,jsoncons::string_sink<std::basic_string<char_type>>,TempAllocator> encoder(s, options, temp_alloc);
j.dump(encoder);
}
template <class T, class Container, class TempAllocator>
typename std::enable_if<!extension_traits::is_basic_json<T>::value &&
extension_traits::is_back_insertable_char_container<Container>::value>::type
encode_csv(temp_allocator_arg_t, const TempAllocator& temp_alloc,
const T& val, Container& s, const basic_csv_encode_options<typename Container::value_type>& options = basic_csv_encode_options<typename Container::value_type>())
{
using char_type = typename Container::value_type;
basic_csv_encoder<char_type,jsoncons::string_sink<std::basic_string<char_type>>,TempAllocator> encoder(s, options, temp_alloc);
std::error_code ec;
encode_traits<T,char_type>::encode(val, encoder, json(), ec);
if (ec)
{
JSONCONS_THROW(ser_error(ec));
}
}
template <class T, class CharT, class TempAllocator>
typename std::enable_if<extension_traits::is_basic_json<T>::value,void>::type
encode_csv(temp_allocator_arg_t, const TempAllocator& temp_alloc,
const T& j, std::basic_ostream<CharT>& os, const basic_csv_encode_options<CharT>& options = basic_csv_encode_options<CharT>())
{
using char_type = CharT;
basic_csv_encoder<char_type,jsoncons::stream_sink<char_type>,TempAllocator> encoder(os, options, temp_alloc);
j.dump(encoder);
}
template <class T, class CharT, class TempAllocator>
typename std::enable_if<!extension_traits::is_basic_json<T>::value,void>::type
encode_csv(temp_allocator_arg_t, const TempAllocator& temp_alloc,
const T& val, std::basic_ostream<CharT>& os, const basic_csv_encode_options<CharT>& options = basic_csv_encode_options<CharT>())
{
using char_type = CharT;
basic_csv_encoder<char_type,jsoncons::stream_sink<char_type>,TempAllocator> encoder(os, options, temp_alloc);
std::error_code ec;
encode_traits<T,CharT>::encode(val, encoder, json(), ec);
if (ec)
{
JSONCONS_THROW(ser_error(ec));
}
}
} // namespace csv
} // namespace jsoncons
#endif

File diff suppressed because it is too large Load diff

Some files were not shown because too many files have changed in this diff Show more