2
0
mirror of https://github.com/boostorg/json.git synced 2026-01-19 04:12:14 +00:00

Add files

This commit is contained in:
Vinnie Falco
2019-09-20 11:07:25 -07:00
parent 4a941f8801
commit a8773de80f
74 changed files with 17029 additions and 2 deletions

147
.appveyor.yml Normal file
View File

@@ -0,0 +1,147 @@
# Copyright 2016, 2017 Peter Dimov
# Copyright (C) 2017 - 2019 James E. King III
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt)
#
# Generic Appveyor build script for boostorg repositories
# See: https://github.com/boostorg/boost-ci/
#
# Instructions for customizing this script for your library:
#
# 1. Customize the compilers and language levels you want.
# 2. If you have more than include/, src/, test/, example/, examples/,
# benchmark/ or tools/ directories, set the environment variable DEPINST.
# For example if your build uses code in "bench/" and "fog/" directories:
# - DEPINST: --include bench --include fog
# 3. Enable pull request builds in your boostorg/<library> account.
#
# That's it - the script will do everything else for you.
#
version: 1.0.{build}-{branch}
shallow_clone: true
branches:
only:
- master
- develop
- /bugfix\/.*/
- /feature\/.*/
- /fix\/.*/
- /pr\/.*/
matrix:
# Adding MAYFAIL to any matrix job allows it to fail but the build stays green:
allow_failures:
- MAYFAIL: true
environment:
global:
# see: http://www.boost.org/build/doc/html/bbv2/overview/invocation.html#bbv2.overview.invocation.properties
# to use the default for a given environment, comment it out; recommend you build debug and release however:
# on Windows it is important to exercise all the possibilities, especially shared vs static, however most
# libraries that care about this exercise it in their Jamfiles...
# B2_ADDRESS_MODEL: address-model=64,32
# B2_LINK: link=shared,static
# B2_THREADING: threading=multi,single
B2_VARIANT: variant=release
matrix:
- FLAVOR: Visual Studio 2019
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
B2_ADDRESS_MODEL: address-model=64
B2_CXXFLAGS: cxxflags=-permissive-
B2_CXXSTD: latest # 2a
B2_TOOLSET: msvc-14.2
- FLAVOR: Visual Studio 2017 C++2a Strict
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
B2_ADDRESS_MODEL: address-model=64
B2_CXXFLAGS: cxxflags=-permissive-
B2_CXXSTD: latest # 2a
B2_TOOLSET: msvc-14.1
- FLAVOR: Visual Studio 2017 C++17
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
B2_ADDRESS_MODEL: address-model=64
B2_CXXSTD: 17
B2_TOOLSET: msvc-14.1
B2_VARIANT: variant=debug
- FLAVOR: Visual Studio 2017 C++14 (Default)
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
B2_ADDRESS_MODEL: address-model=64,32
B2_TOOLSET: msvc-14.1
- FLAVOR: clang-cl
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
B2_ADDRESS_MODEL: address-model=64
B2_CXXSTD: 11
B2_TOOLSET: clang-win
- FLAVOR: Visual Studio 2015 C++14 (Default)
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
B2_ADDRESS_MODEL: address-model=64,32
B2_TOOLSET: msvc-14.0
B2_VARIANT: variant=debug
- FLAVOR: Visual Studio 2010, 2012, 2013
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
B2_TOOLSET: msvc-10.0,msvc-11.0,msvc-12.0
- FLAVOR: cygwin (32-bit)
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
ADDPATH: C:\cygwin\bin;
B2_ADDRESS_MODEL: address-model=32
B2_CXXSTD: 03,11
# https://github.com/boostorg/test/issues/144
B2_DEFINES: define=_POSIX_C_SOURCE=200112L
B2_THREADING: threadapi=pthread
B2_TOOLSET: gcc
B2_VARIANT: variant=debug
- FLAVOR: cygwin (64-bit)
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
ADDPATH: C:\cygwin64\bin;
B2_ADDRESS_MODEL: address-model=64
B2_CXXSTD: 11,17
# https://github.com/boostorg/test/issues/144
B2_DEFINES: define=_POSIX_C_SOURCE=200112L define=__USE_ISOC99
B2_THREADING: threadapi=pthread
B2_TOOLSET: gcc
- FLAVOR: mingw32
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
ARCH: i686
B2_ADDRESS_MODEL: address-model=32
B2_CXXSTD: 03,11
SCRIPT: ci\appveyor\mingw.bat
B2_VARIANT: variant=debug
- FLAVOR: mingw64
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
ARCH: x86_64
B2_ADDRESS_MODEL: address-model=64
B2_CXXSTD: 11,17
B2_DEFINES: define=__USE_ISOC99
SCRIPT: ci\appveyor\mingw.bat
install:
- set SELF=%APPVEYOR_PROJECT_NAME:-=_%
- git clone https://github.com/boostorg/boost-ci.git C:\boost-ci
- xcopy /s /e /q /i C:\boost-ci\ci .\ci
- ci\appveyor\install.bat
build: off
test_script:
- set SELF=%APPVEYOR_PROJECT_NAME:-=_%
- PATH=%ADDPATH%%PATH%
# The definition of B2_TOOLCXX omits B2_CXXSTD= if it was not defined above
- IF NOT DEFINED B2_CXXSTD (SET B2_TOOLCXX=toolset=%B2_TOOLSET%) ELSE (SET B2_TOOLCXX=toolset=%B2_TOOLSET% cxxstd=%B2_CXXSTD%)
# Echo the complete build command to the build log
- IF NOT DEFINED SCRIPT (ECHO b2 libs/%SELF:\=/% %B2_TOOLCXX% %B2_CXXFLAGS% %B2_DEFINES% %B2_THREADING% %B2_ADDRESS_MODEL% %B2_LINK% %B2_THREADING% %B2_VARIANT% -j3)
# Now go build...
- IF DEFINED SCRIPT (call libs\%SELF%\%SCRIPT%) ELSE (b2 libs/%SELF:\=/% %B2_TOOLCXX% %B2_CXXFLAGS% %B2_DEFINES% %B2_THREADING% %B2_ADDRESS_MODEL% %B2_LINK% %B2_THREADING% %B2_VARIANT% -j3)

311
.azure-pipelines.yml Normal file
View File

@@ -0,0 +1,311 @@
# Copyright 2015-2019 Rene Rivera.
# Copyright 2019 Mateusz Loskot <mateusz at loskot dot net>
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt)
#
# Generic Azure Pipelines build script for boostorg repositories
# See: https://github.com/boostorg/boost-ci/
#
# Instructions for customizing this script for your library:
#
# 1. Customize the compilers and language levels you want.
# 2. If you have more than include/, src/, test/, example/, examples/,
# benchmark/ or tools/ directories, set the environment variable DEPINST.
# For example if your build uses code in "bench/" and "fog/" directories:
# - DEPINST: --include bench --include fog
# 3. Enable pull request builds in your boostorg/<library> account.
#
# That's it - the script will do everything else for you.
trigger:
branches:
include:
- develop
- master
- bugfix/*
- feature/*
- fix/*
- pr/*
pr:
branches:
include:
- develop
variables:
- name: B2_VARIANT
value: variant=release,debug
stages:
- stage: Test
jobs:
- job: 'Linux'
pool:
vmImage: 'ubuntu-16.04'
strategy:
matrix:
GCC 8:
B2_TOOLSET: gcc
B2_CXXSTD: 14,17,2a
CXX: g++-8
PACKAGES: g++-8
GCC 7:
B2_TOOLSET: gcc
B2_CXXSTD: 11,14,17
CXX: g++-7
PACKAGES: g++-7
GCC 6:
B2_TOOLSET: gcc
B2_CXXSTD: 11,14
CXX: g++-6
PACKAGES: g++-6
GCC 5:
B2_TOOLSET: gcc
B2_CXXSTD: 11
CXX: g++-5
PACKAGES: g++-5
GCC 4.9:
B2_TOOLSET: gcc
B2_CXXSTD: 03,11
CXX: g++-4.9
PACKAGES: g++-4.9
GCC 4.8:
B2_TOOLSET: gcc
B2_CXXSTD: 03,11
CXX: g++-4.8
PACKAGES: g++-4.8
Clang 8:
B2_TOOLSET: clang
B2_CXXSTD: 14,17,2a
CXX: clang++-8
PACKAGES: clang-8
LLVM_REPO: llvm-toolchain-xenial-8
Clang 7:
B2_TOOLSET: clang
B2_CXXSTD: 14,17,2a
CXX: clang++-7
PACKAGES: clang-7
LLVM_REPO: llvm-toolchain-xenial-7
Clang 6:
B2_TOOLSET: clang
B2_CXXSTD: 03,11,14,17,2a
B2_CXXFLAGS: -stdlib=libc++
CXX: clang++-6.0
PACKAGES: clang-6.0
LLVM_REPO: llvm-toolchain-xenial-6.0
Clang 6:
B2_TOOLSET: clang
B2_CXXSTD: 14,17,2a
CXX: clang++-6.0
PACKAGES: clang-6.0
LLVM_REPO: llvm-toolchain-xenial-6.0
Clang 5:
B2_TOOLSET: clang
B2_CXXSTD: 11,14,17
PACKAGES: clang-5.0
CXX: clang++-5.0
LLVM_REPO: llvm-toolchain-xenial-5.0
Clang 4:
B2_TOOLSET: clang
B2_CXXSTD: 11,14,17
CXX: clang++-4.0
PACKAGES: clang-4.0
LLVM_REPO: llvm-toolchain-xenial-4.0
Clang 3.9:
B2_TOOLSET: clang
B2_CXXSTD: 03,11,14
CXX: clang++-3.9
PACKAGES: clang-3.9
Clang 3.8:
B2_TOOLSET: clang
CXX: clang++-3.8
B2_CXXSTD: 03,11,14
PACKAGES: clang-3.8
Clang 3.7:
B2_TOOLSET: clang
B2_CXXSTD: 03,11
CXX: clang++-3.7
PACKAGES: clang-3.7
Clang 3.6:
B2_TOOLSET: clang
B2_CXXSTD: 03,11
CXX: clang++-3.6
PACKAGES: clang-3.6
Clang 3.5:
B2_TOOLSET: clang
B2_CXXSTD: 03,11
CXX: clang++-3.5
PACKAGES: clang-3.5
steps:
- bash: |
set -e
uname -a
sudo -E apt-add-repository -y "ppa:ubuntu-toolchain-r/test"
if test -n "${LLVM_REPO}" ; then
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
sudo -E apt-add-repository "deb http://apt.llvm.org/xenial/ ${LLVM_REPO} main"
fi
sudo -E apt-get update
sudo -E apt-get -yq --no-install-suggests --no-install-recommends install ${PACKAGES}
git clone --branch master https://github.com/boostorg/boost-ci.git boost-ci
cp -pr boost-ci/ci boost-ci/.codecov.yml .
rm -rf boost-ci
source ci/azure-pipelines/install.sh
# AzP requires to run special task in order to export
# SELF and BOOST_ROOT as job-scoped variable from a script.
# NOTE: Disable set -x is necessary, see the troubleshooting guide
# on "Variables having ' (single quote) appended":
# https://docs.microsoft.com/en-us/azure/devops/pipelines/troubleshooting
set +x
echo "##vso[task.setvariable variable=SELF]"$SELF
echo "##vso[task.setvariable variable=BOOST_ROOT]"$BOOST_ROOT
set -x
displayName: 'Install'
- bash: |
set -e
echo "SELF=$SELF"
echo "BOOST_ROOT=$BOOST_ROOT"
cd $BOOST_ROOT/libs/$SELF
ci/azure-pipelines/build.sh --debug-configuration
displayName: 'Build'
- job: 'Windows'
strategy:
matrix:
VS 2019 C++2a Strict:
B2_TOOLSET: msvc-14.2
B2_CXXSTD: latest # 2a
B2_CXXFLAGS: cxxflags=-permissive-
B2_ADDRESS_MODEL: address-model=64
VM_IMAGE: 'windows-2019'
VS 2017 C++2a Strict:
B2_TOOLSET: msvc-14.1
B2_CXXSTD: latest # 2a
B2_CXXFLAGS: cxxflags=-permissive-
B2_ADDRESS_MODEL: address-model=64
VM_IMAGE: 'vs2017-win2016'
VS 2017 C++17:
B2_TOOLSET: msvc-14.1
B2_CXXSTD: 17
B2_ADDRESS_MODEL: address-model=64,32
VM_IMAGE: 'vs2017-win2016'
VS 2017 C++14:
B2_TOOLSET: msvc-14.1
#B2_CXXSTD: 14 # default
B2_ADDRESS_MODEL: address-model=64,32
VM_IMAGE: 'vs2017-win2016'
VS 2015 C++14:
B2_TOOLSET: msvc-14.0
#B2_CXXSTD: 14 # default
B2_ADDRESS_MODEL: address-model=64,32
VM_IMAGE: 'vs2015-win2012r2'
pool:
vmImage: $(VM_IMAGE)
steps:
- script: |
set SELF=%BUILD_REPOSITORY_NAME:-=_%
for /f "tokens=2 delims=/" %%a in ("%SELF%") do set SELF=%%a
set BOOST_ROOT=%BUILD_SOURCESDIRECTORY%\boost-root
git clone --branch master https://github.com/boostorg/boost-ci.git boost-ci
xcopy /s /e /q /i boost-ci\ci .\ci
cmd /k ci\azure-pipelines\install.bat
echo ##vso[task.setvariable variable=SELF]%SELF%
echo ##vso[task.setvariable variable=BOOST_ROOT]%BOOST_ROOT%
displayName: 'Install'
- script: |
PATH=%ADDPATH%%PATH%
REM The definition of B2_TOOLCXX omits B2_CXXSTD= if it was not defined above
IF NOT DEFINED B2_CXXSTD (SET B2_TOOLCXX=toolset=%B2_TOOLSET%) ELSE (SET B2_TOOLCXX=toolset=%B2_TOOLSET% cxxstd=%B2_CXXSTD%)
cd %BOOST_ROOT%
ECHO b2 libs/%SELF:\=/% %B2_TOOLCXX% %B2_CXXFLAGS% %B2_DEFINES% %B2_THREADING% %B2_ADDRESS_MODEL% %B2_LINK% %B2_THREADING% %B2_VARIANT% -j3
b2 libs/%SELF:\=/% %B2_TOOLCXX% %B2_CXXFLAGS% %B2_DEFINES% %B2_THREADING% %B2_ADDRESS_MODEL% %B2_LINK% %B2_THREADING% %B2_VARIANT% -j3
displayName: 'Build'
- job: 'macOS'
pool:
vmImage: 'macOS-10.13'
strategy:
matrix:
Xcode 10.1:
B2_TOOLSET: clang
B2_CXXSTD: 14,17,2a
XCODE_APP: /Applications/Xcode_10.1.app
Xcode 10.0:
B2_TOOLSET: clang
B2_CXXSTD: 14,17,2a
XCODE_APP: /Applications/Xcode_10.app
Xcode 9.4.1:
B2_TOOLSET: clang
B2_CXXSTD: 11,14,17
XCODE_APP: /Applications/Xcode_9.4.1.app
Xcode 9.4:
B2_TOOLSET: clang
B2_CXXSTD: 11,14,17
XCODE_APP: /Applications/Xcode_9.4.app
Xcode 9.3.1:
B2_TOOLSET: clang
B2_CXXSTD: 11,14,17
XCODE_APP: /Applications/Xcode_9.3.1.app
Xcode 9.3:
B2_TOOLSET: clang
B2_CXXSTD: 11,14
XCODE_APP: /Applications/Xcode_9.3.app
Xcode 9.2:
B2_TOOLSET: clang
B2_CXXSTD: 11,14
XCODE_APP: /Applications/Xcode_9.2.app
Xcode 9.1:
B2_TOOLSET: clang
B2_CXXSTD: 03,11
XCODE_APP: /Applications/Xcode_9.1.app
Xcode 9.0.1:
B2_TOOLSET: clang
B2_CXXSTD: 03,11
XCODE_APP: /Applications/Xcode_9.0.1.app
Xcode 9.0:
B2_TOOLSET: clang
B2_CXXSTD: 03,11
XCODE_APP: /Applications/Xcode_9.app
Xcode 8.3.3:
B2_TOOLSET: clang
B2_CXXSTD: 03,11
XCODE_APP: /Applications/Xcode_8.3.3.app
steps:
- bash: |
set -e
uname -a
sudo xcode-select -switch ${XCODE_APP}
which clang++
git clone --branch master https://github.com/boostorg/boost-ci.git boost-ci
cp -pr boost-ci/ci boost-ci/.codecov.yml .
rm -rf boost-ci
source ci/azure-pipelines/install.sh
# AzP requires to run special task in order to export
# SELF and BOOST_ROOT as job-scoped variable from a script.
# NOTE: Disable set -x is necessary, see the troubleshooting guide
# on "Variables having ' (single quote) appended":
# https://docs.microsoft.com/en-us/azure/devops/pipelines/troubleshooting
set +x
echo "##vso[task.setvariable variable=SELF]"$SELF
echo "##vso[task.setvariable variable=BOOST_ROOT]"$BOOST_ROOT
set -x
displayName: Install
- bash: |
set -e
echo "SELF=$SELF"
echo "BOOST_ROOT=$BOOST_ROOT"
cd $BOOST_ROOT/libs/$SELF
ci/azure-pipelines/build.sh --debug-configuration
displayName: 'Build'

5
.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
bin/
build/
*.*#
static/log.txt
tags

236
.travis.yml Normal file
View File

@@ -0,0 +1,236 @@
# Copyright 2016 Peter Dimov
# Copyright 2017 - 2019 James E. King III
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt)
#
# Generic Travis CI build script for boostorg repositories
# See: https://github.com/boostorg/boost-ci
#
# Instructions for customizing this script for your library:
#
# 1. Customize the compilers and language levels you want in the 'jobs'.
# 2. If you have more than include/, src/, test/, example/, examples/, or
# tools/ directories, modify your Travis CI project and add the environment
# variable DEPINST. For example if your build uses code in "bench/" and
# "fog/" directories, then set DEPINST to the following:
# --include bench --include fog
# 3. If you want to enable Coverity Scan, you need to provide the environment
# variables COVERITY_SCAN_TOKEN and COVERITY_SCAN_NOTIFICATION_EMAIL in
# your github settings.
# 4. If you want to enable a big-endian build, you need to uncomment the
# big-endian build job.
# 5. Enable pull request builds in your boostorg/<library> account.
#
# That's it - the scripts will do everything else for you.
dist: xenial
language: cpp
env:
global:
# see: http://www.boost.org/build/doc/html/bbv2/overview/invocation.html#bbv2.overview.invocation.properties
# - B2_ADDRESS_MODEL=address-model=64,32
# - B2_LINK=link=shared,static
# - B2_THREADING=threading=multi,single
- B2_VARIANT=variant=release
install:
- git clone https://github.com/boostorg/boost-ci.git boost-ci
- cp -pr boost-ci/ci boost-ci/.codecov.yml .
- source ci/travis/install.sh
addons:
apt:
packages:
- binutils-gold
- gdb
- libc6-dbg
- qemu-user-static
services:
- docker
branches:
only:
- master
- develop
- /bugfix\/.*/
- /feature\/.*/
- /fix\/.*/
- /pr\/.*/
script:
- cd $BOOST_ROOT/libs/$SELF
- ci/travis/build.sh
#
# Default toolsets in Ubuntu
#
# trusty xenial bionic
# 14.04 16.04 18.04
# ------ ------ ------
# clang 3.4 3.8 6.0
# gcc 4.8.2 5.3.1 7.3.0
#
anchors:
clang-38: &clang-38 { apt: { packages: [ "clang-3.8",
"libstdc++-6-dev" ], sources: [ "llvm-toolchain-xenial-3.8",
"ubuntu-toolchain-r-test" ] } }
clang-4: &clang-4 { apt: { packages: [ "clang-4.0",
"libstdc++-6-dev" ], sources: [ "llvm-toolchain-xenial-4.0",
"ubuntu-toolchain-r-test" ] } }
clang-5: &clang-5 { apt: { packages: [ "clang-5.0",
"libstdc++-7-dev" ], sources: [ "llvm-toolchain-xenial-5.0",
"ubuntu-toolchain-r-test" ] } }
clang-6: &clang-6 { apt: { packages: [ "clang-6.0",
"libc6-dbg",
"libc++-dev",
"libstdc++-8-dev" ], sources: [ "llvm-toolchain-xenial-6.0",
"ubuntu-toolchain-r-test" ] } }
clang-7: &clang-7 { apt: { packages: [ "clang-7",
"libc6-dbg",
"libc++-dev",
"libstdc++-8-dev" ], sources: [ "llvm-toolchain-xenial-7",
"ubuntu-toolchain-r-test" ] } }
clang-8: &clang-8 { apt: { packages: [ "clang-8",
"libc6-dbg",
"libc++-dev",
"libstdc++-8-dev" ], sources: [ "llvm-toolchain-xenial-8",
"ubuntu-toolchain-r-test" ] } }
gcc-48: &gcc-48 { apt: { packages: [ "g++-4.8" ] } }
gcc-49: &gcc-49 { apt: { packages: [ "g++-4.9" ], sources: [ "ubuntu-toolchain-r-test" ] } }
gcc-5: &gcc-5 { apt: { packages: [ "g++-5" ] } }
gcc-6: &gcc-6 { apt: { packages: [ "g++-6" ], sources: [ "ubuntu-toolchain-r-test" ] } }
gcc-7: &gcc-7 { apt: { packages: [ "g++-7" ], sources: [ "ubuntu-toolchain-r-test" ] } }
gcc-8: &gcc-8 { apt: { packages: [ "g++-8" ], sources: [ "ubuntu-toolchain-r-test" ] } }
gcc-9: &gcc-9 { apt: { packages: [ "g++-9" ], sources: [ "ubuntu-toolchain-r-test" ] } }
jobs:
allow_failures:
- env:
- COPY="all the environment settings from your job"
include:
# coverage
- os: linux
env:
- COMMENT=codecov.io
- B2_CXXSTD=11
- B2_TOOLSET=gcc-8
- B2_DEFINES="define=BOOST_NO_STRESS_TEST=1"
addons: *gcc-8
script:
- cd $BOOST_ROOT/libs/$SELF
- ci/travis/codecov.sh
- os: linux
env:
- COMMENT=asan
- B2_VARIANT=variant=debug
- B2_TOOLSET=gcc-8
- B2_CXXSTD=11,14
- B2_CXXFLAGS="address-sanitizer=norecover"
- B2_DEFINES="define=BOOST_NO_STRESS_TEST=1"
addons: *gcc-8
- os: linux
env:
- COMMENT=tsan
- B2_VARIANT=variant=debug
- B2_TOOLSET=gcc-8
- B2_CXXSTD=11,14
- B2_CXXFLAGS="thread-sanitizer=norecover"
- B2_DEFINES="define=BOOST_NO_STRESS_TEST=1"
addons: *gcc-8
- os: linux
env:
- COMMENT=ubsan
- B2_VARIANT=variant=debug
- B2_TOOLSET=gcc-8
- B2_CXXSTD=11,14
- B2_CXXFLAGS="undefined-sanitizer=norecover"
- B2_DEFINES="define=BOOST_NO_STRESS_TEST=1"
- B2_LINKFLAGS="linkflags=-fuse-ld=gold"
- UBSAN_OPTIONS=print_stacktrace=1
addons: *gcc-8
- os: linux
env:
- COMMENT=valgrind
- B2_TOOLSET=clang-6.0
- B2_CXXSTD=11,14
- B2_DEFINES="define=BOOST_NO_STRESS_TEST=1"
- B2_VARIANT=variant=debug
- B2_TESTFLAGS=testing.launcher=valgrind
- VALGRIND_OPTS=--error-exitcode=1
addons: *clang-6
script:
- cd $BOOST_ROOT/libs/$SELF
- ci/travis/valgrind.sh
# libstdc++
- { os: "linux", dist: "trusty", # xenial has libstdc++ from gcc 5.4.0 with newer ABI
env: [ "B2_TOOLSET=gcc-4.8", "B2_CXXSTD=11" ], addons: *gcc-48 }
- { os: "linux", dist: "trusty", # xenial has libstdc++ from gcc 5.4.0 with newer ABI
env: [ "B2_TOOLSET=gcc-4.9", "B2_CXXSTD=11" ], addons: *gcc-49 }
- { os: "linux", env: [ "B2_TOOLSET=gcc-5", "B2_CXXSTD=11" ], addons: *gcc-5 }
- { os: "linux", env: [ "B2_TOOLSET=gcc-6", "B2_CXXSTD=11,14" ], addons: *gcc-6 }
- { os: "linux", env: [ "B2_TOOLSET=gcc-7", "B2_CXXSTD=14,17" ], addons: *gcc-7 }
- { os: "linux", env: [ "B2_TOOLSET=gcc-8", "B2_CXXSTD=17,2a" ], addons: *gcc-8 }
- { os: "linux", env: [ "B2_TOOLSET=gcc-9", "B2_CXXSTD=17,2a" ], addons: *gcc-9 }
- { os: "linux", dist: "trusty", # xenial has libstdc++ from gcc 5.4.0 with newer ABI
env: [ "B2_TOOLSET=clang-3.8", "B2_CXXSTD=11" ], addons: *clang-38 }
- { os: "linux", env: [ "B2_TOOLSET=clang-4.0", "B2_CXXSTD=11,14" ], addons: *clang-4 }
- { os: "linux", env: [ "B2_TOOLSET=clang-5.0", "B2_CXXSTD=11,14" ], addons: *clang-5 }
- { os: "linux", env: [ "B2_TOOLSET=clang-6.0", "B2_CXXSTD=14,17" ], addons: *clang-6 }
- { os: "linux", env: [ "B2_TOOLSET=clang-7", "B2_CXXSTD=17,2a" ], addons: *clang-7 }
- { os: "linux", env: [ "B2_TOOLSET=clang-8", "B2_CXXSTD=17,2a" ], addons: *clang-8 }
# libc++
- { os: "linux", env: [ "B2_TOOLSET=clang-6.0", "B2_CXXSTD=11,14",
"B2_CXXFLAGS=-stdlib=libc++" ], addons: *clang-6 }
- { os: "osx" , env: [ "B2_TOOLSET=clang", "B2_CXXSTD=11,17" ] }
# to enable Intel ICC define INTEL_ICC_SERIAL_NUMBER and the following (under development):
# - { os: "linux", env: [ "B2_TOOLSET=intel-linux", "B2_CXXSTD=11,14,17" ], addons: *gcc-7,
# script: cd $BOOST_ROOT/libs/$SELF && ci/travis/intelicc.sh }
# uncomment to enable a big-endian build job, just note that it is 5-10 times slower
# than a regular build and travis has a 50 minute time limit per job
# - os: linux
# env:
# - COMMENT=big-endian
# - B2_CXXSTD=03
# - B2_TOOLSET=gcc
# - B2_DEFINES="define=BOOST_NO_STRESS_TEST=1"
# - BDDE_OS=red
# - BDDE_ARCH=ppc64
# script:
# - cd $BOOST_ROOT/libs/$SELF
# - ci/travis/bdde.sh
# - os: linux
# env:
# - COMMENT=cppcheck
# script:
# - cd $BOOST_ROOT/libs/$SELF
# - ci/travis/cppcheck.sh
#################### Jobs to run on pushes to master, develop ###################
# Coverity Scan
- os: linux
if: (env(COVERITY_SCAN_NOTIFICATION_EMAIL) IS present) AND (branch IN (develop, master)) AND (type IN (cron, push))
env:
- COMMENT="Coverity Scan"
- B2_TOOLSET=clang
script:
- cd $BOOST_ROOT/libs/$SELF
- ci/travis/coverity.sh
notifications:
email:
false

147
CMakeLists.txt Normal file
View File

@@ -0,0 +1,147 @@
#
# Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
#
# Distributed under the Boost Software License, Version 1.0. (See accompanying
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#
# Official repository: https://github.com/boostorg/fixed_string
#
cmake_minimum_required (VERSION 3.5.1)
if (POLICY CMP0074)
cmake_policy (SET CMP0074 NEW)
endif()
#-------------------------------------------------------------------------------
function (DoGroupSources curdir rootdir folder)
file (GLOB children RELATIVE ${PROJECT_SOURCE_DIR}/${curdir} ${PROJECT_SOURCE_DIR}/${curdir}/*)
foreach (child ${children})
if (IS_DIRECTORY ${PROJECT_SOURCE_DIR}/${curdir}/${child})
DoGroupSources (${curdir}/${child} ${rootdir} ${folder})
elseif (${child} STREQUAL "CMakeLists.txt")
source_group("" FILES ${PROJECT_SOURCE_DIR}/${curdir}/${child})
else()
string (REGEX REPLACE ^${rootdir} ${folder} groupname ${curdir})
string (REPLACE "/" "\\" groupname ${groupname})
source_group (${groupname} FILES ${PROJECT_SOURCE_DIR}/${curdir}/${child})
endif()
endforeach()
endfunction()
function (GroupSources curdir folder)
DoGroupSources (${curdir} ${curdir} ${folder})
endfunction()
#-------------------------------------------------------------------------------
#
# JSON
#
#-------------------------------------------------------------------------------
project (JSON VERSION 1)
set_property (GLOBAL PROPERTY USE_FOLDERS ON)
if (MSVC)
set (CMAKE_VERBOSE_MAKEFILE FALSE)
add_definitions (
-D_WIN32_WINNT=0x0601
)
add_compile_options(
/permissive- # strict C++
/W4 # enable all warnings
/MP # Multi-processor compilation
)
set (Boost_USE_STATIC_LIBS ON)
set (Boost_USE_STATIC_RUNTIME ON)
set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd")
set (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Ob2 /Oi /Ot /GL /MT")
set (CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /Oi /Ot /MT")
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SAFESEH:NO")
set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG")
# for RelWithDebInfo builds, disable incremental linking
# since CMake sets it ON by default for that build type and it
# causes warnings
#
string (REPLACE "/INCREMENTAL" "/INCREMENTAL:NO" replacement_flags
${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO})
set (CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO ${replacement_flags})
else()
set (THREADS_PREFER_PTHREAD_FLAG ON)
find_package (Threads)
set( CMAKE_CXX_FLAGS
"${CMAKE_CXX_FLAGS} -std=c++11 -Wall -Wextra -Wpedantic -Wno-unused-parameter")
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wrange-loop-analysis")
endif ()
endif()
# Must come before Boost includes, otherwise the
# IDE sees the wrong file due to boost/ symlinks.
include_directories (include)
#-------------------------------------------------------------------------------
#
# Boost
#
#-------------------------------------------------------------------------------
get_filename_component (BOOST_ROOT ../../ ABSOLUTE)
# VFALCO I want static but "b2 stage" builds a minimal set which excludes static
add_definitions (-DBOOST_ALL_STATIC_LINK=1)
include_directories (${BOOST_ROOT})
link_directories(${BOOST_ROOT}/stage/lib)
#-------------------------------------------------------------------------------
if ("${VARIANT}" STREQUAL "coverage")
if (MSVC)
else()
set (CMAKE_BUILD_TYPE DEBUG)
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -msse4.2 --coverage")
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --coverage")
endif()
elseif ("${VARIANT}" STREQUAL "ubasan")
if (MSVC)
else()
set (CMAKE_BUILD_TYPE RELWITHDEBINFO)
set (CMAKE_CXX_FLAGS
"${CMAKE_CXX_FLAGS} -msse4.2 -funsigned-char -fno-omit-frame-pointer -fsanitize=address,undefined -fno-sanitize-recover=address,undefined -fsanitize-blacklist=${PROJECT_SOURCE_DIR}/tools/blacklist.supp")
set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address,undefined -fno-sanitize-recover=address,undefined")
endif()
elseif ("${VARIANT}" STREQUAL "debug")
set (CMAKE_BUILD_TYPE DEBUG)
elseif ("${VARIANT}" STREQUAL "release")
set (CMAKE_BUILD_TYPE RELEASE)
endif()
#-------------------------------------------------------------------------------
#
# Tests and examples
#
file (GLOB_RECURSE PROJECT_FILES
${PROJECT_SOURCE_DIR}/include/boost/json.hpp
${PROJECT_SOURCE_DIR}/include/boost/json/*.hpp
${PROJECT_SOURCE_DIR}/include/boost/json/*.ipp
)
add_subdirectory (test)

45
Jamfile Normal file
View File

@@ -0,0 +1,45 @@
#
# Copyright (c) 2019 Vinnie Falco (vinnie dot falco at gmail dot com)
#
# Distributed under the Boost Software License, Version 1.0. (See accompanying
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#
# Official repository: https://github.com/boostorg/json
#
import ac ;
import os ;
import feature ;
import boost ;
import modules ;
import testing ;
import ../../config/checks/config : requires ;
boost.use-project ;
local defines =
[ requires
cxx11_constexpr
cxx11_decltype
cxx11_hdr_tuple
cxx11_template_aliases
cxx11_variadic_templates
]
<include>.
<implicit-dependency>/boost//headers
<define>BOOST_ALL_NO_LIB=1
<toolset>msvc-14.1:<cxxflags>"/permissive-"
<toolset>msvc-14.2:<cxxflags>"/permissive-"
<toolset>msvc,<variant>release:<cxxflags>"/Ob2 /Oi /Ot"
<target-os>windows:<define>_WIN32_WINNT=0x0601
;
project /boost/json
: requirements
<link>static
$(defines)
: usage-requirements
$(defines)
;
build-project test ;

23
LICENSE_1_0.txt Normal file
View File

@@ -0,0 +1,23 @@
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

@@ -1,2 +1,3 @@
# json
Boost.JSON
# Boost.JSON
This is currently **NOT** an official Boost library.

30
include/boost/json.hpp Normal file
View File

@@ -0,0 +1,30 @@
//
// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/json
//
#ifndef BOOST_JSON_HPP
#define BOOST_JSON_HPP
#include <boost/json/allocator.hpp>
#include <boost/json/array.hpp>
#include <boost/json/assign_string.hpp>
#include <boost/json/assign_vector.hpp>
#include <boost/json/basic_parser.hpp>
#include <boost/json/iterator.hpp>
#include <boost/json/error.hpp>
#include <boost/json/kind.hpp>
#include <boost/json/number.hpp>
#include <boost/json/object.hpp>
#include <boost/json/parse_file.hpp>
#include <boost/json/parser.hpp>
#include <boost/json/serializer.hpp>
#include <boost/json/storage.hpp>
#include <boost/json/string.hpp>
#include <boost/json/value.hpp>
#endif

View File

@@ -0,0 +1,90 @@
//
// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/json
//
#ifndef BOOST_JSON_ALLOCATOR_HPP
#define BOOST_JSON_ALLOCATOR_HPP
#include <boost/beast/core/detail/config.hpp>
#include <boost/json/storage.hpp>
#include <type_traits>
namespace boost {
namespace beast {
namespace json {
template<typename T>
class allocator
{
storage_ptr sp_;
template<typename U>
friend class allocator;
public:
using pointer = T*;
using reference = T&;
using const_pointer = T const*;
using const_reference = T const&;
using value_type = T;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
template<typename U>
struct rebind
{
using other = allocator<U>;
};
allocator(allocator const&) = default;
allocator& operator=(allocator const&) = default;
allocator();
allocator(allocator&&) noexcept;
allocator& operator=(allocator&&) noexcept;
template<typename U>
allocator(allocator<U> const& other) noexcept;
explicit
allocator(storage_ptr sp) noexcept;
T*
allocate(size_t n);
void
deallocate(T* t, size_t n) noexcept;
bool
operator==(allocator const&) const noexcept;
bool
operator!=(allocator const&) const noexcept;
storage_ptr
get_storage() const & noexcept
{
return sp_;
}
storage_ptr
get_storage() && noexcept
{
return std::move(sp_);
}
};
} // json
} // beast
} // boost
#include <boost/json/impl/allocator.hpp>
#endif

View File

@@ -0,0 +1,440 @@
//
// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/json
//
#ifndef BOOST_JSON_ARRAY_HPP
#define BOOST_JSON_ARRAY_HPP
#include <boost/beast/core/detail/config.hpp>
#include <boost/json/allocator.hpp>
#include <boost/json/storage.hpp>
#include <cstdlib>
#include <initializer_list>
#include <iterator>
namespace boost {
namespace beast {
namespace json {
class value;
/** The native type of array values
*/
class array
{
class table;
table* tab_ = nullptr;
storage_ptr sp_;
struct cleanup_assign;
struct cleanup_insert;
public:
using value_type = value;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
using reference = value&;
using const_reference = value const&;
using pointer = value*;
using const_pointer = value const*;
using iterator = value*;
using const_iterator = value const*;
using reverse_iterator =
std::reverse_iterator<iterator>;
using const_reverse_iterator =
std::reverse_iterator<const_iterator>;
//--------------------------------------------------------------------------
//
// Special Members
//
//--------------------------------------------------------------------------
BOOST_BEAST_DECL
~array();
BOOST_BEAST_DECL
array();
BOOST_BEAST_DECL
explicit
array(storage_ptr store);
BOOST_BEAST_DECL
array(
size_type count);
BOOST_BEAST_DECL
array(
size_type count,
storage_ptr store);
BOOST_BEAST_DECL
array(
size_type count,
value_type const& v);
BOOST_BEAST_DECL
array(
size_type count,
value_type const& v,
storage_ptr store);
template<class InputIt>
array(
InputIt first, InputIt last);
template<class InputIt>
array(
InputIt first, InputIt last,
storage_ptr store);
BOOST_BEAST_DECL
array(array const& other);
BOOST_BEAST_DECL
array(
array const& other,
storage_ptr store);
BOOST_BEAST_DECL
array(array&& other) noexcept;
BOOST_BEAST_DECL
array(
array&& other,
storage_ptr store);
BOOST_BEAST_DECL
array(
std::initializer_list<value_type> list);
BOOST_BEAST_DECL
array(
std::initializer_list<value_type> list,
storage_ptr store);
BOOST_BEAST_DECL
array&
operator=(array&& other);
BOOST_BEAST_DECL
array&
operator=(array const& other);
BOOST_BEAST_DECL
array&
operator=(
std::initializer_list<value_type> list);
BOOST_BEAST_DECL
storage_ptr const&
get_storage() const noexcept
{
return sp_;
}
//--------------------------------------------------------------------------
//
// Elements
//
//--------------------------------------------------------------------------
BOOST_BEAST_DECL
reference
at(size_type pos);
BOOST_BEAST_DECL
const_reference
at(size_type pos) const;
BOOST_BEAST_DECL
reference
operator[](size_type pos);
BOOST_BEAST_DECL
const_reference
operator[](size_type pos) const;
reference
front()
{
return (*this)[0];
}
const_reference
front() const
{
return (*this)[0];
}
reference
back()
{
return (*this)[size() - 1];
}
const_reference
back() const
{
return (*this)[size() - 1];
}
BOOST_BEAST_DECL
value_type*
data() noexcept;
BOOST_BEAST_DECL
value_type const*
data() const noexcept;
//--------------------------------------------------------------------------
//
// Iterators
//
//--------------------------------------------------------------------------
BOOST_BEAST_DECL
iterator
begin() noexcept;
BOOST_BEAST_DECL
const_iterator
begin() const noexcept;
BOOST_BEAST_DECL
const_iterator
cbegin() noexcept
{
return begin();
}
BOOST_BEAST_DECL
iterator
end() noexcept;
BOOST_BEAST_DECL
const_iterator
end() const noexcept;
BOOST_BEAST_DECL
const_iterator
cend() noexcept
{
return end();
}
BOOST_BEAST_DECL
reverse_iterator
rbegin() noexcept;
BOOST_BEAST_DECL
const_reverse_iterator
rbegin() const noexcept;
BOOST_BEAST_DECL
const_reverse_iterator
crbegin() noexcept
{
return rbegin();
}
BOOST_BEAST_DECL
reverse_iterator
rend() noexcept;
BOOST_BEAST_DECL
const_reverse_iterator
rend() const noexcept;
BOOST_BEAST_DECL
const_reverse_iterator
crend() noexcept
{
return rend();
}
//--------------------------------------------------------------------------
//
// Capacity
//
//--------------------------------------------------------------------------
BOOST_BEAST_DECL
bool
empty() const noexcept;
BOOST_BEAST_DECL
size_type
size() const noexcept;
BOOST_BEAST_DECL
size_type
max_size() const noexcept;
BOOST_BEAST_DECL
void
reserve(size_type new_capacity);
BOOST_BEAST_DECL
size_type
capacity() const noexcept;
BOOST_BEAST_DECL
void
shrink_to_fit() noexcept;
//--------------------------------------------------------------------------
//
// Modifiers
//
//--------------------------------------------------------------------------
BOOST_BEAST_DECL
void
clear() noexcept;
BOOST_BEAST_DECL
iterator
insert(
const_iterator before,
value_type const& v);
BOOST_BEAST_DECL
iterator
insert(
const_iterator before,
value_type&& v);
BOOST_BEAST_DECL
iterator
insert (
const_iterator before,
size_type count,
value_type const& v);
template<class InputIt>
iterator
insert(
const_iterator before,
InputIt first, InputIt last);
BOOST_BEAST_DECL
iterator
insert(
const_iterator before,
std::initializer_list<value_type> list);
template<class Arg>
iterator
emplace(
const_iterator before,
Arg&& arg);
BOOST_BEAST_DECL
iterator
erase(const_iterator pos);
BOOST_BEAST_DECL
iterator
erase(
const_iterator first,
const_iterator last);
BOOST_BEAST_DECL
void
push_back(value_type const& v);
BOOST_BEAST_DECL
void
push_back(value_type&& v);
template<class Arg>
reference
emplace_back(Arg&& arg);
BOOST_BEAST_DECL
void
pop_back();
BOOST_BEAST_DECL
void
resize(size_type count);
BOOST_BEAST_DECL
void
resize(
size_type count,
value_type const& v);
BOOST_BEAST_DECL
void
swap(array& other) noexcept;
private:
template<class It>
using iter_cat = typename
std::iterator_traits<It>::iterator_category;
template<class InputIt>
array(
InputIt first, InputIt last,
storage_ptr store,
std::input_iterator_tag);
template<class InputIt>
array(
InputIt first, InputIt last,
storage_ptr store,
std::forward_iterator_tag);
template<class InputIt>
iterator
insert(
const_iterator before,
InputIt first, InputIt last,
std::input_iterator_tag);
template<class InputIt>
iterator
insert(
const_iterator before,
InputIt first, InputIt last,
std::forward_iterator_tag);
template<class Arg>
iterator
emplace_impl(
const_iterator before,
Arg&& arg);
BOOST_BEAST_DECL
void
destroy(
value* first,
value* last);
BOOST_BEAST_DECL
void
move(
value* to,
value* from,
size_type n) noexcept;
};
} // json
} // beast
} // boost
// Must be included here for this file to stand alone
#include <boost/json/value.hpp>
// headers for this file are at the bottom of value.hpp
#endif

View File

@@ -0,0 +1,43 @@
//
// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/json
//
#ifndef BOOST_JSON_ASSIGN_STRING_HPP
#define BOOST_JSON_ASSIGN_STRING_HPP
#include <boost/beast/core/detail/config.hpp>
#include <boost/json/error.hpp>
#include <boost/json/value.hpp>
#include <string>
#include <type_traits>
namespace boost {
namespace beast {
namespace json {
template<class Allocator>
void
from_json(
std::basic_string<
char,
std::char_traits<char>,
Allocator>& t,
value const& v)
{
if(! v.is_string())
throw system_error(
error::expected_string);
auto& s= v.as_string();
t.assign(s.data(), s.size());
}
} // json
} // beast
} // boost
#endif

View File

@@ -0,0 +1,49 @@
//
// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/json
//
#ifndef BOOST_JSON_ASSIGN_VECTOR_HPP
#define BOOST_JSON_ASSIGN_VECTOR_HPP
#include <boost/beast/core/detail/config.hpp>
#include <boost/json/error.hpp>
#include <boost/json/value.hpp>
#include <type_traits>
#include <vector>
namespace boost {
namespace beast {
namespace json {
template<class T, class A
#if 0
,class = typename std::enable_if<
can_assign_from<T>::value>::type
#endif
>
void
from_json(
std::vector<T, A>& t,
value const& v)
{
if(! v.is_array())
throw system_error(
error::expected_array);
auto& arr = v.as_array();
t.resize(0);
t.resize(arr.size());
auto it = t.begin();
for(auto const& e : arr)
e.store(*it++);
}
} // json
} // beast
} // boost
#endif

View File

@@ -0,0 +1,190 @@
//
// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/json
//
#ifndef BOOST_JSON_BASIC_PARSER_HPP
#define BOOST_JSON_BASIC_PARSER_HPP
#include <boost/beast/core/detail/config.hpp>
#include <boost/json/number.hpp>
#include <boost/json/detail/basic_parser.hpp>
#include <boost/json/detail/stack.hpp>
#include <boost/beast/core/error.hpp>
#include <boost/beast/core/string.hpp>
#include <boost/asio/buffer.hpp>
#include <cstdint>
#include <string>
#include <vector>
namespace boost {
namespace beast {
namespace json {
/** A parser for serialized JSON
*/
class basic_parser
#ifndef BOOST_BEAST_DOXYGEN
: private detail::parser_base
#endif
{
enum class state : char;
/// Depth to which the stack does not require dynamic allocation
static std::size_t const stack_capacity = 64;
detail::stack<
state, stack_capacity> stack_;
number::mantissa_type n_mant_;
number::exponent_type n_exp_;
bool n_neg_;
bool n_exp_neg_;
bool is_key_;
BOOST_BEAST_DECL
static
bool
append_digit(
number::mantissa_type* value,
char digit);
BOOST_BEAST_DECL
static
bool
append_digit(
number::exponent_type* value,
char digit, bool neg);
public:
/// Returns `true` if the parser has completed without error
BOOST_BEAST_DECL
bool
is_done() const noexcept;
/** Reset the state, to parse a new document.
*/
BOOST_BEAST_DECL
void
reset();
template<
class ConstBufferSequence
#ifndef BOOST_BEAST_DOXYGEN
,class = typename std::enable_if<
! std::is_convertible<
ConstBufferSequence,
net::const_buffer>::value>::type
#endif
>
std::size_t
write_some(
ConstBufferSequence const& buffers,
error_code& ec);
BOOST_BEAST_DECL
std::size_t
write_some(
net::const_buffer buffer,
error_code& ec);
template<
class ConstBufferSequence
#ifndef BOOST_BEAST_DOXYGEN
,class = typename std::enable_if<
! std::is_convertible<
ConstBufferSequence,
net::const_buffer>::value>::type
#endif
>
std::size_t
write(
ConstBufferSequence const& buffers,
error_code& ec);
BOOST_BEAST_DECL
std::size_t
write(
net::const_buffer buffer,
error_code& ec);
BOOST_BEAST_DECL
void
write_eof(error_code& ec);
protected:
/// Constructor (default)
BOOST_BEAST_DECL
basic_parser();
virtual
void
on_document_begin(error_code& ec) = 0;
virtual
void
on_object_begin(error_code& ec) = 0;
virtual
void
on_object_end(error_code& ec) = 0;
virtual
void
on_array_begin(error_code& ec) = 0;
virtual
void
on_array_end(error_code& ec) = 0;
virtual
void
on_key_data(
string_view s,
error_code& ec) = 0;
virtual
void
on_key_end(
string_view s,
error_code& ec) = 0;
virtual
void
on_string_data(
string_view s,
error_code& ec) = 0;
virtual
void
on_string_end(
string_view,
error_code& ec) = 0;
virtual
void
on_number(number n, error_code& ec) = 0;
virtual
void
on_bool(bool b, error_code& ec) = 0;
virtual
void
on_null(error_code& ec) = 0;
};
} // json
} // beast
} // boost
#include <boost/json/impl/basic_parser.hpp>
#if BOOST_BEAST_HEADER_ONLY
#include <boost/json/impl/basic_parser.ipp>
#endif
#endif

View File

@@ -0,0 +1,49 @@
//
// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/json
//
#ifndef BOOST_JSON_DETAIL_BASIC_PARSER_HPP
#define BOOST_JSON_DETAIL_BASIC_PARSER_HPP
namespace boost {
namespace beast {
namespace json {
namespace detail {
struct parser_base
{
static
bool
is_ws(char c) noexcept
{
return
c == ' ' || c == '\t' ||
c == '\r' || c == '\n';
}
static
bool
is_digit(char c) noexcept
{
return static_cast<unsigned char>(c - '0') < 10;
}
static
bool
is_control(char c)
{
return static_cast<unsigned char>(c) < 32;
}
};
} // detail
} // json
} // beast
} // boost
#endif

View File

@@ -0,0 +1,39 @@
//
// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/json
//
#ifndef BOOST_JSON_DETAIL_IS_SPECIALIZED_HPP
#define BOOST_JSON_DETAIL_IS_SPECIALIZED_HPP
#include <type_traits>
namespace boost {
namespace beast {
namespace json {
namespace detail {
struct primary_template
{
};
template<class T>
using is_specialized =
std::integral_constant<bool,
! std::is_base_of<primary_template, T>::value>;
template<class T>
using remove_cr =
typename std::remove_const<
typename std::remove_reference<T>::type>::type;
} // detail
} // json
} // beast
} // boost
#endif

View File

@@ -0,0 +1,190 @@
//
// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/json
//
#ifndef BOOST_JSON_DETAIL_STACK_HPP
#define BOOST_JSON_DETAIL_STACK_HPP
#include <boost/assert.hpp>
#include <new>
#include <type_traits>
#include <utility>
#include <vector>
namespace boost {
namespace beast {
namespace json {
namespace detail {
template<class T, std::size_t N>
class stack
{
std::vector<T> v_;
std::size_t n_ = 0; // includes v_.size()
typename std::aligned_storage<
N * sizeof(T), alignof(T)>::type buf_;
T*
base() noexcept
{
return reinterpret_cast<
T*>(&buf_);
}
T const*
base() const noexcept
{
return reinterpret_cast<
T const*>(&buf_);
}
void
destroy()
{
for(auto p = base(),
last = base() +
(n_ < N ? n_ : N);
p != last; ++p)
{
(*p).~T();
}
}
public:
using value_type = T;
stack() = default;
~stack()
{
destroy();
}
// element access
T&
operator[](std::size_t i) noexcept
{
BOOST_ASSERT(i < n_);
if(v_.empty())
return base()[n_ - (i + 1)];
if(i < v_.size())
return v_[v_.size() - (i + 1)];
return base()[
N - (v_.size() + i + 1)];
}
T const&
operator[](std::size_t i) const noexcept
{
BOOST_ASSERT(i < n_);
if(v_.empty())
return base()[n_ - (i + 1)];
if(i < v_.size())
return v_[v_.size() - (i + 1)];
return base()[
N - (v_.size() + i + 1)];
}
T&
front() noexcept
{
return (*this)[0];
}
T const&
front() const noexcept
{
return (*this)[0];
}
// capacity
bool
empty() const noexcept
{
return n_ == 0;
}
std::size_t
size() const noexcept
{
return n_;
}
std::size_t
max_size() const noexcept
{
return v_.max_size();
}
void
reserve(std::size_t n)
{
if(n <= N)
return;
v_.reserve(n - N);
}
std::size_t
capacity() const noexcept
{
return N + v_.capacity();
}
// modifiers
void
clear() noexcept
{
v_.clear();
destroy();
n_ = 0;
}
void
push_front(T const& t)
{
if(n_ < N)
::new(&base()[n_]) T(t);
else
v_.push_back(t);
++n_;
}
template<class... Args>
void
emplace_front(Args&&... args)
{
if(n_ < N)
::new(&base()[n_]) T(
std::forward<Args>(args)...);
else
v_.emplace_back(
std::forward<Args>(args)...);
++n_;
}
void
pop_front()
{
BOOST_ASSERT(n_ > 0);
if(! v_.empty())
v_.pop_back();
else
base()[n_ - 1].~T();
--n_;
}
};
} // detail
} // json
} // beast
} // boost
#endif

View File

@@ -0,0 +1,112 @@
//
// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/json
//
#ifndef BOOST_JSON_DETAIL_STORAGE_ADAPTOR_HPP
#define BOOST_JSON_DETAIL_STORAGE_ADAPTOR_HPP
#include <boost/beast/core/detail/config.hpp>
#include <boost/beast/core/detail/allocator.hpp>
#include <boost/json/storage.hpp>
#include <boost/align/align_up.hpp>
#include <boost/assert.hpp>
#include <boost/core/empty_value.hpp>
#include <atomic>
#include <cstddef>
namespace boost {
namespace beast {
namespace json {
namespace detail {
template<class Allocator>
using allocator_of_char =
typename beast::detail::allocator_traits<
Allocator>::template rebind_alloc<char>;
template<class Allocator>
struct storage_adaptor
: boost::empty_value<
allocator_of_char<Allocator>>
, storage
{
// VFALCO This is all public because msvc friend bugs
std::atomic<unsigned> count_;
explicit
storage_adaptor(Allocator const& alloc)
: boost::empty_value<
allocator_of_char<Allocator>>(
boost::empty_init_t{}, alloc)
, count_(1)
{
}
~storage_adaptor()
{
}
void
addref() noexcept override
{
++count_;
}
void
release() noexcept override
{
if(--count_ > 0)
return;
delete this;
}
void*
allocate(
std::size_t n,
std::size_t align) override
{
auto const n1 =
boost::alignment::align_up(n, align);
BOOST_ASSERT(n1 >= n);
return this->get().allocate(n1);
}
void
deallocate(
void* p,
std::size_t n,
std::size_t) noexcept override
{
this->get().deallocate(
reinterpret_cast<
char*>(p), n);
}
bool
is_equal(
storage const& other) const noexcept override
{
auto p = dynamic_cast<
storage_adaptor const*>(&other);
if(! p)
return false;
//return this->get() == p->get();
// VFALCO We require pointer equality
// to prevent objects from different
// "documents" getting mixed together.
return this == p;
}
};
} // detail
} // json
} // beast
} // boost
#endif

View File

@@ -0,0 +1,150 @@
//
// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/json
//
#ifndef BOOST_JSON_DETAIL_VALUE_HPP
#define BOOST_JSON_DETAIL_VALUE_HPP
#include <boost/beast/core/error.hpp>
#include <boost/type_traits/make_void.hpp>
#include <type_traits>
namespace boost {
namespace beast {
namespace json {
class value;
namespace detail {
// Determine if `to_json(value&,T)` is found via ADL
template<class T, class = void>
struct has_adl_to_json : std::false_type
{
};
template<class T>
struct has_adl_to_json<T,
boost::void_t<decltype(to_json(
std::declval<T const&>(),
std::declval<json::value&>()))>>
: std::true_type
{
};
// Determine if `from_json(T&,value)` is found via ADL
template<class T, class = void>
struct has_adl_from_json : std::false_type
{
};
template<class T>
struct has_adl_from_json<T,
boost::void_t<decltype(from_json(
std::declval<T&>(),
std::declval<json::value const&>()))>>
: std::true_type
{
};
// Determine if `t.to_json(value&)` exists
template<class T, class = void>
struct has_mf_to_json : std::false_type
{
};
template<class T>
struct has_mf_to_json<T,
boost::void_t<decltype(
std::declval<T const&>().to_json(
std::declval<json::value&>()))>>
: std::true_type
{
};
// Determine if `t.to_json(value const&)` exists
template<class T, class = void>
struct has_mf_from_json : std::false_type
{
};
template<class T>
struct has_mf_from_json<T,
boost::void_t<decltype(
std::declval<T&>().from_json(
std::declval<json::value const&>()))>>
: std::true_type
{
};
template<class T>
void
call_to_json(
T const& t,
value& v,
std::true_type)
{
t.to_json(v);
}
template<class T>
void
call_to_json(
T const& t,
value& v,
std::false_type)
{
to_json(t, v);
}
template<class T>
void
call_to_json(
T const& t,
value& v)
{
call_to_json(t, v,
has_mf_to_json<T>{});
}
template<class T>
void
call_from_json(
T& t,
value const& v,
std::true_type)
{
t.from_json(v);
}
template<class T>
void
call_from_json(
T& t,
value const& v,
std::false_type)
{
from_json(t, v);
}
template<class T>
void
call_from_json(
T& t,
value const& v)
{
call_from_json(t, v,
has_mf_from_json<T>{});
}
} // detail
} // json
} // beast
} // boost
#endif

View File

@@ -0,0 +1,45 @@
//
// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/json
//
#ifndef BOOST_JSON_DETAIL_VARINT_HPP
#define BOOST_JSON_DETAIL_VARINT_HPP
#include <cstdlib>
#include <cstdint>
#include <utility>
namespace boost {
namespace beast {
namespace json {
namespace detail {
BOOST_BEAST_DECL
int
varint_size(std::uint64_t value);
BOOST_BEAST_DECL
std::pair<std::uint64_t, int>
varint_read(void const* src);
BOOST_BEAST_DECL
int
varint_write(
void* dest,
std::uint64_t value);
} // detail
} // json
} // beast
} // boost
#ifdef BOOST_BEAST_HEADER_ONLY
#include <boost/json/detail/varint.ipp>
#endif
#endif

View File

@@ -0,0 +1,75 @@
//
// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/json
//
#ifndef BOOST_JSON_DETAIL_VARINT_IPP
#define BOOST_JSON_DETAIL_VARINT_IPP
#include <boost/json/detail/varint.hpp>
#include <utility>
namespace boost {
namespace beast {
namespace json {
namespace detail {
int
varint_size(std::uint64_t value)
{
int n = 1;
while(value > 127)
{
++n;
value /= 128;
}
return n;
}
std::pair<std::uint64_t, int>
varint_read(void const* src)
{
auto cp0 = reinterpret_cast<
unsigned char const*>(src);
auto cp = cp0;
std::size_t value = 0;
std::size_t factor = 1;
while(*cp > 127)
{
value += (*cp++ & 0x7f) * factor;
factor *= 128;
}
value += *cp++ * factor;
return {value,
static_cast<int>(cp - cp0)};
}
int
varint_write(
void* dest,
std::uint64_t value)
{
auto cp0 = reinterpret_cast<
unsigned char*>(dest);
auto cp = cp0;
while(value > 127)
{
*cp++ = static_cast<
unsigned char>(value & 0x7f);
value >>= 7;
}
*cp++ = static_cast<
unsigned char>(value);
return static_cast<int>(cp - cp0);
}
} // detail
} // json
} // beast
} // boost
#endif

View File

@@ -0,0 +1,81 @@
//
// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/json
//
#ifndef BOOST_JSON_ERROR_HPP
#define BOOST_JSON_ERROR_HPP
#include <boost/beast/core/detail/config.hpp>
#include <boost/beast/core/error.hpp>
namespace boost {
namespace beast {
namespace json {
/// Error codes returned by JSON operations
enum class error
{
syntax = 1,
/// Unexpected extra data encountered while parsing
extra_data,
/// A mantissa overflowed while parsing
mantissa_overflow,
/// The parser encountered an exponent that overflowed
exponent_overflow,
/// The parser's maximum depth limit was reached
too_deep,
/// Expected a value of kind object
expected_object,
/// Expected a value of kind array
expected_array,
/// Expected a value of kind string
expected_string,
/// Expect a value of kind number
expected_number,
/// Expected a value of kind boolean
expected_bool,
/// Expected a value of kind boolean
expected_null,
/// An integer assignment would overflow
integer_overflow,
/// The key was not found in the object
key_not_found
};
/// Error conditions corresponding to JSON errors
enum class condition
{
/// A parser-related error
parse_error = 1,
/// An error on assignment to or from a JSON value
assign_error
};
} // websocket
} // beast
} // boost
#include <boost/json/impl/error.hpp>
#ifdef BOOST_BEAST_HEADER_ONLY
#include <boost/json/impl/error.ipp>
#endif
#endif

View File

@@ -0,0 +1,99 @@
//
// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/json
//
#ifndef BOOST_JSON_IMPL_ALLOCATOR_HPP
#define BOOST_JSON_IMPL_ALLOCATOR_HPP
#include <memory>
#include <utility>
namespace boost {
namespace beast {
namespace json {
template<typename T>
allocator<T>::
allocator()
: sp_(default_storage())
{
}
template<typename T>
allocator<T>::
allocator(allocator&& other) noexcept
: allocator(other)
{
// Postcondition: *this == other
}
template<typename T>
auto
allocator<T>::
operator=(allocator&& other) noexcept ->
allocator&
{
// Postcondition: *this == other
sp_ = other.sp_;
return *this;
}
template<typename T>
template<typename U>
allocator<T>::
allocator(allocator<U> const& other) noexcept
: sp_(other.sp_)
{
}
template<typename T>
allocator<T>::
allocator(storage_ptr sp) noexcept
: sp_(std::move(sp))
{
}
template<typename T>
T*
allocator<T>::
allocate(size_t n)
{
return static_cast<T*>(sp_->allocate(
n * sizeof(T), alignof(T)));
}
template<typename T>
void
allocator<T>::
deallocate(T* p, size_t n) noexcept
{
sp_->deallocate(
p, n * sizeof(T), alignof(T));
}
template<typename T>
bool
allocator<T>::
operator==(allocator const& other) const noexcept
{
return *sp_ == *other.sp_;
}
template<typename T>
bool
allocator<T>::
operator!=(allocator const& other) const noexcept
{
return *sp_ != *other.sp_;
}
} // json
} // beast
} // boost
#endif

View File

@@ -0,0 +1,262 @@
//
// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/json
//
#ifndef BOOST_JSON_IMPL_ARRAY_HPP
#define BOOST_JSON_IMPL_ARRAY_HPP
#include <boost/json/value.hpp>
#include <boost/core/exchange.hpp>
#include <boost/static_assert.hpp>
#include <algorithm>
#include <type_traits>
namespace boost {
namespace beast {
namespace json {
//------------------------------------------------------------------------------
class array::table
{
union
{
std::size_t capacity_;
value unused_; // for alignment
};
BOOST_STATIC_ASSERT(
sizeof(value) >= sizeof(std::size_t));
BOOST_BEAST_DECL
~table();
public:
size_type size = 0;
explicit
table(size_type capacity)
: capacity_(capacity)
{
}
size_type
capacity() const noexcept
{
return capacity_;
}
value_type*
begin() noexcept
{
return reinterpret_cast<
value_type*>(this + 1);
}
value_type*
end() noexcept
{
return begin() + size;
}
BOOST_BEAST_DECL
static
table*
create(
size_type capacity,
storage_ptr const& sp);
BOOST_BEAST_DECL
static
void
destroy(
table* tab,
storage_ptr const& sp);
};
//------------------------------------------------------------------------------
struct array::cleanup_assign
{
array& self;
table* tab;
bool ok = false;
BOOST_BEAST_DECL
explicit
cleanup_assign(
array& self);
BOOST_BEAST_DECL
~cleanup_assign();
};
//------------------------------------------------------------------------------
struct array::cleanup_insert
{
array& self;
size_type pos;
size_type n;
size_type valid = 0;
bool ok = false;
BOOST_BEAST_DECL
cleanup_insert(
size_type pos_,
size_type n_,
array& self_);
BOOST_BEAST_DECL
~cleanup_insert();
};
//------------------------------------------------------------------------------
template<class InputIt>
array::
array(
InputIt first, InputIt last)
: array(
first, last,
default_storage())
{
}
template<class InputIt>
array::
array(
InputIt first, InputIt last,
storage_ptr store)
: array(
first, last,
std::move(store),
iter_cat<InputIt>{})
{
}
template<class InputIt>
auto
array::
insert(
const_iterator before,
InputIt first, InputIt last) ->
iterator
{
return insert(before, first, last,
iter_cat<InputIt>{});
}
template<class Arg>
auto
array::
emplace(
const_iterator before,
Arg&& arg) ->
iterator
{
return emplace_impl(
before, std::forward<Arg>(arg));
}
template<class Arg>
auto
array::
emplace_back(Arg&& arg) ->
reference
{
return *emplace_impl(
end(), std::forward<Arg>(arg));
}
//------------------------------------------------------------------------------
template<class InputIt>
array::
array(
InputIt first, InputIt last,
storage_ptr store,
std::input_iterator_tag)
: sp_(std::move(store))
{
while(first != last)
emplace_impl(end(), *first++);
}
template<class InputIt>
array::
array(
InputIt first, InputIt last,
storage_ptr store,
std::forward_iterator_tag)
: sp_(std::move(store))
{
reserve(std::distance(first, last));
while(first != last)
emplace_impl(end(), *first++);
}
template<class InputIt>
auto
array::
insert(
const_iterator before,
InputIt first, InputIt last,
std::input_iterator_tag) ->
iterator
{
auto pos = before - begin();
while(first != last)
before = insert(before, *first++) + 1;
return begin() + pos;
}
template<class InputIt>
auto
array::
insert(
const_iterator before,
InputIt first, InputIt last,
std::forward_iterator_tag) ->
iterator
{
auto count = std::distance(first, last);
auto pos = before - begin();
reserve(size() + count);
cleanup_insert c(pos, count, *this);
while(count--)
{
::new(&begin()[pos++]) value_type(
*first++, sp_);
++c.valid;
}
c.ok = true;
return begin() + c.pos;
}
template<class Arg>
auto
array::
emplace_impl(
const_iterator before,
Arg&& arg) ->
iterator
{
auto const pos = before - begin();
reserve(size() + 1);
cleanup_insert c(pos, 1, *this);
::new(&tab_->begin()[pos]) value_type(
std::forward<Arg>(arg), sp_);
c.ok = true;
return begin() + pos;
}
} // json
} // beast
} // boost
#endif

View File

@@ -0,0 +1,746 @@
//
// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/json
//
#ifndef BOOST_JSON_IMPL_ARRAY_IPP
#define BOOST_JSON_IMPL_ARRAY_IPP
#include <boost/json/array.hpp>
#include <boost/core/exchange.hpp>
#include <boost/assert.hpp>
#include <algorithm>
#include <cstdlib>
#include <limits>
#include <new>
#include <stdexcept>
#include <type_traits>
#include <utility>
namespace boost {
namespace beast {
namespace json {
//------------------------------------------------------------------------------
array::
table::
~table()
{
while(size > 0)
begin()[--size].~value();
}
auto
array::
table::
create(
size_type capacity,
storage_ptr const& sp) ->
table*
{
return ::new(sp->allocate(
sizeof(table) +
capacity * sizeof(value_type),
sizeof(value))) table(capacity);
}
void
array::
table::
destroy(
table* tab,
storage_ptr const& sp)
{
auto const capacity = tab->capacity();
tab->~table();
sp->deallocate(tab,
sizeof(table) +
capacity * sizeof(value_type),
sizeof(value));
}
//------------------------------------------------------------------------------
array::
cleanup_assign::
cleanup_assign(
array& self_)
: self(self_)
, tab(boost::exchange(
self_.tab_, nullptr))
{
}
array::
cleanup_assign::
~cleanup_assign()
{
if(ok)
{
if(tab)
table::destroy(tab, self.sp_);
}
else
{
if(self.tab_)
table::destroy(
self.tab_, self.sp_);
self.tab_ = tab;
}
}
//------------------------------------------------------------------------------
array::
cleanup_insert::
cleanup_insert(
size_type pos_,
size_type n_,
array& self_)
: self(self_)
, pos(pos_)
, n(n_)
{
self.move(
self.data() + pos + n,
self.data() + pos,
self.size() - pos);
}
array::
cleanup_insert::
~cleanup_insert()
{
if(ok)
{
self.tab_->size += n;
}
else
{
for(size_type i = n;
valid--; ++i)
self[i].~value();
self.move(
self.data() + pos,
self.data() + pos + n,
self.size() - pos);
}
}
//------------------------------------------------------------------------------
//
// Special Members
//
//------------------------------------------------------------------------------
array::
~array()
{
if(tab_)
table::destroy(tab_, sp_);
}
array::
array()
: sp_(default_storage())
{
}
array::
array(storage_ptr store)
: sp_(std::move(store))
{
}
array::
array(
size_type count)
: array(
count, kind::null,
default_storage())
{
}
array::
array(
size_type count,
storage_ptr store)
: array(
count, kind::null,
std::move(store))
{
}
array::
array(
size_type count,
value_type const& v)
: array(
count, v,
default_storage())
{
}
array::
array(
size_type count,
value_type const& v,
storage_ptr store)
: sp_(std::move(store))
{
resize(count, v);
}
array::
array(array const& other)
: sp_(other.get_storage())
{
*this = other;
}
array::
array(
array const& other,
storage_ptr store)
: sp_(std::move(store))
{
*this = other;
}
array::
array(array&& other) noexcept
: tab_(boost::exchange(
other.tab_, nullptr))
, sp_(other.sp_)
{
}
array::
array(
array&& other,
storage_ptr store)
: sp_(std::move(store))
{
*this = std::move(other);
}
array::
array(
std::initializer_list<value_type> list)
: sp_(default_storage())
{
*this = list;
}
array::
array(
std::initializer_list<value_type> list,
storage_ptr store)
: sp_(std::move(store))
{
*this = list;
}
array&
array::
operator=(array&& other)
{
if(*sp_ == *other.sp_)
{
if(tab_)
table::destroy(tab_, sp_);
tab_ = boost::exchange(
other.tab_, nullptr);
}
else
{
*this = other;
}
return *this;
}
array&
array::
operator=(array const& other)
{
cleanup_assign c(*this);
reserve(other.size());
for(auto const& v : other)
emplace_impl(end(), v);
c.ok = true;
return *this;
}
array&
array::
operator=(
std::initializer_list<value_type> list)
{
cleanup_assign c(*this);
reserve(list.size());
for(auto it = list.begin();
it != list.end(); ++it)
emplace_impl(end(), std::move(*it));
c.ok = true;
return *this;
}
//------------------------------------------------------------------------------
//
// Elements
//
//------------------------------------------------------------------------------
auto
array::
at(size_type pos) ->
reference
{
if(pos >= size())
throw std::out_of_range(
"json::array index out of bounds");
return tab_->begin()[pos];
}
auto
array::
at(size_type pos) const ->
const_reference
{
if(pos >= size())
throw std::out_of_range(
"json::array index out of bounds");
return tab_->begin()[pos];
}
auto
array::
operator[](size_type pos) ->
reference
{
return tab_->begin()[pos];
}
auto
array::
operator[](size_type pos) const ->
const_reference
{
return tab_->begin()[pos];
}
auto
array::
data() noexcept ->
value_type*
{
if(! tab_)
return nullptr;
return tab_->begin();
}
auto
array::
data() const noexcept ->
value_type const*
{
if(! tab_)
return nullptr;
return tab_->begin();
}
//------------------------------------------------------------------------------
//
// Iterators
//
//------------------------------------------------------------------------------
auto
array::
begin() noexcept ->
iterator
{
if(! tab_)
return nullptr;
return tab_->begin();
}
auto
array::
begin() const noexcept ->
const_iterator
{
if(! tab_)
return nullptr;
return tab_->begin();
}
auto
array::
end() noexcept ->
iterator
{
if(! tab_)
return nullptr;
return tab_->end();
}
auto
array::
end() const noexcept ->
const_iterator
{
if(! tab_)
return nullptr;
return tab_->end();
}
auto
array::
rbegin() noexcept ->
reverse_iterator
{
if(! tab_)
return reverse_iterator(nullptr);
return reverse_iterator(tab_->end());
}
auto
array::
rbegin() const noexcept ->
const_reverse_iterator
{
if(! tab_)
return const_reverse_iterator(nullptr);
return const_reverse_iterator(tab_->end());
}
auto
array::
rend() noexcept ->
reverse_iterator
{
if(! tab_)
return reverse_iterator(nullptr);
return reverse_iterator(tab_->begin());
}
auto
array::
rend() const noexcept ->
const_reverse_iterator
{
if(! tab_)
return const_reverse_iterator(nullptr);
return const_reverse_iterator(tab_->begin());
}
//------------------------------------------------------------------------------
//
// Capacity
//
//------------------------------------------------------------------------------
bool
array::
empty() const noexcept
{
return ! tab_ || tab_->size == 0;
}
auto
array::
size() const noexcept ->
size_type
{
if(! tab_)
return 0;
return tab_->size;
}
auto
array::
max_size() const noexcept ->
size_type
{
return (std::numeric_limits<
size_type>::max)() / sizeof(value_type);
}
void
array::
reserve(size_type new_capacity)
{
// minimum size is 3
if( new_capacity > 0 &&
new_capacity < 3)
new_capacity = 3;
// don't shrink
if( tab_ &&
new_capacity <= tab_->capacity())
return;
new_capacity = (std::max<size_type>)(
tab_ ? ((tab_->capacity() * 3 + 1) / 2) : 0,
new_capacity);
auto tab = table::create(new_capacity, sp_);
if(! tab_)
{
tab_ = tab;
return;
}
for(size_type i = 0; i < tab_->size; ++i)
::new(&tab->begin()[i]) value_type(
std::move(tab_->begin()[i]));
tab->size = tab_->size;
std::swap(tab, tab_);
table::destroy(tab, sp_);
}
auto
array::
capacity() const noexcept ->
size_type
{
if(! tab_)
return 0;
return tab_->capacity();
}
void
array::
shrink_to_fit() noexcept
{
if(! tab_ ||
tab_->capacity() <= tab_->size)
return;
auto tab = table::create(tab_->size, sp_);
for(size_type i = 0; i < tab_->size; ++i)
::new(&tab->begin()[i]) value_type(
std::move(tab_->begin()[i]));
tab->size = tab_->size;
std::swap(tab, tab_);
table::destroy(tab, sp_);
}
//------------------------------------------------------------------------------
//
// Modifiers
//
//------------------------------------------------------------------------------
void
array::
clear() noexcept
{
if(! tab_)
return;
destroy(begin(), end());
tab_->size = 0;
}
auto
array::
insert(
const_iterator before,
value_type const& v) ->
iterator
{
return emplace_impl(before, v);
}
auto
array::
insert(
const_iterator before,
value_type&& v) ->
iterator
{
return emplace_impl(
before, std::move(v));
}
auto
array::
insert(
const_iterator before,
size_type count,
value_type const& v) ->
iterator
{
auto pos = before - begin();
reserve(size() + count);
cleanup_insert c(pos, count, *this);
while(count--)
{
::new(&begin()[pos++])
value_type(v, sp_);
++c.valid;
}
c.ok = true;
return begin() + c.pos;
}
auto
array::
insert(
const_iterator before,
std::initializer_list<value_type> list) ->
iterator
{
auto pos = before - begin();
reserve(size() + list.size());
cleanup_insert c(
pos, list.size(), *this);
for(auto it = list.begin();
it != list.end(); ++it)
{
::new(&begin()[pos++]) value_type(
std::move(*it), sp_);
++c.valid;
}
c.ok = true;
return begin() + c.pos;
}
auto
array::
erase(const_iterator pos) ->
iterator
{
auto it = data() + (pos - begin());
destroy(it, it + 1);
move(it, it + 1, 1);
--tab_->size;
return it;
}
auto
array::
erase(
const_iterator first,
const_iterator last) ->
iterator
{
auto const n = last - first;
auto it = data() + (first - begin());
destroy(it, it + n);
move(it, it + n, n);
tab_->size -= n;
return it;
}
void
array::
push_back(value_type const& v)
{
emplace_impl(end(), v);
}
void
array::
push_back(value_type&& v)
{
emplace_impl(end(), std::move(v));
}
void
array::
pop_back()
{
back().~value();
--tab_->size;
}
void
array::
resize(size_type count)
{
resize(count, kind::null);
}
void
array::
resize(
size_type count,
value_type const& v)
{
if(count > size())
{
reserve(count);
while(count--)
emplace_impl(end(), v);
}
else if(count < size())
{
tab_->size = count;
count = size() - count;
for(size_type i = size() - 1;
count-- > 0; --i)
tab_->begin()[i].~value();
}
}
void
array::
swap(array& other) noexcept
{
BOOST_ASSERT(*sp_ == *other.sp_);
std::swap(tab_, other.tab_);
}
//------------------------------------------------------------------------------
void
array::
destroy(
value* first,
value* last)
{
while(first != last)
(*first++).~value();
}
void
array::
move(
value* to,
value* from,
size_type n) noexcept
{
if(to > from)
{
// backwards
to += n;
from += n;
while(n--)
{
::new(&*--to) value_type(
std::move(*--from));
from->~value();
}
}
else
{
while(n--)
{
::new(&*to++) value_type(
std::move(*from));
(*from++).~value();
}
}
}
} // json
} // beast
} // boost
#endif

View File

@@ -0,0 +1,76 @@
//
// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/json
//
#ifndef BOOST_JSON_IMPL_BASIC_PARSER_HPP
#define BOOST_JSON_IMPL_BASIC_PARSER_HPP
#include <boost/beast/core/buffers_range.hpp>
namespace boost {
namespace beast {
namespace json {
template<class ConstBufferSequence, class>
std::size_t
basic_parser::
write_some(
ConstBufferSequence const& buffers,
error_code& ec)
{
static_assert(
net::is_const_buffer_sequence<ConstBufferSequence>::value,
"ConstBufferSequence type requirements not met");
std::size_t bytes_used = 0;
for(auto const b : beast::buffers_range_ref(buffers))
{
bytes_used += write_some(b, ec);
if(ec)
break;
}
return bytes_used;
}
template<class ConstBufferSequence, class>
std::size_t
basic_parser::
write(
ConstBufferSequence const& buffers,
error_code& ec)
{
static_assert(
net::is_const_buffer_sequence<ConstBufferSequence>::value,
"ConstBufferSequence type requirements not met");
std::size_t bytes_used = 0;
auto it =
net::buffer_sequence_begin(buffers);
auto end =
net::buffer_sequence_end(buffers);
if(it == end)
{
ec = {};
return 0;
}
for(--end; it != end; ++it)
{
bytes_used +=
write_some(*it, ec);
if(ec)
return bytes_used;
}
bytes_used += write(*it, ec);
return bytes_used;
}
} // json
} // beast
} // boost
#endif

View File

@@ -0,0 +1,967 @@
//
// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/json
//
#ifndef BOOST_JSON_IMPL_BASIC_PARSER_IPP
#define BOOST_JSON_IMPL_BASIC_PARSER_IPP
#include <boost/json/basic_parser.hpp>
#include <boost/json/error.hpp>
#include <boost/beast/core/static_string.hpp>
#include <boost/assert.hpp>
namespace boost {
namespace beast {
namespace json {
/* References:
https://www.json.org/
RFC 7159: The JavaScript Object Notation (JSON) Data Interchange Format
https://tools.ietf.org/html/rfc7159
character
'0020' . '10ffff' - '"' - '\'
'\' escape
escape
'"'
'\'
'/'
'b'
'n'
'r'
't'
'u' hex hex hex hex
hex
digit
'A' . 'F'
'a' . 'f'
number
int frac exp
ws
""
'0009' ws
'000A' ws
'000D' ws
'0020' ws
*/
enum class basic_parser::state : char
{
json,
element,
ws,
value,
object1, object2, object3, object4, colon,
array1, array2, array3, array4,
string1, string2, string3,
true1, true2, true3, true4,
false1, false2, false3, false4, false5,
null1, null2, null3, null4,
number, number_mant1, number_mant2,
number_fract1, number_fract2, number_fract3,
number_exp, number_exp_sign,
number_exp_digits1, number_exp_digits2, number_end,
end
};
basic_parser::
basic_parser()
{
reset();
}
bool
basic_parser::is_done() const noexcept
{
return stack_.front() == state::end;
}
void
basic_parser::
reset()
{
stack_.clear();
stack_.push_front(state::end);
stack_.push_front(state::json);
}
//------------------------------------------------------------------------------
// Append the digit to the
// value, which must be unsigned.
// Returns `false` on overflow.
bool
basic_parser::
append_digit(
number::mantissa_type* value,
char digit)
{
number::mantissa_type temp =
*value * 10;
if(temp < *value)
return false;
number::mantissa_type result =
temp + digit;
if(result < temp)
return false;
*value = result;
return true;
}
// Append the digit to the signed exponent
bool
basic_parser::
append_digit(
number::exponent_type* value,
char digit, bool neg)
{
if(neg)
{
if(! *value)
{
*value = -digit;
}
else
{
*value *= 10;
*value -= digit;
}
}
else
{
*value *= 10;
*value += digit;
}
return true;
}
//------------------------------------------------------------------------------
void
basic_parser::
write_eof(error_code& ec)
{
// write a null, this is invalid no matter
// what state we are in, to get a descriptive
// error.
//
// VFALCO we might want to return error::partial_data
auto const fail =
[this, &ec]
{
char c = 0;
write_some(
boost::asio::const_buffer(
&c, 1), ec);
BOOST_ASSERT(ec);
};
while(stack_.front() != state::end)
{
// pop all states that
// allow "" (empty string)
switch(stack_.front())
{
case state::number_mant2:
case state::number_fract1:
case state::number_fract3:
case state::number_exp:
case state::number_exp_digits2:
stack_.front() = state::number_end;
write_some(
net::const_buffer{}, ec);
if(ec)
return;
break;
case state::ws:
stack_.pop_front();
break;
default:
return fail();
}
}
ec = {};
}
//------------------------------------------------------------------------------
std::size_t
basic_parser::
write_some(
net::const_buffer buffer,
error_code& ec)
{
auto p = static_cast<
char const*>(buffer.data());
auto n = buffer.size();
auto const p0 = p;
auto const p1 = p0 + n;
static_string<4096> temp;
ec.assign(0, ec.category());
BOOST_ASSERT(stack_.front() != state::end);
auto const maybe_flush =
[&]
{
if(temp.size() != temp.max_size())
return;
if(is_key_)
this->on_key_data(
{temp.data(), temp.size()}, ec);
else
this->on_string_data(
{temp.data(), temp.size()}, ec);
};
loop:
switch(stack_.front())
{
case state::json:
this->on_document_begin(ec);
if(ec)
goto finish;
stack_.front() = state::element;
temp.clear();
is_key_ = false;
goto loop;
case state::element:
stack_.front() = state::ws;
stack_.push_front(state::value);
stack_.push_front(state::ws);
goto loop;
case state::ws:
while(p < p1)
{
if(! is_ws(*p))
{
stack_.pop_front();
goto loop;
}
++p;
}
break;
case state::value:
{
if(p >= p1)
break;
switch(*p)
{
// object
case '{':
stack_.front() = state::object1;
goto loop;
// array
case '[':
++p;
stack_.front() = state::array1;
this->on_array_begin(ec);
goto loop;
// string
case '"':
stack_.front() = state::string1;
goto loop;
// number
case '0':
case '1': case '2': case '3':
case '4': case '5': case '6':
case '7': case '8': case '9':
case '-':
stack_.front() = state::number;
goto loop;
// true
case 't':
if(p + 4 <= p1)
{
if(
p[1] != 'r' ||
p[2] != 'u' ||
p[3] != 'e')
{
ec = error::syntax;
goto finish;
}
p = p + 4;
stack_.front() = state::true4;
goto loop;
}
++p;
stack_.front() = state::true1;
goto loop;
// false
case 'f':
if(p + 5 <= p1)
{
if(
p[1] != 'a' ||
p[2] != 'l' ||
p[3] != 's' ||
p[4] != 'e')
{
ec = error::syntax;
goto finish;
}
p = p + 5;
stack_.front() = state::false5;
goto loop;
}
++p;
stack_.front() = state::false1;
goto loop;
// null
case 'n':
if(p + 4 <= p1)
{
if(
p[1] != 'u' ||
p[2] != 'l' ||
p[3] != 'l')
{
ec = error::syntax;
goto finish;
}
p = p + 4;
stack_.front() = state::null4;
goto loop;
}
++p;
stack_.front() = state::null1;
goto loop;
default:
ec = error::syntax;
goto finish;
}
break;
}
//--------------------------------------------------------------------------
//
// object
//
// beginning of object
case state::object1:
BOOST_ASSERT(*p == '{');
++p;
this->on_object_begin(ec);
if(ec)
goto finish;
stack_.front() = state::object2;
stack_.push_front(state::ws);
goto loop;
// first key or end of object
case state::object2:
if(p >= p1)
break;
if(*p == '}')
{
++p;
stack_.front() = state::object4;
goto loop;
}
stack_.front() = state::object3;
stack_.push_front(state::element);
stack_.push_front(state::colon);
stack_.push_front(state::ws);
stack_.push_front(state::string1);
is_key_ = true;
goto loop;
case state::object3:
if(p >= p1)
break;
if(*p == '}')
{
++p;
stack_.front() = state::object4;
goto loop;
}
if(*p != ',')
{
ec = error::syntax;
goto finish;
}
++p;
stack_.front() = state::object3;
stack_.push_front(state::element);
stack_.push_front(state::colon);
stack_.push_front(state::ws);
stack_.push_front(state::string1);
stack_.push_front(state::ws);
is_key_ = true;
goto loop;
case state::object4:
this->on_object_end(ec);
if(ec)
goto finish;
stack_.pop_front();
goto loop;
case state::colon:
if(p >= p1)
break;
if(*p != ':')
{
ec = error::syntax;
goto finish;
}
++p;
stack_.pop_front();
goto loop;
//--------------------------------------------------------------------------
//
// array
//
case state::array1:
stack_.front() = state::array2;
stack_.push_front(state::ws);
goto loop;
case state::array2:
if(p >= p1)
break;
if(*p == ']')
{
++p;
stack_.front() = state::array4;
goto loop;
}
stack_.front() = state::array3;
stack_.push_front(state::element);
goto loop;
case state::array3:
if(p >= p1)
break;
if(*p == ']')
{
++p;
stack_.front() = state::array4;
goto loop;
}
if(*p != ',')
{
ec = error::syntax;
goto finish;
}
++p;
stack_.front() = state::array3;
stack_.push_front(state::element);
stack_.push_front(state::ws);
goto loop;
case state::array4:
this->on_array_end(ec);
if(ec)
goto finish;
stack_.pop_front();
goto loop;
//--------------------------------------------------------------------------
//
// string
//
// double quote opening string
case state::string1:
if(p >= p1)
break;
if(*p != '\"')
{
ec = error::syntax;
goto finish;
}
++p;
stack_.front() = state::string2;
goto loop;
// characters
case state::string2:
while(p < p1)
{
if(*p == '\"')
{
++p;
if(is_key_)
this->on_key_end({temp.data(),
temp.size()}, ec);
else
this->on_string_end({temp.data(),
temp.size()}, ec);
if(ec)
goto finish;
temp.clear();
is_key_ = false;
stack_.pop_front();
goto loop;
}
if(*p == '\\')
{
++p;
stack_.front() = state::string3;
goto loop;
}
if(is_control(*p))
{
ec = error::syntax;
goto finish;
}
// TODO UTF-8
maybe_flush();
temp.push_back(*p++);
}
break;
// escape
case state::string3:
if(p >= p1)
break;
switch(*p)
{
case '\"':
maybe_flush();
temp.push_back('\"');
break;
case '\\':
maybe_flush();
temp.push_back('\\');
break;
case '/':
maybe_flush();
temp.push_back('/');
break;
case 'b':
maybe_flush();
temp.push_back('\x08');
break;
case 'f':
maybe_flush();
temp.push_back('\x08');
break;
case 'n':
maybe_flush();
temp.push_back('\x0a');
break;
case 'r':
maybe_flush();
temp.push_back('\x0d');
break;
case 't':
maybe_flush();
temp.push_back('\x09');
break;
case 'u':
BOOST_ASSERT(false);
break;
default:
ec = error::syntax;
goto finish;
}
++p;
stack_.front()=state::string2;
goto loop;
//--------------------------------------------------------------------------
//
// true
//
case state::true1:
if(p >= p1)
break;
if(*p != 'r')
{
ec = error::syntax;
goto finish;
}
++p;
stack_.front() = state::true2;
BOOST_FALLTHROUGH;
case state::true2:
if(p >= p1)
break;
if(*p != 'u')
{
ec = error::syntax;
goto finish;
}
++p;
stack_.front() = state::true3;
BOOST_FALLTHROUGH;
case state::true3:
if(p >= p1)
break;
if(*p != 'e')
{
ec = error::syntax;
goto finish;
}
++p;
stack_.front() = state::true4;
BOOST_FALLTHROUGH;
case state::true4:
this->on_bool(true, ec);
if(ec)
goto finish;
stack_.pop_front();
goto loop;
//
// false
//
case state::false1:
if(p >= p1)
break;
if(*p != 'a')
{
ec = error::syntax;
goto finish;
}
++p;
stack_.front() = state::false2;
BOOST_FALLTHROUGH;
case state::false2:
if(p >= p1)
break;
if(*p != 'l')
{
ec = error::syntax;
goto finish;
}
++p;
stack_.front() = state::false3;
BOOST_FALLTHROUGH;
case state::false3:
if(p >= p1)
break;
if(*p != 's')
{
ec = error::syntax;
goto finish;
}
++p;
stack_.front() = state::false4;
BOOST_FALLTHROUGH;
case state::false4:
if(p >= p1)
break;
if(*p != 'e')
{
ec = error::syntax;
goto finish;
}
++p;
stack_.front() = state::false5;
BOOST_FALLTHROUGH;
case state::false5:
this->on_bool(false, ec);
if(ec)
goto finish;
stack_.pop_front();
goto loop;
//
// null
//
case state::null1:
if(p >= p1)
break;
if(*p != 'u')
{
ec = error::syntax;
goto finish;
}
++p;
stack_.front() = state::null2;
BOOST_FALLTHROUGH;
case state::null2:
if(p >= p1)
break;
if(*p != 'l')
{
ec = error::syntax;
goto finish;
}
++p;
stack_.front() = state::null3;
BOOST_FALLTHROUGH;
case state::null3:
if(p >= p1)
break;
if(*p != 'l')
{
ec = error::syntax;
goto finish;
}
++p;
stack_.front() = state::null4;
BOOST_FALLTHROUGH;
case state::null4:
this->on_null(ec);
if(ec)
goto finish;
stack_.pop_front();
goto loop;
//
// number
//
case state::number:
BOOST_ASSERT(p < p1);
n_mant_ = 0;
n_exp_ = 0;
if(*p == '-')
{
++p;
n_neg_ = true;
}
else
{
n_neg_ = false;
}
stack_.front() = state::number_mant1;
goto loop;
case state::number_mant1:
if(p >= p1)
break;
if(! is_digit(*p))
{
// expected mantissa digit
ec = error::syntax;
goto finish;
}
if(*p != '0')
{
stack_.front() = state::number_mant2;
goto loop;
}
++p;
stack_.front() = state::number_fract1;
goto loop;
case state::number_mant2:
while(p < p1)
{
if(! is_digit(*p))
{
stack_.front() = state::number_fract1;
goto loop;
}
if(! append_digit(&n_mant_, *p++ - '0'))
{
ec = error::mantissa_overflow;
goto finish;
}
}
break;
case state::number_fract1:
if(p >= p1)
break;
if(*p == '.')
{
++p;
stack_.front() = state::number_fract2;
goto loop;
}
if(is_digit(*p))
{
// unexpected digit after zero
ec = error::syntax;
goto finish;
}
stack_.front() = state::number_exp;
goto loop;
case state::number_fract2:
if(p >= p1)
break;
if(! is_digit(*p))
{
// expected mantissa fraction digit
ec = error::syntax;
goto finish;
}
stack_.front() = state::number_fract3;
goto loop;
case state::number_fract3:
while(p < p1)
{
if(! is_digit(*p))
{
stack_.front() = state::number_exp;
goto loop;
}
if(! append_digit(&n_mant_, *p++ - '0'))
{
ec = error::mantissa_overflow;
goto finish;
}
--n_exp_;
}
break;
case state::number_exp:
if(p >= p1)
break;
if(*p == 'e' || *p == 'E')
{
++p;
stack_.front() = state::number_exp_sign;
goto loop;
}
stack_.front() = state::number_end;
goto loop;
case state::number_exp_sign:
if(p >= p1)
break;
if(*p == '+')
{
++p;
n_exp_neg_ = false;
}
else if(*p == '-')
{
++p;
n_exp_neg_ = true;
}
else
{
n_exp_neg_ = false;
}
stack_.front() = state::number_exp_digits1;
goto loop;
case state::number_exp_digits1:
if(p >= p1)
break;
if(! is_digit(*p))
{
// expected exponent digit
ec = error::syntax;
goto finish;
}
stack_.front() = state::number_exp_digits2;
goto loop;
case state::number_exp_digits2:
while(p < p1)
{
if(! is_digit(*p))
{
stack_.front() = state::number_end;
goto loop;
}
if(! append_digit(&n_exp_,
*p++ - '0', n_exp_neg_))
{
ec = error::exponent_overflow;
goto finish;
}
}
break;
case state::number_end:
this->on_number(number(
n_mant_, n_exp_, n_neg_), ec);
if(ec)
goto finish;
stack_.pop_front();
goto loop;
//
// (end)
//
case state::end:
/*
if(p < p1)
{
// unexpected extra characters
ec = error::syntax;
goto finish;
}
*/
break;
}
finish:
return p - p0;
}
//------------------------------------------------------------------------------
// Called to parse the rest of the document, this
// can be optimized by assuming no more data is coming.
std::size_t
basic_parser::
write(
net::const_buffer buffer,
error_code& ec)
{
auto bytes_used =
write_some(buffer, ec);
if(! ec)
write_eof(ec);
return bytes_used;
}
} // json
} // beast
} // boost
#endif

View File

@@ -0,0 +1,46 @@
//
// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/json
//
#ifndef BOOST_JSON_IMPL_ERROR_HPP
#define BOOST_JSON_IMPL_ERROR_HPP
#include <type_traits>
namespace boost {
namespace system {
template<>
struct is_error_code_enum<::boost::beast::json::error>
{
static bool const value = true;
};
template<>
struct is_error_condition_enum<::boost::beast::json::condition>
{
static bool const value = true;
};
} // system
} // boost
namespace boost {
namespace beast {
namespace json {
BOOST_BEAST_DECL
error_code
make_error_code(error e);
BOOST_BEAST_DECL
error_condition
make_error_condition(condition c);
} // json
} // beast
} // boost
#endif

View File

@@ -0,0 +1,157 @@
//
// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/json
//
#ifndef BOOST_JSON_IMPL_ERROR_IPP
#define BOOST_JSON_IMPL_ERROR_IPP
#include <boost/json/error.hpp>
namespace boost {
namespace beast {
namespace json {
namespace detail {
class error_codes : public error_category
{
public:
const char*
name() const noexcept override
{
return "boost.beast.json";
}
BOOST_BEAST_DECL
std::string
message(int ev) const override
{
switch(static_cast<error>(ev))
{
default:
case error::syntax: return
"The serialized JSON object contains a syntax error";
case error::extra_data: return
"Unexpected extra data encountered while parsing";
case error::mantissa_overflow: return
"A mantissa overflowed while parsing";
case error::exponent_overflow: return
"An exponent overflowed while parsing";
case error::too_deep: return
"The parser reached the maximum allowed depth";
//
case error::integer_overflow: return
"An integer assignment overflowed";
case error::expected_object: return
"Expected a value of kind object";
case error::expected_array: return
"Expected a value of kind array";
case error::expected_string: return
"Expected a value of kind string";
case error::expected_number: return
"Expected a value of kind number";
case error::expected_bool: return
"Expected a value of kind bool";
case error::expected_null: return
"Expected a value of kind null";
//
case error::key_not_found: return
"The key was not found in the object";
}
}
BOOST_BEAST_DECL
error_condition
default_error_condition(int ev) const noexcept override
{
switch(static_cast<error>(ev))
{
default:
return {ev, *this};
case error::syntax:
case error::extra_data:
case error::mantissa_overflow:
case error::exponent_overflow:
case error::too_deep:
return condition::parse_error;
case error::integer_overflow:
case error::expected_object:
case error::expected_array:
case error::expected_string:
case error::expected_number:
case error::expected_bool:
case error::expected_null:
return condition::assign_error;
}
}
};
class error_conditions : public error_category
{
public:
BOOST_BEAST_DECL
const char*
name() const noexcept override
{
return "boost.beast";
}
BOOST_BEAST_DECL
std::string
message(int cv) const override
{
switch(static_cast<condition>(cv))
{
default:
case condition::parse_error:
return "A JSON parsing error occurred";
case condition::assign_error:
return "An error occurred during assignment";
}
}
};
} // detail
error_code
make_error_code(error e)
{
static detail::error_codes const cat{};
return error_code{static_cast<
std::underlying_type<error>::type>(e), cat};
}
error_condition
make_error_condition(condition c)
{
static detail::error_conditions const cat{};
return error_condition{static_cast<
std::underlying_type<condition>::type>(c), cat};
}
} // json
} // beast
} // boost
#endif

View File

@@ -0,0 +1,214 @@
//
// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/json
//
#ifndef BOOST_JSON_ITERATOR_IMPL_IPP
#define BOOST_JSON_ITERATOR_IMPL_IPP
#include <boost/json/iterator.hpp>
namespace boost {
namespace beast {
namespace json {
const_iterator::
node::
~node()
{
if(it)
{
if(v->is_object())
{
obj_it.~const_iterator();
}
else
{
// VFALCO Why not?
//arr.it.~const_iterator();
}
}
}
const_iterator::
node::
node(
value const& v_,
bool it_) noexcept
: v(&v_)
, it(it_)
{
if(it)
{
BOOST_ASSERT(
v->is_structured());
if(v->is_object())
::new(&obj_it)
object::const_iterator(
v->as_object().begin());
else
::new(&arr_it)
array::const_iterator(
v->as_array().begin());
}
}
const_iterator::
node::
node(node const& other) noexcept
: v(other.v)
, key(other.key)
{
it = other.it;
if(it)
::new(&obj_it)
object::const_iterator(
other.obj_it);
else
::new(&arr_it)
array::const_iterator(
other.arr_it);
}
bool
const_iterator::
node::
last() const noexcept
{
if(! it)
return true;
if(v->is_object())
return obj_it ==
v->as_object().end();
return arr_it ==
v->as_array().end();
}
//------------------------------------------------------------------------------
const_iterator::
const_iterator(
value const& jv)
{
stack_.emplace_front(
jv, false);
}
auto
const_iterator::
operator*() const noexcept ->
value_type
{
auto const& n = stack_.front();
if(! n.it)
{
BOOST_ASSERT(
stack_.size() == 1);
return {
stack_.size() - 1,
n.key,
*n.v,
true,
false };
}
BOOST_ASSERT(n.v->is_structured());
if(n.v->is_object())
{
if(n.obj_it !=
n.v->as_object().end())
return {
stack_.size(),
n.obj_it->first,
n.obj_it->second,
std::next(n.obj_it) ==
n.v->as_object().end(),
false };
return {
stack_.size() - 1,
"",
*n.v,
stack_.size() == 1
|| stack_[1].last(),
true};
}
if(n.arr_it !=
n.v->as_array().end())
return {
stack_.size(),
"",
*n.arr_it,
std::next(n.arr_it) ==
n.v->as_array().end(),
false };
return {
stack_.size() - 1,
"",
*n.v,
stack_.size() == 1
|| stack_[1].last(),
true};
}
const_iterator&
const_iterator::
operator++() noexcept
{
auto& n = stack_.front();
if(! n.it)
{
if(n.v->is_structured())
{
stack_.pop_front();
stack_.emplace_front(
*n.v, true);
}
else
{
stack_.pop_front();
}
}
else if(n.v->is_object())
{
if(n.obj_it ==
n.v->as_object().end())
{
stack_.pop_front();
}
else
{
auto const& jv =
n.obj_it->second;
if(jv.is_structured())
stack_.emplace_front(
jv, true);
++n.obj_it;
}
}
else
{
if(n.arr_it ==
n.v->as_array().end())
{
stack_.pop_front();
}
else
{
auto const& jv = *n.arr_it;
if(jv.is_structured())
stack_.emplace_front(
jv, true);
++n.arr_it;
}
}
return *this;
}
} // json
} // beast
} // boost
#endif

View File

@@ -0,0 +1,454 @@
//
// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/json
//
#ifndef BOOST_JSON_IMPL_NUMBER_IPP
#define BOOST_JSON_IMPL_NUMBER_IPP
#include <boost/json/number.hpp>
#include <boost/beast/core/static_string.hpp>
#include <algorithm>
#include <cmath>
#include <cstdint>
#include <ostream>
#include <cstdio>
#include <string>
#include <vector>
namespace boost {
namespace beast {
namespace json {
//------------------------------------------------------------------------------
struct number::pow10
{
std::size_t
size() const noexcept
{
return size_;
}
mantissa_type const*
begin() const noexcept
{
return begin_;
}
mantissa_type const*
end() const noexcept
{
return end_;
}
mantissa_type
operator[](
exponent_type n) const
{
return begin_[n];
}
static
pow10 const&
get() noexcept
{
struct pow10_impl : pow10
{
pow10_impl()
{
static mantissa_type constexpr list[] = {
1ULL,
10ULL,
100ULL,
1000ULL,
10000ULL,
100000ULL,
1000000ULL,
10000000ULL,
100000000ULL,
1000000000ULL,
10000000000ULL,
100000000000ULL,
1000000000000ULL,
10000000000000ULL,
100000000000000ULL,
1000000000000000ULL,
10000000000000000ULL,
100000000000000000ULL,
1000000000000000000ULL,
10000000000000000000ULL
};
size_ = std::extent<
decltype(list)>::value;
begin_ = &list[0];
end_ = &list[size_];
}
};
static pow10_impl const tab;
return tab;
}
protected:
std::size_t size_;
mantissa_type const* begin_;
mantissa_type const* end_;
};
//------------------------------------------------------------------------------
number::
number(
mantissa_type mant,
exponent_type exp,
bool sign) noexcept
{
auto const as_double =
[&]
{
double d =
static_cast<double>(mant) *
std::pow(10, exp);
if(sign)
d *= -1;
return d;
};
if(exp == 0)
{
if(! sign)
{
assign_unsigned(mant);
}
else if(mant <= static_cast<unsigned long long>(
(std::numeric_limits<long long>::max)()) + 1)
{
assign_signed(static_cast<long long>(mant));
}
else
{
assign_double(as_double());
}
}
else
{
auto const d = as_double();
if(! sign)
{
auto v = static_cast<unsigned long long>(d);
if(v == d)
assign_unsigned(v);
else
assign_double(d);
}
else
{
auto v = static_cast<long long>(d);
if(v == d)
assign_signed(v);
else
assign_double(d);
}
}
}
//------------------------------------------------------------------------------
number::
number(short i) noexcept
{
assign_signed(i);
}
number::
number(int i) noexcept
{
assign_signed(i);
}
number::
number(long i) noexcept
{
assign_signed(i);
}
number::
number(long long i) noexcept
{
assign_signed(i);
}
number::
number(unsigned short i) noexcept
{
assign_unsigned(i);
}
number::
number(unsigned int i) noexcept
{
assign_unsigned(i);
}
number::
number(unsigned long i) noexcept
{
assign_unsigned(i);
}
number::
number(unsigned long long i) noexcept
{
assign_unsigned(i);
}
number::
number(float f) noexcept
{
assign_double(f);
}
number::
number(double f) noexcept
{
assign_double(f);
}
//------------------------------------------------------------------------------
bool
number::
is_int64() const noexcept
{
switch(k_)
{
case type_int64:
return true;
case type_uint64:
return int64_ >= 0;
case type_double:
return static_cast<long long>(
double_) == double_;
default:
case type_ieee:
break;
}
return false;
}
bool
number::
is_uint64() const noexcept
{
switch(k_)
{
case type_int64:
return int64_ >= 0;
case type_uint64:
return true;
case type_double:
return static_cast<
unsigned long long>(
double_) == double_;
default:
case type_ieee:
break;
}
return false;
}
std::int_least64_t
number::
get_int64() const noexcept
{
switch(k_)
{
case type_int64:
return int64_;
case type_uint64:
return static_cast<
long long>(uint64_);
case type_double:
return static_cast<
long long>(double_);
default:
case type_ieee:
break;
}
return 0;
}
std::uint_least64_t
number::
get_uint64() const noexcept
{
switch(k_)
{
case type_int64:
return static_cast<
unsigned long long>(int64_);
case type_uint64:
return uint64_;
case type_double:
return static_cast<
unsigned long long>(double_);
default:
case type_ieee:
break;
}
return 0;
}
double
number::
get_double() const noexcept
{
switch(k_)
{
case type_int64:
return static_cast<double>(int64_);
case type_uint64:
return static_cast<double>(uint64_);
case type_double:
return double_;
default:
case type_ieee:
break;
}
return 0;
}
string_view
number::
print(
char* buf,
std::size_t buf_size) const noexcept
{
int n;
switch(k_)
{
case type_int64:
n = snprintf(buf, buf_size,
"%lld", int64_);
break;
case type_uint64:
n = snprintf(buf, buf_size,
"%llu", uint64_);
break;
case type_double:
n = snprintf(buf, buf_size,
"%e", double_);
break;
default:
case type_ieee:
n = snprintf(buf, buf_size,
"_unimpl");
break;
}
return { buf, static_cast<
std::size_t>(n) };
}
//------------------------------------------------------------------------------
void
number::
assign_signed(long long i) noexcept
{
k_ = type_int64;
int64_ = i;
}
void
number::
assign_unsigned(unsigned long long i) noexcept
{
k_ = type_uint64;
uint64_ = i;
}
void
number::
assign_double(double f) noexcept
{
k_ = type_double;
double_ = f;
}
//------------------------------------------------------------------------------
std::ostream&
operator<<(std::ostream& os, number const& n)
{
char buf[number::max_string_chars];
os << n.print(buf, sizeof(buf));
return os;
}
bool
operator==(
number const& lhs,
number const& rhs) noexcept
{
switch(lhs.k_)
{
case number::type_int64:
return
rhs.is_int64() &&
lhs.get_int64() ==
rhs.get_int64();
case number::type_uint64:
return
rhs.is_uint64() &&
lhs.get_uint64() ==
rhs.get_uint64();
case number::type_double:
return
lhs.get_double() ==
rhs.get_double();
default:
case number::type_ieee:
break;
}
return false;
}
bool
operator!=(
number const& lhs,
number const& rhs) noexcept
{
return !(lhs == rhs);
}
} // json
} // beast
} // boost
#endif

View File

@@ -0,0 +1,932 @@
//
// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/json
//
#ifndef BOOST_JSON_IMPL_OBJECT_HPP
#define BOOST_JSON_IMPL_OBJECT_HPP
#include <boost/json/value.hpp>
#include <boost/json/detail/varint.hpp>
#include <boost/core/exchange.hpp>
#include <boost/core/ignore_unused.hpp>
#include <algorithm>
#include <type_traits>
namespace boost {
namespace beast {
namespace json {
//------------------------------------------------------------------------------
struct object::list_hook
{
public:
element* prev_;
element* next_;
};
//------------------------------------------------------------------------------
struct object::element
: public list_hook
{
value v_;
element* local_next_;
BOOST_BEAST_DECL
string_view
key() const noexcept;
struct cleanup
{
std::size_t size;
storage_ptr const& sp;
std::size_t n;
void
operator()(char* p)
{
sp->deallocate(p,
size, alignof(element));
}
};
template<class Arg>
static
element*
allocate(
storage_ptr const& sp,
key_type key,
Arg&& arg)
{
auto up =
prepare_allocate(sp, key);
auto const p = up.get();
auto const n = up.get_deleter().n;
auto e = ::new(up.get()) element(
std::forward<Arg>(arg), sp);
up.release();
detail::varint_write(
p + sizeof(element), key.size());
std::memcpy(
p + sizeof(element) + n,
key.data(),
key.size());
p[sizeof(element) +
n + key.size()] = '\0';
boost::ignore_unused(e);
BOOST_ASSERT(
*e->v_.get_storage() == *sp);
return reinterpret_cast<element*>(p);
}
BOOST_BEAST_DECL
static
void
destroy(
element const* e,
storage_ptr const& sp);
private:
template<class Arg>
element(
Arg&& arg,
storage_ptr sp)
: v_(std::forward<Arg>(arg),
std::move(sp))
{
}
BOOST_BEAST_DECL
static
std::unique_ptr<char, cleanup>
prepare_allocate(
storage_ptr const& sp,
key_type key);
};
//------------------------------------------------------------------------------
class object::hasher
{
BOOST_BEAST_DECL
static
std::pair<
std::uint64_t, std::uint64_t>
init(std::true_type) noexcept;
BOOST_BEAST_DECL
static
std::pair<
std::uint32_t, std::uint32_t>
init(std::false_type) noexcept;
public:
BOOST_BEAST_DECL
std::size_t
operator()(key_type key) const noexcept;
};
//------------------------------------------------------------------------------
class object::key_equal
{
public:
bool
operator()(
beast::string_view lhs,
beast::string_view rhs) const noexcept
{
return lhs == rhs;
}
};
//------------------------------------------------------------------------------
class object::pointer
{
reference t_;
public:
pointer(reference t)
: t_(t)
{
}
reference*
operator->() noexcept
{
return &t_;
}
};
//------------------------------------------------------------------------------
class object::const_pointer
{
const_reference t_;
public:
const_pointer(
const_reference t)
: t_(t)
{
}
const_reference*
operator->() noexcept
{
return &t_;
}
};
//------------------------------------------------------------------------------
class object::iterator
{
element* e_ = nullptr;
friend class object;
iterator(element* e)
: e_(e)
{
}
public:
using value_type = object::value_type;
using pointer = object::pointer;
using reference = object::reference;
using difference_type = std::ptrdiff_t;
using iterator_category =
std::bidirectional_iterator_tag;
iterator() = default;
iterator(
iterator const&) = default;
iterator& operator=(
iterator const&) = default;
bool
operator==(
iterator const& other) const noexcept
{
return e_ == other.e_;
}
bool
operator!=(
iterator const& other) const noexcept
{
return e_ != other.e_;
}
bool
operator==(
const_iterator const& other) const noexcept;
bool
operator!=(
const_iterator const& other) const noexcept;
iterator&
operator++() noexcept
{
e_ = e_->next_;
return *this;
}
iterator
operator++(int) noexcept
{
auto tmp = *this;
++*this;
return tmp;
}
iterator&
operator--() noexcept
{
e_ = e_->prev_;
return *this;
}
iterator
operator--(int) noexcept
{
auto tmp = *this;
--*this;
return tmp;
}
pointer
operator->() const noexcept
{
return reference{
e_->key(), e_->v_ };
}
reference
operator*() const noexcept
{
return {
e_->key(), e_->v_ };
}
};
//------------------------------------------------------------------------------
class object::const_iterator
{
element* e_ = nullptr;
friend class object;
const_iterator(element* e)
: e_(e)
{
}
public:
using value_type = object::value_type;
using pointer = object::const_pointer;
using reference = object::const_reference;
using difference_type = std::ptrdiff_t;
using iterator_category =
std::bidirectional_iterator_tag;
const_iterator() = default;
const_iterator(
const_iterator const&) = default;
const_iterator& operator=(
const_iterator const&) = default;
const_iterator(iterator it)
: e_(it.e_)
{
}
const_iterator&
operator=(iterator it) noexcept
{
e_ = it.e_;
return *this;
}
bool
operator==(
const_iterator const& other) const noexcept
{
return e_ == other.e_;
}
bool
operator!=(
const_iterator const& other) const noexcept
{
return e_ != other.e_;
}
bool
operator==(
iterator const& other) const noexcept
{
return e_ == other.e_;
}
bool
operator!=(
iterator const& other) const noexcept
{
return e_ != other.e_;
}
const_iterator&
operator++() noexcept
{
e_ = e_->next_;
return *this;
}
const_iterator
operator++(int) noexcept
{
auto tmp = *this;
++*this;
return tmp;
}
const_iterator&
operator--() noexcept
{
e_ = e_->prev_;
return *this;
}
const_iterator
operator--(int) noexcept
{
auto tmp = *this;
--*this;
return tmp;
}
pointer
operator->() const noexcept
{
return const_reference{
e_->key(), e_->v_ };
}
reference
operator*() const noexcept
{
return {
e_->key(), e_->v_ };
}
};
inline
bool
object::
iterator::
operator==(
const_iterator const& other) const noexcept
{
return e_ == other.e_;
}
inline
bool
object::
iterator::
operator!=(
const_iterator const& other) const noexcept
{
return e_ != other.e_;
}
//------------------------------------------------------------------------------
class object::local_iterator
{
element* e_ = nullptr;
friend class object;
local_iterator(element* e)
: e_(e)
{
}
public:
using value_type = object::value_type;
using reference = object::reference;
local_iterator() = default;
local_iterator(
local_iterator const&) = default;
local_iterator& operator=(
local_iterator const&) = default;
bool
operator==(
local_iterator const& other) const noexcept
{
return e_ == other.e_;
}
bool
operator!=(
local_iterator const& other) const noexcept
{
return e_ != other.e_;
}
bool
operator==(
iterator const& other) const noexcept
{
return e_ == other.e_;
}
bool
operator!=(
iterator const& other) const noexcept
{
return e_ != other.e_;
}
local_iterator&
operator++() noexcept
{
e_ = e_->local_next_;
return *this;
}
local_iterator
operator++(int) noexcept
{
auto tmp = *this;
++*this;
return tmp;
}
const_pointer
operator->() const noexcept
{
return const_reference{
e_->key(), e_->v_ };
}
const_reference
operator*() const noexcept
{
return {
e_->key(), e_->v_ };
}
};
//------------------------------------------------------------------------------
class object::const_local_iterator
{
element const* e_ = nullptr;
friend class object;
const_local_iterator(element const* e)
: e_(e)
{
}
public:
using value_type = object::value_type;
using reference = object::const_reference;
const_local_iterator() = default;
const_local_iterator(
const_local_iterator const&) = default;
const_local_iterator& operator=(
const_local_iterator const&) = default;
bool
operator==(
const_local_iterator const& other) const noexcept
{
return e_ == other.e_;
}
bool
operator!=(
const_local_iterator const& other) const noexcept
{
return e_ != other.e_;
}
bool
operator==(
iterator const& other) const noexcept
{
return e_ == other.e_;
}
bool
operator!=(
iterator const& other) const noexcept
{
return e_ != other.e_;
}
const_local_iterator&
operator++() noexcept
{
e_ = e_->local_next_;
return *this;
}
const_local_iterator
operator++(int) noexcept
{
auto tmp = *this;
++*this;
return tmp;
}
const_pointer
operator->() const noexcept
{
return const_reference{
e_->key(), e_->v_ };
}
const_reference
operator*() const noexcept
{
return {
e_->key(), e_->v_ };
}
};
//------------------------------------------------------------------------------
class object::node_type
{
element* e_ = nullptr;
storage_ptr sp_;
friend class object;
node_type(
element* e,
storage_ptr sp)
: e_(e)
, sp_(std::move(sp))
{
}
public:
using key_type = beast::string_view;
using mapped_type = json::value;
node_type() = default;
node_type(node_type const&) = delete;
~node_type()
{
if(e_)
element::destroy(e_, sp_);
}
node_type(node_type&& other)
: e_(boost::exchange(
other.e_, nullptr))
, sp_(boost::exchange(
other.sp_, nullptr))
{
}
node_type&
operator=(node_type&& other)
{
if(e_)
{
element::destroy(e_, sp_);
e_ = nullptr;
sp_ = nullptr;
}
if(other.e_)
{
e_ = boost::exchange(
other.e_, nullptr);
sp_ = std::move(other.sp_);
}
return *this;
}
storage_ptr const&
get_storage() const noexcept
{
return sp_;
}
bool
empty() const noexcept
{
return e_ == nullptr;
}
explicit
operator bool() const noexcept
{
return e_ != nullptr;
}
key_type
key() const noexcept
{
return e_->key();
}
mapped_type&
value() noexcept
{
return e_->v_;
}
mapped_type const&
value() const noexcept
{
return e_->v_;
}
};
struct object::insert_return_type
{
iterator position;
bool inserted;
node_type node;
};
//------------------------------------------------------------------------------
template<class InputIt>
object::
object(
InputIt first,
InputIt last)
: sp_(default_storage())
{
construct(first, last, 0,
iter_cat<InputIt>{});
}
template<class InputIt>
object::
object(
InputIt first,
InputIt last,
size_type capacity)
: sp_(default_storage())
{
construct(first, last, capacity,
iter_cat<InputIt>{});
}
template<class InputIt>
object::
object(
InputIt first,
InputIt last,
storage_ptr store)
: sp_(std::move(store))
{
construct(first, last, 0,
iter_cat<InputIt>{});
}
template<class InputIt>
object::
object(
InputIt first,
InputIt last,
size_type capacity,
storage_ptr store)
: sp_(std::move(store))
{
construct(first, last, capacity,
iter_cat<InputIt>{});
}
//------------------------------------------------------------------------------
template<class P, class>
auto
object::
insert(P&& p)->
std::pair<iterator, bool>
{
return insert(end(), std::forward<P>(p));
}
template<class P, class>
auto
object::
insert(const_iterator before, P&& p) ->
std::pair<iterator, bool>
{
value_type v(std::forward<P>(p));
return emplace_impl(before, v.first,
std::move(v.second));
}
template<class InputIt>
void
object::
insert(InputIt first, InputIt last)
{
insert(first, last, iter_cat<InputIt>{});
}
template<class M>
auto
object::
insert_or_assign(
key_type key, M&& obj) ->
std::pair<iterator, bool>
{
return insert_or_assign(end(), key,
std::forward<M>(obj));
}
template<class M>
auto
object::
insert_or_assign(
const_iterator before,
key_type key,
M&& obj) ->
std::pair<iterator, bool>
{
auto const hash = hasher{}(key);
auto e = prepare_insert(&before, key, hash);
if(e)
{
e->v_ = std::forward<M>(obj);
return { iterator(e), false };
}
e = element::allocate(sp_, key,
std::forward<M>(obj));
finish_insert(before, e, hash);
return { iterator(e), true, };
}
template<class Arg>
auto
object::
emplace(key_type key, Arg&& arg) ->
std::pair<iterator, bool>
{
return emplace_impl(end(), key,
std::forward<Arg>(arg));
}
template<class Arg>
auto
object::
emplace(const_iterator before,
key_type key, Arg&& arg) ->
std::pair<iterator, bool>
{
return emplace_impl(before, key,
std::forward<Arg>(arg));
}
inline
auto
object::
hash_function() const ->
hasher
{
return hasher{};
}
inline
auto
object::
key_eq() const ->
key_equal
{
return key_equal{};
}
//------------------------------------------------------------------------------
template<class InputIt>
void
object::
construct(
InputIt first,
InputIt last,
size_type capacity,
std::forward_iterator_tag)
{
reserve(std::max<size_type>(capacity,
std::distance(first, last)));
while(first != last)
{
value_type v(*first++);
emplace_impl(end(), v.first,
std::move(v.second));
}
}
template<class InputIt>
void
object::
construct(
InputIt first,
InputIt last,
size_type capacity,
std::input_iterator_tag)
{
reserve(capacity);
while(first != last)
{
value_type v(*first++);
emplace_impl(end(), v.first,
std::move(v.second));
}
}
template<class InputIt>
void
object::
insert(InputIt first, InputIt last,
std::forward_iterator_tag)
{
reserve(size() +
std::distance(first, last));
while(first != last)
{
value_type v(*first++);
emplace_impl(end(), v.first,
std::move(v.second));
}
}
template<class InputIt>
void
object::
insert(InputIt first, InputIt last,
std::input_iterator_tag)
{
while(first != last)
{
value_type v(*first++);
emplace_impl(end(), v.first,
std::move(v.second));
}
}
template<class Arg>
auto
object::
emplace_impl(
const_iterator before,
key_type key,
Arg&& arg) ->
std::pair<iterator, bool>
{
auto const hash = hasher{}(key);
auto e = prepare_insert(
&before, key, hash);
if(e)
return { iterator(e), false };
e = element::allocate(sp_, key,
std::forward<Arg>(arg));
finish_insert(before, e, hash);
return { iterator(e), true };
}
} // json
} // beast
} // boost
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,61 @@
//
// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/json
//
#ifndef BOOST_JSON_IMPL_PARSE_FILE_IPP
#define BOOST_JSON_IMPL_PARSE_FILE_IPP
#include <boost/beast/core/file.hpp>
#include <boost/beast/core/flat_buffer.hpp>
#include <boost/beast/core/detail/clamp.hpp>
namespace boost {
namespace beast {
namespace json {
void
parse_file(
char const* path,
basic_parser& parser,
error_code& ec)
{
file f;
f.open(path, beast::file_mode::scan, ec);
if(ec)
return;
flat_buffer b;
auto remain = f.size(ec);
if(ec)
return;
while(remain > 0)
{
auto amount = beast::detail::clamp(remain);
auto mb = b.prepare(amount);
b.commit(f.read(mb.data(), mb.size(), ec));
if(ec)
return;
if(remain == b.size())
break;
auto bytes_used =
parser.write_some(b.data(), ec);
if(ec)
return;
remain -= b.size();
b.consume(bytes_used);
}
parser.write(b.data(), ec);
if(ec)
return;
// finished
}
} // json
} // beast
} // boost
#endif

View File

@@ -0,0 +1,47 @@
//
// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/json
//
#ifndef BOOST_JSON_IMPL_PARSER_HPP
#define BOOST_JSON_IMPL_PARSER_HPP
namespace boost {
namespace beast {
namespace json {
template<class T>
void
parser::
assign(T&& t)
{
auto& jv = *stack_.front();
BOOST_ASSERT(! jv.is_object());
if(obj_)
{
BOOST_ASSERT(jv.is_null());
jv = std::forward<T>(t);
stack_.pop_front();
}
else if(stack_.front()->is_array())
{
BOOST_ASSERT(s_.empty());
jv.as_array().emplace_back(
std::forward<T>(t));
}
else
{
BOOST_ASSERT(jv.is_null());
jv = std::forward<T>(t);
}
}
} // json
} // beast
} // boost
#endif

View File

@@ -0,0 +1,273 @@
//
// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/json
//
#ifndef BOOST_JSON_IMPL_PARSER_IPP
#define BOOST_JSON_IMPL_PARSER_IPP
#include <boost/json/parser.hpp>
#include <boost/json/error.hpp>
#include <boost/core/ignore_unused.hpp>
#include <boost/assert.hpp>
namespace boost {
namespace beast {
namespace json {
parser::
parser()
{
}
parser::
parser(storage_ptr const& store)
: jv_(store)
{
}
value const&
parser::
get() const noexcept
{
return jv_;
}
value
parser::
release() noexcept
{
return std::move(jv_);
}
void
parser::
on_document_begin(error_code&)
{
stack_.clear();
stack_.push_front(&jv_);
s_.clear();
obj_ = false;
}
void
parser::
on_object_begin(error_code& ec)
{
if(stack_.size() >= max_depth_)
{
ec = error::too_deep;
return;
}
auto& jv = *stack_.front();
BOOST_ASSERT(! jv.is_object());
if(obj_)
{
BOOST_ASSERT(jv.is_null());
jv.emplace_object();
}
else if(jv.is_array())
{
jv.as_array().emplace_back(
kind::object);
stack_.push_front(
&jv.as_array().back());
}
else
{
BOOST_ASSERT(jv.is_null());
jv = kind::object;
}
obj_ = true;
}
void
parser::
on_object_end(error_code&)
{
BOOST_ASSERT(
stack_.front()->is_object());
stack_.pop_front();
if(! stack_.empty())
{
auto const& jv = stack_.front();
BOOST_ASSERT(
jv->is_array() || jv->is_object());
obj_ = jv->is_object();
}
}
void
parser::
on_array_begin(error_code& ec)
{
if(stack_.size() >= max_depth_)
{
ec = error::too_deep;
return;
}
auto& jv = *stack_.front();
BOOST_ASSERT(! jv.is_object());
if(obj_)
{
BOOST_ASSERT(jv.is_null());
jv.emplace_array();
}
else if(jv.is_array())
{
BOOST_ASSERT(s_.empty());
jv.as_array().emplace_back(
kind::array);
stack_.push_front(
&jv.as_array().back());
}
else
{
BOOST_ASSERT(jv.is_null());
jv = kind::array;
}
obj_ = false;
}
void
parser::
on_array_end(error_code&)
{
BOOST_ASSERT(
stack_.front()->is_array());
stack_.pop_front();
if(! stack_.empty())
{
auto const& jv = stack_.front();
BOOST_ASSERT(
jv->is_array() || jv->is_object());
obj_ = jv->is_object();
}
}
void
parser::
on_key_data(
string_view s,
error_code&)
{
s_.append(s.data(), s.size());
}
void
parser::
on_key_end(
string_view s,
error_code&)
{
auto& jv = *stack_.front();
if(! s_.empty())
{
s_.append(s.data(), s.size());
s = {s_.data(), s_.size()};
}
if(jv.is_object())
{
stack_.push_front(
&jv.as_object().emplace(s,
kind::null).first->second);
}
else if(stack_.front()->is_array())
{
BOOST_ASSERT(s_.empty());
jv.as_array().emplace_back(kind::null);
}
else
{
BOOST_ASSERT(jv.is_null());
// nothing to do
}
s_.clear();
}
void
parser::
on_string_data(
string_view s, error_code&)
{
auto& jv = *stack_.front();
BOOST_ASSERT(! jv.is_object());
if(! jv.is_string())
{
if(obj_)
{
BOOST_ASSERT(jv.is_null());
jv.emplace_string().append(
s.data(), s.size());
}
else if(stack_.front()->is_array())
{
BOOST_ASSERT(s_.empty());
jv.as_array().emplace_back(kind::string);
stack_.push_front(
&jv.as_array().back());
stack_.front()->as_string().append(
s.data(), s.size());
}
else
{
BOOST_ASSERT(jv.is_null());
jv.emplace_string().append(
s.data(), s.size());
}
}
else
{
stack_.front()->as_string().append(
s.data(), s.size());
}
}
void
parser::
on_string_end(
string_view s,
error_code& ec)
{
on_string_data(s, ec);
BOOST_ASSERT(stack_.front()->is_string());
stack_.pop_front();
if(! stack_.empty())
{
auto const& jv = stack_.front();
BOOST_ASSERT(
jv->is_array() || jv->is_object());
obj_ = jv->is_object();
}
}
void
parser::
on_number(number n, error_code&)
{
assign(n);
}
void
parser::
on_bool(bool b, error_code&)
{
assign(b);
}
void
parser::
on_null(error_code&)
{
assign(null);
}
} // json
} // beast
} // boost
#endif

View File

@@ -0,0 +1,260 @@
//
// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/json
//
#ifndef BOOST_JSON_IMPL_SERIALIZER_IPP
#define BOOST_JSON_IMPL_SERIALIZER_IPP
#include <boost/json/serializer.hpp>
namespace boost {
namespace beast {
namespace json {
serializer::
impl::
impl(value const& jv)
: jv_(jv)
, it_(jv)
{
}
bool
serializer::
impl::
is_done() const noexcept
{
return state_ == state::done;
}
std::size_t
serializer::
impl::
next(net::mutable_buffer b)
{
auto const p0 =
reinterpret_cast<char*>(b.data());
auto p = p0;
auto n = b.size();
while(n > 0)
{
switch(state_)
{
case state::next:
++it_;
if(it_ == end)
{
state_ = state::done;
break;
}
BOOST_FALLTHROUGH;
case state::init:
str_ = it_->key;
if(! str_.empty())
{
*p++ = '\"';
--n;
state_ = state::key;
}
else
{
state_ = state::value;
}
break;
case state::key:
case state::string:
// Write escaped/UTF-8 string
if(n >= str_.size())
{
std::memcpy(p,
str_.data(), str_.size());
p += str_.size();
n -= str_.size();
if(state_ == state::string)
{
if(last_)
str_ = {"\"", 1};
else
str_ = {"\",", 2};
state_ = state::literal;
}
else
{
str_ = {"\":", 2};
state_ = state::key_literal;
}
break;
}
else
{
std::memcpy(p,
str_.data(), n);
p += n;
str_ = {
str_.data() + n,
str_.size() - n};
n = 0;
}
break;
case state::literal:
case state::key_literal:
// Copy content of str_ without escapes
if(n >= str_.size())
{
std::memcpy(p,
str_.data(), str_.size());
p += str_.size();
n -= str_.size();
if(state_ == state::literal)
state_ = state::next;
else
state_ = state::value;
}
else
{
std::memcpy(p,
str_.data(), n);
p += n;
str_ = {
str_.data() + n,
str_.size() - n};
n = 0;
}
break;
case state::value:
{
auto const& e = *it_;
if(! e.end)
{
switch(e.value.kind())
{
case kind::object:
*p++ = '{';
--n;
state_ = state::next;
break;
case kind::array:
*p++ = '[';
--n;
state_ = state::next;
break;
case kind::string:
*p++ = '\"';
str_ = e.value.as_string();
last_ = e.last;
state_ = state::string;
break;
case kind::number:
str_ = e.value.as_number().print(
buf_, sizeof(buf_));
if(! e.last)
{
buf_[str_.size()] = ',';
str_ = {buf_, str_.size() + 1};
}
state_ = state::literal;
break;
case kind::boolean:
if(e.value.as_bool())
{
if(! e.last)
str_ = {"true,", 5};
else
str_ = {"true", 4};
}
else
{
if(! e.last)
str_ = {"false,", 6};
else
str_ = {"false", 5};
}
state_ = state::literal;
break;
case kind::null:
if(! e.last)
str_ = {"null,", 5};
else
str_ = {"null", 4};
state_ = state::literal;
break;
}
}
else if(e->value.is_object())
{
if(! e.last)
str_ = {"},", 2};
else
str_ = {"}", 1};
state_ = state::literal;
}
else if(e->value.is_array())
{
if(! e.last)
str_ = {"],", 2};
else
str_ = {"]", 1};
state_ = state::literal;
}
break;
}
case state::done:
goto finish;
}
}
finish:
return p - p0;
}
void
serializer::
impl::
append(char c,
net::mutable_buffer& b)
{
BOOST_ASSERT(b.size() >= 1);
*reinterpret_cast<char*>(b.data()) = c;
b += 1;
}
void
serializer::
impl::
append(
char const* s, std::size_t n,
net::mutable_buffer& b)
{
BOOST_ASSERT(b.size() >= n);
std::memcpy(b.data(), s, n);
b += n;
}
//------------------------------------------------------------------------------
serializer::
~serializer()
{
get_base().~base();
}
serializer::
serializer(value const& jv)
{
::new(&get_base()) impl(jv);
}
} // json
} // beast
} // boost
#endif

View File

@@ -0,0 +1,31 @@
//
// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/json
//
#ifndef BOOST_JSON_IMPL_STORAGE_HPP
#define BOOST_JSON_IMPL_STORAGE_HPP
#include <boost/json/detail/storage_adaptor.hpp>
namespace boost {
namespace beast {
namespace json {
template<class Allocator>
storage_ptr
make_storage_ptr(Allocator const& a)
{
return storage_ptr(
new detail::storage_adaptor<Allocator>(a));
}
} // json
} // beast
} // boost
#endif

View File

@@ -0,0 +1,113 @@
//
// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/json
//
#ifndef BOOST_JSON_IMPL_STORAGE_IPP
#define BOOST_JSON_IMPL_STORAGE_IPP
#include <boost/json/storage.hpp>
#include <boost/json/detail/storage_adaptor.hpp>
#include <boost/core/exchange.hpp>
#include <boost/assert.hpp>
#include <memory>
namespace boost {
namespace beast {
namespace json {
storage_ptr::
~storage_ptr()
{
if(p_)
p_->release();
}
storage_ptr::
storage_ptr(storage_ptr&& other) noexcept
: p_(boost::exchange(other.p_, nullptr))
{
}
storage_ptr::
storage_ptr(storage_ptr const& other) noexcept
: p_(other.p_)
{
if(p_)
p_->addref();
}
storage_ptr&
storage_ptr::
operator=(storage_ptr&& other) noexcept
{
BOOST_ASSERT(this != &other);
if(p_)
p_->release();
p_ = boost::exchange(other.p_, nullptr);
return *this;
}
storage_ptr&
storage_ptr::
operator=(storage_ptr const& other) noexcept
{
if(other.p_)
other.p_->addref();
if(p_)
p_->release();
p_ = other.p_;
return *this;
}
storage_ptr::
storage_ptr(storage* p) noexcept
: p_(p)
{
}
storage*
storage_ptr::
release() noexcept
{
return boost::exchange(p_, nullptr);
}
//------------------------------------------------------------------------------
namespace detail {
inline
storage_ptr&
raw_default_storage() noexcept
{
static storage_ptr sp =
make_storage_ptr(
std::allocator<void>{});
return sp;
}
} // detail
storage_ptr
default_storage()
{
return detail::raw_default_storage();
}
void
default_storage(storage_ptr sp)
{
detail::raw_default_storage() = std::move(sp);
}
} // json
} // beast
} // boost
#endif

View File

@@ -0,0 +1,574 @@
//
// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/json
//
#ifndef BOOST_JSON_IMPL_VALUE_HPP
#define BOOST_JSON_IMPL_VALUE_HPP
#include <boost/json/error.hpp>
#include <boost/throw_exception.hpp>
#include <limits>
#include <type_traits>
namespace boost {
namespace beast {
namespace json {
//------------------------------------------------------------------------------
class value::pointer
{
reference t_;
public:
pointer(reference t)
: t_(t)
{
}
reference*
operator->() noexcept
{
return &t_;
}
};
//------------------------------------------------------------------------------
class value::const_pointer
{
const_reference t_;
public:
const_pointer(
const_reference t)
: t_(t)
{
}
const_reference*
operator->() noexcept
{
return &t_;
}
};
//------------------------------------------------------------------------------
class value::iterator
{
union
{
array::iterator arr_it_;
object::iterator obj_it_;
};
bool arr_;
friend class value;
public:
using value_type = value::value_type;
using pointer = value::pointer;
using reference = value::reference;
using difference_type = std::ptrdiff_t;
using iterator_category =
std::bidirectional_iterator_tag;
~iterator()
{
if(! arr_)
obj_it_.~iterator();
}
iterator() noexcept
: arr_it_{}
, arr_(true)
{
}
iterator(iterator const& other) noexcept
: arr_(other.arr_)
{
if(arr_)
arr_it_ = other.arr_it_;
else
::new(&obj_it_)
object::iterator(other.obj_it_);
}
iterator(object::iterator it)
: obj_it_(it)
, arr_(false)
{
}
iterator(array::iterator it)
: arr_it_(it)
, arr_(true)
{
}
iterator&
operator=(iterator const& other) noexcept
{
if(! arr_)
obj_it_.~iterator();
arr_ = other.arr_;
if(arr_)
arr_it_ = other.arr_it_;
else
::new(&obj_it_)
object::iterator(other.obj_it_);
return *this;
}
bool
operator==(
iterator const& other) const noexcept
{
if(arr_ != other.arr_)
return false;
if(arr_)
return arr_it_ == other.arr_it_;
return obj_it_ == other.obj_it_;
}
bool
operator!=(
iterator const& other) const noexcept
{
return ! (*this == other);
}
bool
operator==(
const_iterator const& other) const noexcept;
bool
operator!=(
const_iterator const& other) const noexcept;
iterator&
operator++() noexcept
{
if(arr_)
++arr_it_;
else
++obj_it_;
return *this;
}
iterator
operator++(int) noexcept
{
auto tmp = *this;
++*this;
return tmp;
}
iterator&
operator--() noexcept
{
if(arr_)
--arr_it_;
else
--obj_it_;
return *this;
}
iterator
operator--(int) noexcept
{
auto tmp = *this;
--*this;
return tmp;
}
reference
operator*() const noexcept
{
if(arr_)
return reference{
"", *arr_it_ };
return reference{
obj_it_->first,
obj_it_->second };
}
pointer
operator->() const noexcept
{
return *(*this);
}
};
//------------------------------------------------------------------------------
class value::const_iterator
{
union
{
array::const_iterator arr_it_;
object::const_iterator obj_it_;
};
bool arr_;
friend class value;
public:
using value_type = value::value_type;
using pointer = value::const_pointer;
using reference = value::const_reference;
using difference_type = std::ptrdiff_t;
using iterator_category =
std::bidirectional_iterator_tag;
~const_iterator()
{
if(! arr_)
obj_it_.~const_iterator();
}
const_iterator() noexcept
: arr_it_{}
, arr_(true)
{
}
const_iterator(
const_iterator const& other) noexcept
: arr_(other.arr_)
{
if(arr_)
arr_it_ = other.arr_it_;
else
::new(&obj_it_)
object::const_iterator(
other.obj_it_);
}
const_iterator(
object::const_iterator it)
: obj_it_(it)
, arr_(false)
{
}
const_iterator(
array::const_iterator it)
: arr_it_(it)
, arr_(true)
{
}
const_iterator&
operator=(const_iterator const& other) noexcept
{
if(! arr_)
obj_it_.~const_iterator();
arr_ = other.arr_;
if(arr_)
arr_it_ = other.arr_it_;
else
::new(&obj_it_)
object::const_iterator(
other.obj_it_);
return *this;
}
bool
operator==(
const_iterator const& other) const noexcept
{
if(arr_ != other.arr_)
return false;
if(arr_)
return arr_it_ == other.arr_it_;
return obj_it_ == other.obj_it_;
}
bool
operator!=(
const_iterator const& other) const noexcept
{
return ! (*this == other);
}
bool
operator==(
iterator const& other) const noexcept;
bool
operator!=(
iterator const& other) const noexcept;
const_iterator&
operator++() noexcept
{
if(arr_)
++arr_it_;
else
++obj_it_;
return *this;
}
const_iterator
operator++(int) noexcept
{
auto tmp = *this;
++*this;
return tmp;
}
const_iterator&
operator--() noexcept
{
if(arr_)
--arr_it_;
else
--obj_it_;
return *this;
}
const_iterator
operator--(int) noexcept
{
auto tmp = *this;
--*this;
return tmp;
}
reference
operator*() const noexcept
{
if(arr_)
return reference{
"", *arr_it_ };
return reference{
obj_it_->first,
obj_it_->second };
}
pointer
operator->() const noexcept
{
return *(*this);
}
};
//------------------------------------------------------------------------------
template<class M>
auto
value::
insert_or_assign(
key_type key, M&& obj) ->
std::pair<iterator, bool>
{
BOOST_ASSERT(is_object());
return obj_.insert_or_assign(
key, std::forward<M>(obj));
}
template<class M>
auto
value::
insert_or_assign(
const_iterator before,
key_type key,
M&& obj) ->
std::pair<iterator, bool>
{
BOOST_ASSERT(is_object());
BOOST_ASSERT(! before.arr_);
return obj_.insert_or_assign(
before.obj_it_, key,
std::forward<M>(obj));
}
template<class Arg>
auto
value::
emplace(key_type key, Arg&& arg) ->
std::pair<iterator, bool>
{
BOOST_ASSERT(is_object());
return obj_.emplace(key,
std::forward<Arg>(arg));
}
template<class Arg>
auto
value::
emplace(
const_iterator before,
key_type key, Arg&& arg) ->
std::pair<iterator, bool>
{
BOOST_ASSERT(is_object());
BOOST_ASSERT(! before.arr_);
return obj_.emplace(
key, before.obj_it_,
std::forward<Arg>(arg));
}
template<class Arg>
auto
value::
emplace(
const_iterator before,
Arg&& arg) ->
iterator
{
BOOST_ASSERT(is_array());
BOOST_ASSERT(before.arr_);
return arr_.emplace(before.arr_it_,
std::forward<Arg>(arg));
}
template<class Arg>
value&
value::
emplace_back(Arg&& arg)
{
BOOST_ASSERT(is_array());
return *arr_.emplace(arr_.end(),
std::forward<Arg>(arg));
}
//------------------------------------------------------------------------------
namespace detail {
template<class T, class = void>
struct is_range : std::false_type
{
};
template<class T>
struct is_range<T, boost::void_t<
typename T::value_type,
decltype(
std::declval<T const&>().begin(),
std::declval<T const&>().end()
)>> : std::true_type
{
};
} // detail
//------------------------------------------------------------------------------
//
// assign to value
//
// range
template<class T
,class = typename std::enable_if<
detail::is_range<T>::value
&& ! std::is_same<typename T::value_type, char>::value
&& has_to_json<typename T::value_type>::value
>::type
>
void
to_json(T const& t, value& v)
{
v.reset(json::kind::array);
for(auto const& e : t)
v.as_array().push_back(e);
}
// string
inline
void
to_json(string_view t, value& v)
{
v.emplace_string().assign(
t.data(), t.size());
}
// string
inline
void
to_json(char const* t, value& v)
{
v.emplace_string() = t;
}
// number
template<class T
,class = typename std::enable_if<
std::is_constructible<number, T>::value &&
! std::is_same<number, T>::value>::type
>
inline
void
to_json(T t, value& v)
{
v.emplace_number() = t;
}
// bool
inline
void
to_json(bool b, value& v)
{
v.emplace_bool() = b;
}
// null
inline
void
to_json(std::nullptr_t, value& v)
{
v.emplace_null();
}
//------------------------------------------------------------------------------
//
// assign value to
//
// integer
template<typename T
,class = typename std::enable_if<
std::is_integral<T>::value>::type
>
void
from_json(T& t, value const& v)
{
if(v.is_int64())
{
auto const rhs = v.get_int64();
if( rhs > (std::numeric_limits<T>::max)() ||
rhs < (std::numeric_limits<T>::min)())
throw system_error(
error::integer_overflow);
t = static_cast<T>(rhs);
}
else if(v.is_uint64())
{
auto const rhs = v.get_uint64();
if(rhs > (std::numeric_limits<T>::max)())
throw system_error(
error::integer_overflow);
t = static_cast<T>(rhs);
}
else
{
throw system_error(
error::expected_number);
}
}
} // json
} // beast
} // boost
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,149 @@
//
// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/json
//
#ifndef BOOST_JSON_ITERATOR_HPP
#define BOOST_JSON_ITERATOR_HPP
#include <boost/beast/core/detail/config.hpp>
#include <boost/beast/core/detail/static_const.hpp>
#include <boost/json/value.hpp>
#include <boost/json/detail/stack.hpp>
#include <iterator>
#include <new>
namespace boost {
namespace beast {
namespace json {
struct end_t
{
};
BOOST_BEAST_INLINE_VARIABLE(end, end_t)
/** A generator to perform a depth-first traversal of a JSON value.
*/
class const_iterator
{
struct node
{
union
{
array::const_iterator arr_it;
object::const_iterator obj_it;
};
value const* v;
string_view key;
bool it;
BOOST_BEAST_DECL
~node();
BOOST_BEAST_DECL
node(
value const& v_,
bool it_) noexcept;
BOOST_BEAST_DECL
node(node const& other) noexcept;
BOOST_BEAST_DECL
bool
last() const noexcept;
};
detail::stack<node, 50> stack_;
public:
struct value_type
{
std::size_t depth;
string_view key;
json::value const& value;
bool last;
bool end;
value_type const*
operator->() const noexcept
{
return this;
}
};
BOOST_BEAST_DECL
explicit
const_iterator(
value const& jv);
BOOST_BEAST_DECL
value_type
operator*() const noexcept;
BOOST_BEAST_DECL
const_iterator&
operator++() noexcept;
void
operator++(int) noexcept
{
++*this;
}
value_type
operator->() const noexcept
{
return *(*this);
}
friend
bool
operator==(
const_iterator const& lhs,
end_t) noexcept
{
return lhs.stack_.empty();
}
friend
bool
operator==(
end_t,
const_iterator const& rhs) noexcept
{
return rhs.stack_.empty();
}
friend
bool
operator!=(
const_iterator const& lhs,
end_t) noexcept
{
return ! lhs.stack_.empty();
}
friend
bool
operator!=(
end_t,
const_iterator const& rhs) noexcept
{
return ! rhs.stack_.empty();
}
};
} // json
} // beast
} // boost
#if BOOST_BEAST_HEADER_ONLY
#include <boost/json/impl/iterator.ipp>
#endif
#endif

View File

@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<Type Name="boost::beast::json::value">
<DisplayString Condition="kind_==kind::object">object{obj_}</DisplayString>
<DisplayString Condition="kind_==kind::array">array{arr_}</DisplayString>
<DisplayString Condition="kind_==kind::string">string{str_}</DisplayString>
<DisplayString Condition="kind_==kind::number">{nat_.num_}</DisplayString>
<DisplayString Condition="kind_==kind::boolean">{nat_.bool_}</DisplayString>
<DisplayString Condition="kind_==kind::null">null</DisplayString>
<Expand>
<ExpandedItem Condition="kind_==kind::object">obj_</ExpandedItem>
<ExpandedItem Condition="kind_==kind::array">arr_</ExpandedItem>
<ExpandedItem Condition="kind_==kind::string">str_</ExpandedItem>
<Item Name="storage" Condition="kind_==kind::number||kind_==kind::boolean||kind_==kind::null">nat_.sp_</Item>
<ExpandedItem Condition="kind_==kind::number">nat_.num_</ExpandedItem>
<ExpandedItem Condition="kind_==kind::boolean">nat_.bool_</ExpandedItem>
</Expand>
</Type>
<!--
<Type Name="boost::beast::json::storage_ptr">
<DisplayString>storage</DisplayString>
<Expand>
<ExpandedItem>p_</ExpandedItem>
</Expand>
</Type>
<Type Name="boost::beast::json::allocator&lt;*&gt;">
<DisplayString>allocator</DisplayString>
<Expand>
<ExpandedItem>sp_</ExpandedItem>
</Expand>
</Type>
-->
<Type Name="std::pair&lt;const std::string, boost::beast::json::value&gt;">
<Expand>
<ExpandedItem>second</ExpandedItem>
</Expand>
</Type>
</AutoVisualizer>

View File

@@ -0,0 +1,37 @@
//
// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/json
//
#ifndef BOOST_JSON_KIND_HPP
#define BOOST_JSON_KIND_HPP
#include <boost/beast/core/detail/config.hpp>
#include <boost/beast/core/detail/static_const.hpp>
#include <cstddef>
namespace boost {
namespace beast {
namespace json {
enum class kind
{
object,
array,
string,
number,
boolean,
null
};
BOOST_BEAST_INLINE_VARIABLE(null, std::nullptr_t)
} // json
} // beast
} // boost
#endif

View File

@@ -0,0 +1,237 @@
//
// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/json
//
#ifndef BOOST_JSON_NUMBER_HPP
#define BOOST_JSON_NUMBER_HPP
#include <boost/beast/core/detail/config.hpp>
#include <boost/beast/core/string.hpp>
#include <cstdint>
#include <iosfwd>
#include <type_traits>
namespace boost {
namespace beast {
namespace json {
/** The representation of parsed numbers.
*/
class number
{
struct base10_ieee
{
unsigned
long long mant;
short exp;
bool sign;
};
enum kind
{
type_int64,
type_uint64,
type_double,
type_ieee
};
union
{
unsigned
long long uint64_;
long long int64_;
double double_;
base10_ieee ieee_;
};
kind k_;
public:
static std::size_t constexpr
max_string_chars =
1 + // '-'
19 + // unsigned 64-bit mantissa
1 + // 'e'
1 + // '-'
5; // unsigned 16-bit exponent
using mantissa_type =
unsigned long long;
using exponent_type =
short;
number() = default;
number(number const&) = default;
number& operator=(
number const&) = default;
/** Construct a number from mantissa, exponent, and sign
*/
BOOST_BEAST_DECL
number(
mantissa_type mant,
exponent_type exp,
bool sign) noexcept;
/// Construct a number from a signed integer
BOOST_BEAST_DECL
number(short v) noexcept;
/// Construct a number from a signed integer
BOOST_BEAST_DECL
number(int v) noexcept;
/// Construct a number from a signed integer
BOOST_BEAST_DECL
number(long v) noexcept;
/// Construct a number from a signed integer
BOOST_BEAST_DECL
number(long long v) noexcept;
/// Construct a number from an unsigned integer
BOOST_BEAST_DECL
number(unsigned short v) noexcept;
/// Construct a number from an unsigned integer
BOOST_BEAST_DECL
number(unsigned int v) noexcept;
/// Construct a number from an unsigned integer
BOOST_BEAST_DECL
number(unsigned long v) noexcept;
/// Construct a number from an unsigned integer
BOOST_BEAST_DECL
number(unsigned long long v) noexcept;
/// Construct a number from a floating point value
BOOST_BEAST_DECL
number(float v) noexcept;
/// Construct a number from a floating point value
BOOST_BEAST_DECL
number(double v) noexcept;
/// Return true if the number is negative
BOOST_BEAST_DECL
bool
is_negative() const noexcept;
/// Return true if the number is integral
BOOST_BEAST_DECL
bool
is_integral() const noexcept;
/// Return true if the number can be represented with a signed 64-bit integer
BOOST_BEAST_DECL
bool
is_int64() const noexcept;
/// Return true if the number can be represented with an unsigned 64-bit integer
BOOST_BEAST_DECL
bool
is_uint64() const noexcept;
/** Return the number as a signed 64-bit integer
The return value is undefined unless @ref is_int64 returns `true`.
*/
BOOST_BEAST_DECL
std::int_least64_t
get_int64() const noexcept;
/** Return the number as an unsigned 64-bit integer
The return value is undefined unless @ref is_uint64 returns `true`.
*/
BOOST_BEAST_DECL
std::uint_least64_t
get_uint64() const noexcept;
/** Return the number as floating point
*/
BOOST_BEAST_DECL
double
get_double() const noexcept;
/** Convert the number to a string.
The destination must contain at least
@ref max_string_chars bytes of valid storage.
@return A string view representing the number as
as string. Storage for the view comes from `dest`.
*/
BOOST_BEAST_DECL
string_view
print(
char* buf,
std::size_t buf_size) const noexcept;
private:
struct pow10;
BOOST_BEAST_DECL
void
assign_signed(
long long i) noexcept;
BOOST_BEAST_DECL
void
assign_unsigned(
unsigned long long i) noexcept;
BOOST_BEAST_DECL
void
assign_double(double f) noexcept;
friend
std::ostream&
operator<<(std::ostream& os, number const& n);
friend
bool
operator==(
number const& lhs,
number const& rhs) noexcept;
friend
bool
operator!=(
number const& lhs,
number const& rhs) noexcept;
};
BOOST_BEAST_DECL
bool
operator==(
number const& lhs,
number const& rhs) noexcept;
BOOST_BEAST_DECL
bool
operator!=(
number const& lhs,
number const& rhs) noexcept;
BOOST_BEAST_DECL
std::ostream&
operator<<(std::ostream& os, number const& n);
} // json
} // beast
} // boost
#ifdef BOOST_BEAST_HEADER_ONLY
#include <boost/json/impl/number.ipp>
#endif
#endif

View File

@@ -0,0 +1,560 @@
//
// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/json
//
#ifndef BOOST_JSON_OBJECT_HPP
#define BOOST_JSON_OBJECT_HPP
#include <boost/beast/core/detail/config.hpp>
#include <boost/beast/core/string.hpp>
#include <boost/json/storage.hpp>
#include <cstdlib>
#include <initializer_list>
#include <iterator>
#include <utility>
namespace boost {
namespace beast {
namespace json {
class value;
//------------------------------------------------------------------------------
/** The native type of object values
This copies the interface of `std::unordered_map` with
one important distinction: the order of insertions is
preserved.
*/
class object
{
struct list_hook;
struct element;
class table;
storage_ptr sp_;
table* tab_ = nullptr;
float mf_ = 1.0;
public:
using key_type = beast::string_view;
using mapped_type = value;
using value_type = std::pair<key_type, value>;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
using reference = std::pair<key_type, value&>;
using const_reference = std::pair<key_type, value const&>;
class hasher;
class key_equal;
class pointer;
class const_pointer;
class iterator;
class const_iterator;
class local_iterator;
class const_local_iterator;
class node_type;
struct insert_return_type;
//--------------------------------------------------------------------------
//
// Special Members
//
//--------------------------------------------------------------------------
BOOST_BEAST_DECL
~object();
BOOST_BEAST_DECL
object();
BOOST_BEAST_DECL
object(
size_type capacity);
BOOST_BEAST_DECL
object(
storage_ptr store);
BOOST_BEAST_DECL
object(
size_type capacity,
storage_ptr store);
template<class InputIt>
BOOST_BEAST_DECL
object(
InputIt first,
InputIt last);
template<class InputIt>
BOOST_BEAST_DECL
object(
InputIt first,
InputIt last,
size_type capacity);
template<class InputIt>
BOOST_BEAST_DECL
object(
InputIt first,
InputIt last,
storage_ptr store);
template<class InputIt>
BOOST_BEAST_DECL
object(
InputIt first,
InputIt last,
size_type capacity,
storage_ptr store);
BOOST_BEAST_DECL
object(object&& other) noexcept;
BOOST_BEAST_DECL
object(
object&& other,
storage_ptr store) noexcept;
BOOST_BEAST_DECL
object(
object const& other);
BOOST_BEAST_DECL
object(
object const& other,
storage_ptr store);
BOOST_BEAST_DECL
object(
std::initializer_list<value_type> list);
BOOST_BEAST_DECL
object(
std::initializer_list<value_type> list,
size_type capacity);
BOOST_BEAST_DECL
object(
std::initializer_list<value_type> list,
storage_ptr store);
BOOST_BEAST_DECL
object(
std::initializer_list<value_type> list,
size_type capacity,
storage_ptr store);
BOOST_BEAST_DECL
object&
operator=(object&& other);
BOOST_BEAST_DECL
object&
operator=(object const& other);
BOOST_BEAST_DECL
object&
operator=(
std::initializer_list<value_type> list);
BOOST_BEAST_DECL
storage_ptr const&
get_storage() const noexcept;
//--------------------------------------------------------------------------
//
// Iterators
//
//--------------------------------------------------------------------------
BOOST_BEAST_DECL
iterator
begin() noexcept;
BOOST_BEAST_DECL
const_iterator
begin() const noexcept;
BOOST_BEAST_DECL
const_iterator
cbegin() const noexcept;
BOOST_BEAST_DECL
iterator
end() noexcept;
BOOST_BEAST_DECL
const_iterator
end() const noexcept;
BOOST_BEAST_DECL
const_iterator
cend() const noexcept;
//--------------------------------------------------------------------------
//
// Capacity
//
//--------------------------------------------------------------------------
BOOST_BEAST_DECL
bool
empty() const noexcept;
BOOST_BEAST_DECL
size_type
size() const noexcept;
BOOST_BEAST_DECL
size_type
max_size() const noexcept;
//--------------------------------------------------------------------------
//
// Modifiers
//
//--------------------------------------------------------------------------
BOOST_BEAST_DECL
void
clear() noexcept;
template<class P = value_type
#ifndef BOOST_BEAST_DOXYGEN
,class = typename std::enable_if<
std::is_constructible<value_type,
P&&>::value>::type
#endif
>
std::pair<iterator, bool>
insert(P&& p);
template<class P = value_type
#ifndef BOOST_BEAST_DOXYGEN
,class = typename std::enable_if<
std::is_constructible<value_type,
P&&>::value>::type
#endif
>
std::pair<iterator, bool>
insert(
const_iterator before,
P&& p);
template<class InputIt>
void
insert(InputIt first, InputIt last);
BOOST_BEAST_DECL
void
insert(std::initializer_list<
value_type> list);
BOOST_BEAST_DECL
insert_return_type
insert(node_type&& nh);
BOOST_BEAST_DECL
insert_return_type
insert(
const_iterator before,
node_type&& nh);
template<class M>
std::pair<iterator, bool>
insert_or_assign(
key_type key, M&& obj);
template<class M>
std::pair<iterator, bool>
insert_or_assign(
const_iterator before,
key_type key,
M&& obj);
template<class Arg>
std::pair<iterator, bool>
emplace(key_type key, Arg&& arg);
template<class Arg>
std::pair<iterator, bool>
emplace(
const_iterator before,
key_type key, Arg&& arg);
BOOST_BEAST_DECL
iterator
erase(const_iterator pos);
BOOST_BEAST_DECL
iterator
erase(
const_iterator first,
const_iterator last);
BOOST_BEAST_DECL
size_type
erase(key_type key);
BOOST_BEAST_DECL
void
swap(object& other) noexcept;
BOOST_BEAST_DECL
node_type
extract(const_iterator pos);
BOOST_BEAST_DECL
node_type
extract(key_type key);
BOOST_BEAST_DECL
void
merge(object& source);
BOOST_BEAST_DECL
void
merge(object&& source);
//--------------------------------------------------------------------------
//
// Lookup
//
//--------------------------------------------------------------------------
BOOST_BEAST_DECL
value&
at(key_type key);
BOOST_BEAST_DECL
value const&
at(key_type key) const;
BOOST_BEAST_DECL
value&
operator[](key_type key);
BOOST_BEAST_DECL
value const&
operator[](key_type key) const;
BOOST_BEAST_DECL
size_type
count(key_type key) const;
BOOST_BEAST_DECL
size_type
count(
key_type key,
std::size_t hash) const;
BOOST_BEAST_DECL
iterator
find(key_type key);
BOOST_BEAST_DECL
iterator
find(
key_type key,
std::size_t hash);
BOOST_BEAST_DECL
const_iterator
find(key_type key) const;
BOOST_BEAST_DECL
const_iterator
find(
key_type key,
std::size_t hash) const;
BOOST_BEAST_DECL
bool
contains(key_type key) const;
BOOST_BEAST_DECL
bool
contains(
key_type key,
std::size_t hash ) const;
//--------------------------------------------------------------------------
//
// Bucket Interface
//
//--------------------------------------------------------------------------
BOOST_BEAST_DECL
local_iterator
begin(size_type n) noexcept;
BOOST_BEAST_DECL
const_local_iterator
begin(size_type n) const noexcept;
BOOST_BEAST_DECL
const_local_iterator
cbegin(size_type n) noexcept;
BOOST_BEAST_DECL
local_iterator
end(size_type n) noexcept;
BOOST_BEAST_DECL
const_local_iterator
end(size_type n) const noexcept;
BOOST_BEAST_DECL
const_local_iterator
cend(size_type n) noexcept;
BOOST_BEAST_DECL
size_type
bucket_count() const noexcept;
BOOST_BEAST_DECL
size_type
max_bucket_count() const noexcept;
BOOST_BEAST_DECL
size_type
bucket_size(size_type n) const noexcept;
BOOST_BEAST_DECL
size_type
bucket(key_type key) const noexcept;
//--------------------------------------------------------------------------
//
// Hash Policy
//
//--------------------------------------------------------------------------
BOOST_BEAST_DECL
float
load_factor() const noexcept;
BOOST_BEAST_DECL
float
max_load_factor() const;
BOOST_BEAST_DECL
void
max_load_factor(float ml);
BOOST_BEAST_DECL
void
rehash(size_type count);
BOOST_BEAST_DECL
void
reserve(size_type count);
//--------------------------------------------------------------------------
//
// Observers
//
//--------------------------------------------------------------------------
BOOST_BEAST_DECL
hasher
hash_function() const;
BOOST_BEAST_DECL
key_equal
key_eq() const;
private:
struct cleanup_replace;
template<class It>
using iter_cat = typename
std::iterator_traits<It>::iterator_category;
template<class InputIt>
void
construct(
InputIt first,
InputIt last,
size_type capacity,
std::forward_iterator_tag);
template<class InputIt>
void
construct(
InputIt first,
InputIt last,
size_type capacity,
std::input_iterator_tag);
template<class InputIt>
void
insert(
InputIt first,
InputIt last,
std::forward_iterator_tag);
template<class InputIt>
void
insert(
InputIt first,
InputIt last,
std::input_iterator_tag);
template<class Arg>
std::pair<iterator, bool>
emplace_impl(
const_iterator before,
key_type key,
Arg&& arg);
BOOST_BEAST_DECL
static
size_type
constrain_hash(
std::size_t hash,
size_type bucket_count) noexcept;
BOOST_BEAST_DECL
element*
find_element(
key_type key,
std::size_t hash) const noexcept;
BOOST_BEAST_DECL
element*
prepare_insert(
const_iterator* before,
key_type key,
std::size_t hash);
BOOST_BEAST_DECL
void
finish_insert(
const_iterator before,
element* e,
std::size_t hash);
BOOST_BEAST_DECL
void
remove(element* e);
};
} // json
} // beast
} // boost
// Must be included here for this file to stand alone
#include <boost/json/value.hpp>
// headers for this file are at the bottom of value.hpp
#endif

View File

@@ -0,0 +1,38 @@
//
// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/json
//
#ifndef BOOST_JSON_PARSE_FILE_HPP
#define BOOST_JSON_PARSE_FILE_HPP
#include <boost/beast/core/detail/config.hpp>
#include <boost/json/basic_parser.hpp>
#include <boost/beast/core/error.hpp>
namespace boost {
namespace beast {
namespace json {
/** Parse the contents of a file as JSON.
*/
BOOST_BEAST_DECL
void
parse_file(
char const* path,
basic_parser& parser,
error_code& ec);
} // json
} // beast
} // boost
#ifdef BOOST_BEAST_HEADER_ONLY
#include <boost/json/impl/parse_file.ipp>
#endif
#endif

View File

@@ -0,0 +1,153 @@
//
// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/json
//
#ifndef BOOST_JSON_PARSER_HPP
#define BOOST_JSON_PARSER_HPP
#include <boost/beast/core/detail/config.hpp>
#include <boost/json/value.hpp>
#include <boost/json/basic_parser.hpp>
#include <boost/json/storage.hpp>
#include <new>
#include <string>
#include <type_traits>
namespace boost {
namespace beast {
namespace json {
class parser : public basic_parser
{
static std::size_t const
default_max_depth = 32;
value jv_;
detail::stack<value*,
default_max_depth> stack_;
std::string s_;
unsigned long max_depth_ =
default_max_depth;
bool obj_;
public:
BOOST_BEAST_DECL
parser();
BOOST_BEAST_DECL
parser(storage_ptr const& store);
/** Returns the maximum allowed depth of input JSON.
*/
std::size_t
max_depth() const noexcept
{
return max_depth_;
}
/** Set the maximum allowed depth of input JSON.
*/
void
max_depth(unsigned long levels) noexcept
{
max_depth_ = levels;
}
BOOST_BEAST_DECL
value const&
get() const noexcept;
BOOST_BEAST_DECL
value
release() noexcept;
private:
template<class T>
void
assign(T&& t);
BOOST_BEAST_DECL
void
reset();
BOOST_BEAST_DECL
void
on_document_begin(
error_code& ec) override;
BOOST_BEAST_DECL
void
on_object_begin(
error_code& ec) override;
BOOST_BEAST_DECL
void
on_object_end(
error_code& ec) override;
BOOST_BEAST_DECL
void
on_array_begin(
error_code& ec) override;
BOOST_BEAST_DECL
void
on_array_end(
error_code& ec) override;
BOOST_BEAST_DECL
void
on_key_data(
string_view s,
error_code& ec) override;
BOOST_BEAST_DECL
void
on_key_end(
string_view s,
error_code& ec) override;
BOOST_BEAST_DECL
void
on_string_data(
string_view s,
error_code& ec) override;
BOOST_BEAST_DECL
void
on_string_end(
string_view s,
error_code& ec) override;
BOOST_BEAST_DECL
void
on_number(
number n,
error_code& ec) override;
BOOST_BEAST_DECL
void
on_bool(
bool b,
error_code& ec) override;
BOOST_BEAST_DECL
void
on_null(error_code&) override;
};
} // json
} // beast
} // boost
#include <boost/json/impl/parser.hpp>
#ifdef BOOST_BEAST_HEADER_ONLY
#include <boost/json/impl/parser.ipp>
#endif
#endif

View File

@@ -0,0 +1,143 @@
//
// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/json
//
#ifndef BOOST_JSON_SERIALIZER_HPP
#define BOOST_JSON_SERIALIZER_HPP
#include <boost/beast/core/detail/config.hpp>
#include <boost/json/iterator.hpp>
#include <boost/json/number.hpp>
#include <boost/json/value.hpp>
#include <boost/asio/buffer.hpp>
namespace boost {
namespace beast {
namespace json {
class serializer
{
struct base
{
virtual ~base() = default;
virtual
bool
is_done() const noexcept = 0;
virtual
std::size_t
next(net::mutable_buffer) = 0;
};
class impl : public base
{
enum class state
{
next,
init,
key,
value,
literal,
key_literal,
string,
done
};
value const& jv_;
const_iterator it_;
string_view str_;
char buf_[number::max_string_chars + 1];
state state_ = state::init;
bool last_;
public:
BOOST_BEAST_DECL
impl(value const& jv);
BOOST_BEAST_DECL
bool
is_done() const noexcept override;
BOOST_BEAST_DECL
std::size_t
next(net::mutable_buffer) override;
private:
BOOST_BEAST_DECL
void
append(char c,
net::mutable_buffer& b);
BOOST_BEAST_DECL
void
append(
char const* s, std::size_t n,
net::mutable_buffer& b);
};
typename std::aligned_storage<
sizeof(impl)>::type buf_;
base&
get_base() noexcept
{
return *reinterpret_cast<
base*>(&buf_);
}
base const&
get_base() const noexcept
{
return *reinterpret_cast<
base const*>(&buf_);
}
public:
BOOST_BEAST_DECL
~serializer();
BOOST_BEAST_DECL
explicit
serializer(value const& jv);
template<class MutableBufferSequence>
std::size_t
next(MutableBufferSequence const& buffers)
{
std::size_t bytes_transferred = 0;
for(auto it = net::buffer_sequence_begin(buffers),
end = net::buffer_sequence_end(buffers);
it != end; ++it)
bytes_transferred += next(
net::mutable_buffer(*it));
return bytes_transferred;
}
bool
is_done() const noexcept
{
return get_base().is_done();
}
std::size_t
next(net::mutable_buffer buffer)
{
return get_base().next(buffer);
}
};
} // json
} // beast
} // boost
#ifdef BOOST_BEAST_HEADER_ONLY
#include <boost/json/impl/serializer.ipp>
#endif
#endif

View File

@@ -0,0 +1,41 @@
//
// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/json
//
#ifndef BOOST_BEAST_SRC_EXTRA_HPP
#define BOOST_BEAST_SRC_EXTRA_HPP
/*
This file is meant to be included once, in a translation unit of
the program, with the macro BOOST_BEAST_SPLIT_COMPILATION defined.
*/
#define BOOST_BEAST_SOURCE
#include <boost/beast/core/detail/config.hpp>
#if defined(BOOST_BEAST_HEADER_ONLY)
# error Do not compile Beast library source with BOOST_BEAST_HEADER_ONLY defined
#endif
#include <boost/json/detail/varint.ipp>
#include <boost/json/impl/array.ipp>
#include <boost/json/impl/basic_parser.ipp>
#include <boost/json/impl/error.ipp>
#include <boost/json/impl/iterator.ipp>
#include <boost/json/impl/number.ipp>
#include <boost/json/impl/object.ipp>
#include <boost/json/impl/parse_file.ipp>
#include <boost/json/impl/parser.ipp>
#include <boost/json/impl/serializer.ipp>
#include <boost/json/impl/storage.ipp>
#include <boost/json/impl/value.ipp>
#endif

View File

@@ -0,0 +1,220 @@
//
// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/json
//
#ifndef BOOST_JSON_STORAGE_HPP
#define BOOST_JSON_STORAGE_HPP
#include <boost/beast/core/detail/config.hpp>
#include <cstddef>
#include <cstdlib>
#include <type_traits>
namespace boost {
namespace beast {
namespace json {
/** Abstract interface to a memory resource used with JSON.
*/
struct storage
{
static std::size_t constexpr max_align =
sizeof(max_align_t);
virtual
~storage() = default;
virtual
void
addref() noexcept = 0;
virtual
void
release() noexcept = 0;
virtual
void*
allocate(
std::size_t n,
std::size_t align =
max_align) = 0;
virtual
void
deallocate(
void* p,
std::size_t n,
std::size_t align =
max_align) noexcept = 0;
virtual
bool
is_equal(
storage const& other) const noexcept = 0;
friend
bool
operator==(
storage const& lhs,
storage const& rhs) noexcept
{
return &lhs == &rhs || lhs.is_equal(rhs);
}
friend
bool
operator!=(
storage const& lhs,
storage const& rhs) noexcept
{
return !(lhs == rhs);
}
};
//------------------------------------------------------------------------------
/** Manages a type-erased storage object and options for a set of JSON values.
*/
class storage_ptr
{
storage* p_ = nullptr;
public:
storage_ptr() = default;
BOOST_BEAST_DECL
~storage_ptr();
BOOST_BEAST_DECL
storage_ptr(storage_ptr&&) noexcept;
BOOST_BEAST_DECL
storage_ptr(storage_ptr const&) noexcept;
BOOST_BEAST_DECL
storage_ptr&
operator=(storage_ptr&&) noexcept;
BOOST_BEAST_DECL
storage_ptr&
operator=(storage_ptr const&) noexcept;
/** Constructor
@param p A pointer to a storage object. Ownership of the
object is transferred; the reference count is not adjusted.
*/
BOOST_BEAST_DECL
storage_ptr(storage* p) noexcept;
/** Return ownership of the managed storage object.
*/
BOOST_BEAST_DECL
storage*
release() noexcept;
explicit
operator bool() const noexcept
{
return p_ != nullptr;
}
storage*
get() const noexcept
{
return p_;
}
storage*
operator->() const noexcept
{
return p_;
}
storage&
operator*() const noexcept
{
return *p_;
}
};
inline
bool
operator==(storage_ptr const& lhs, storage_ptr const& rhs) noexcept
{
return lhs.get() == rhs.get();
}
inline
bool
operator==(storage* lhs, storage_ptr const& rhs) noexcept
{
return lhs == rhs.get();
}
inline
bool
operator==(storage_ptr const& lhs, storage* rhs) noexcept
{
return lhs.get() == rhs;
}
inline
bool
operator!=(storage_ptr const& lhs, storage_ptr const& rhs) noexcept
{
return lhs.get() != rhs.get();
}
inline
bool
operator!=(storage* lhs, storage_ptr const& rhs) noexcept
{
return lhs != rhs.get();
}
inline
bool
operator!=(storage_ptr const& lhs, storage* rhs) noexcept
{
return lhs.get() != rhs;
}
//------------------------------------------------------------------------------
/** Construct a storage pointer to the specified allocator
*/
template<class Allocator>
storage_ptr
make_storage_ptr(Allocator const& a);
/** Return a pointer to the current default storage
*/
BOOST_BEAST_DECL
storage_ptr
default_storage();
/** Set the current default storage
This function may not be called concurrently,
or concurrent with @ref default_storage.
*/
BOOST_BEAST_DECL
void
default_storage(storage_ptr sp);
} // json
} // beast
} // boost
#include <boost/json/impl/storage.hpp>
#ifdef BOOST_BEAST_HEADER_ONLY
#include <boost/json/impl/storage.ipp>
#endif
#endif

View File

@@ -0,0 +1,35 @@
//
// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/json
//
#ifndef BOOST_JSON_STRING_HPP
#define BOOST_JSON_STRING_HPP
#include <boost/beast/core/detail/config.hpp>
#include <boost/json/allocator.hpp>
#include <string>
namespace boost {
namespace beast {
namespace json {
class value;
/** The native type of string values
*/
using string =
std::basic_string<
char,
std::char_traits<char>,
allocator<char>>;
} // json
} // beast
} // boost
#endif

View File

@@ -0,0 +1,942 @@
//
// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/json
//
#ifndef BOOST_JSON_VALUE_HPP
#define BOOST_JSON_VALUE_HPP
#include <boost/beast/core/detail/config.hpp>
#include <boost/json/array.hpp>
#include <boost/json/kind.hpp>
#include <boost/json/number.hpp>
#include <boost/json/object.hpp>
#include <boost/json/storage.hpp>
#include <boost/json/string.hpp>
#include <boost/json/detail/is_specialized.hpp>
#include <boost/json/detail/value.hpp>
#include <boost/type_traits/make_void.hpp>
#include <cstdlib>
#include <initializer_list>
#include <iosfwd>
#include <type_traits>
#include <utility>
namespace boost {
namespace beast {
namespace json {
class value;
/** Customization point for assigning to and from class types.
*/
template<class T>
struct value_exchange final
#ifndef BOOST_BEAST_DOXYGEN
: detail::primary_template
#endif
{
static
void
to_json(T const& t, value& v)
{
detail::call_to_json(t, v);
}
static
void
from_json(T& t, value const& v)
{
detail::call_from_json(t, v);
}
};
/** Trait to determine if a type can be assigned to a json value.
*/
template<class T>
using has_from_json =
#ifdef BOOST_BEAST_DOXYGEN
__see_below__;
#else
std::integral_constant<bool,
detail::is_specialized<value_exchange<
detail::remove_cr<T>>>::value ||
detail::has_adl_from_json<
detail::remove_cr<T>>::value ||
detail::has_mf_from_json<
detail::remove_cr<T>>::value>;
#endif
/** Returns `true` if a JSON value can be constructed from `T`
*/
template<class T>
using has_to_json =
#ifdef BOOST_BEAST_DOXYGEN
__see_below__;
#else
std::integral_constant<bool,
detail::is_specialized<value_exchange<
detail::remove_cr<T>>>::value ||
detail::has_adl_to_json<
detail::remove_cr<T>>::value ||
detail::has_mf_to_json<
detail::remove_cr<T>>::value>;
#endif
//------------------------------------------------------------------------------
/** A JSON value.
*/
class value
{
friend class value_test;
struct native
{
union
{
number num_;
bool bool_;
};
storage_ptr sp_;
};
union
{
object obj_;
array arr_;
string str_;
native nat_;
};
json::kind kind_;
public:
//--------------------------------------------------------------------------
//
// Special members
//
//--------------------------------------------------------------------------
/// Destroy a value and all of its contents
BOOST_BEAST_DECL
~value();
/// Move constructor
BOOST_BEAST_DECL
value(value&& other) noexcept;
/// Move construct a value, using the specified storage
BOOST_BEAST_DECL
value(
value&& other,
storage_ptr store);
/// Construct a copy of a value
BOOST_BEAST_DECL
value(value const& other);
/// Construct a copy of a value using the specified storage
BOOST_BEAST_DECL
value(
value const& other,
storage_ptr store);
/// Move-assign a value
BOOST_BEAST_DECL
value& operator=(value&& other);
/// Assign a copy of a value
BOOST_BEAST_DECL
value& operator=(value const& other);
//--------------------------------------------------------------------------
//
// Construction and Assignment
//
//--------------------------------------------------------------------------
/** Construct a null value using the default storage.
*/
BOOST_BEAST_DECL
value() noexcept;
/** Construct a null value using the specified storage.
The value and all of its contents will use the
specified storage object.
*/
BOOST_BEAST_DECL
explicit
value(storage_ptr store) noexcept;
/** Construct a value using the default storage
The value and all of its contents will use the
specified storage object.
*/
BOOST_BEAST_DECL
value(json::kind k) noexcept;
/** Construct a value using the specified storage.
The value and all of its contents will use the specified
storage object.
@param k The kind of JSON value.
@param store The storage to use.
*/
BOOST_BEAST_DECL
value(
json::kind k,
storage_ptr store) noexcept;
/** Construct a value from an object.
*/
BOOST_BEAST_DECL
value(object obj) noexcept;
/** Construct a value from an object using the specified storage
*/
BOOST_BEAST_DECL
value(object obj, storage_ptr store);
/** Construct a value from an array.
*/
BOOST_BEAST_DECL
value(array arr) noexcept;
/** Construct a value from an array using the specified storage
*/
BOOST_BEAST_DECL
value(array arr, storage_ptr store);
/** Construct a value from a string.
*/
BOOST_BEAST_DECL
value(string str) noexcept;
/** Construct a value from a string using the specified storage
*/
BOOST_BEAST_DECL
value(string str, storage_ptr store);
/** Construct a value from a nujmber
*/
BOOST_BEAST_DECL
value(number num);
/** Construct a value from a nujmber using the specified storage
*/
BOOST_BEAST_DECL
value(number num, storage_ptr store);
/** Construct an object from an initializer list.
*/
BOOST_BEAST_DECL
value(std::initializer_list<
std::pair<string_view, value>> init);
/** Construct an object from an initializer list using the specified storage
*/
BOOST_BEAST_DECL
value(std::initializer_list<
std::pair<string_view, value>> init,
storage_ptr store);
#if 0
/** Construct an array from an initializer list.
*/
BOOST_BEAST_DECL
value(std::initializer_list<value> init);
/** Construct an array from an initializer list using the specified storage.
*/
BOOST_BEAST_DECL
value(std::initializer_list<value> init,
storage_ptr store);
#endif
/** Assign a value from an object
*/
BOOST_BEAST_DECL
value&
operator=(object obj);
/** Assign a value from an array
*/
BOOST_BEAST_DECL
value&
operator=(array arr);
/** Assign a value from a string
*/
BOOST_BEAST_DECL
value&
operator=(string str);
//--------------------------------------------------------------------------
//
// Modifiers
//
//--------------------------------------------------------------------------
/** Reset the json to the specified type.
This changes the value to hold a value of the
specified type. Any previous contents are cleared.
@param k The kind to set. If the new kind is an
object, array, or string the resulting value will be
empty. Otherwise, the value will be in an undefined,
valid state.
*/
BOOST_BEAST_DECL
void
reset(json::kind k = json::kind::null) noexcept;
/** Reset the json to the specified type.
This changes the value to hold a value of the
specified type. Any previous contents are cleared.
@param k The kind to set. If the new kind is an
object, array, or string the resulting value will be
empty. Otherwise, the value will be in an undefined,
valid state.
*/
BOOST_BEAST_DECL
value&
operator=(json::kind k) noexcept
{
reset(k);
return *this;
}
/** Set the value to an empty object, and return it.
This calls `reset(json::kind::object)` and returns
`as_object()`. The previous contents of the value
are destroyed.
*/
object&
emplace_object() noexcept
{
reset(json::kind::object);
return as_object();
}
/** Set the value to an empty array, and return it.
This calls `reset(json::kind::array)` and returns
`as_array()`. The previous contents of the value
are destroyed.
*/
array&
emplace_array() noexcept
{
reset(json::kind::array);
return as_array();
}
/** Set the value to an empty string, and return it.
This calls `reset(json::kind::string)` and returns
`as_string()`. The previous contents of the value
are destroyed.
*/
string&
emplace_string() noexcept
{
reset(json::kind::string);
return as_string();
}
/** Set the value to an uninitialized number, and return it.
This calls `reset(json::kind::number)` and returns
`as_number()`. The previous contents of the value
are destroyed.
*/
number&
emplace_number() noexcept
{
reset(json::kind::number);
return as_number();
}
/** Set the value to an uninitialized boolean, and return it.
This calls `reset(json::kind::boolean)` and returns
`as_bool()`. The previous contents of the value
are destroyed.
*/
bool&
emplace_bool() noexcept
{
reset(json::kind::boolean);
return as_bool();
}
/// Set the value to a null
void
emplace_null() noexcept
{
reset(json::kind::null);
}
//--------------------------------------------------------------------------
//
// Exchange
//
//--------------------------------------------------------------------------
/// Construct a value from another type
template<
class T
#ifndef BOOST_BEAST_DOXYGEN
,class = typename std::enable_if<
has_to_json<T>::value>::type
#endif
>
value(T const& t)
: value(t, default_storage())
{
}
/// Construct a value from another type using the specified storage
template<
class T
#ifndef BOOST_BEAST_DOXYGEN
,class = typename std::enable_if<
has_to_json<T>::value>::type
#endif
>
value(T const& t, storage_ptr store)
: value(std::move(store))
{
value_exchange<
detail::remove_cr<T>
>::to_json(t, *this);
}
/// Assign a value from another type
template<
class T
#ifndef BOOST_BEAST_DOXYGEN
,class = typename std::enable_if<
has_to_json<T>::value>::type
#endif
>
value&
operator=(T const& t)
{
value_exchange<
detail::remove_cr<T>
>::to_json(t, *this);
return *this;
}
/** Try to assign a value to another type
@throws system error Thrown upon failure
*/
template<class T>
void
store(T& t) const
{
// If this assert goes off, it means that there are no known
// ways to convert a JSON value into a user defined type `T`.
// There are three ways to fix this:
//
// 1. Add the member function `T::from_json(value const&)`,
//
// 2. Add the free function `from_json(T&, value const&)`
// in the same namespace as T, or
//
// 3. Specialize `json::value_exchange` for `T`, and provide
// the static member `from_json(T&, value const&)`.
static_assert(
has_from_json<T>::value,
"Destination type is unknown");
value_exchange<
detail::remove_cr<T>
>::from_json(t, *this);
}
//--------------------------------------------------------------------------
//
// Observers
//
//--------------------------------------------------------------------------
/// Returns the kind of this JSON value
json::kind
kind() const noexcept
{
return kind_;
}
/// Returns `true` if this is an object
bool
is_object() const noexcept
{
return kind_ == json::kind::object;
}
/// Returns `true` if this is an array
bool
is_array() const noexcept
{
return kind_ == json::kind::array;
}
/// Returns `true` if this is a string
bool
is_string() const noexcept
{
return kind_ == json::kind::string;
}
/// Returns `true` if this is a number
bool
is_number() const noexcept
{
return kind_ == json::kind::number;
}
bool
is_bool() const noexcept
{
return kind_ == json::kind::boolean;
}
bool
is_null() const noexcept
{
return kind_ == json::kind::null;
}
//---
/// Returns `true` if this is not an array or object
bool
is_primitive() const noexcept
{
switch(kind_)
{
case json::kind::object:
case json::kind::array:
return false;
default:
return true;
}
}
/// Returns `true` if this is an array or object
bool
is_structured() const noexcept
{
return ! is_primitive();
}
/// Returns `true` if this is a number representable as a `std::int64_t`
bool
is_int64() const noexcept
{
return
kind_ == json::kind::number &&
nat_.num_.is_int64();
}
/// Returns `true` if this is a number representable as a `std::uint64_t`
bool
is_uint64() const noexcept
{
return
kind_ == json::kind::number &&
nat_.num_.is_uint64();
}
/** Returns `true` if this is a number representable as a `double`
The return value will always be the same as the
value returned from @ref is_number.
*/
bool
is_double() const noexcept
{
return kind_ == json::kind::number;
}
//--------------------------------------------------------------------------
//
// Accessors
//
//--------------------------------------------------------------------------
BOOST_BEAST_DECL
storage_ptr
get_storage() const noexcept;
object&
as_object() noexcept
{
BOOST_ASSERT(is_object());
return obj_;
}
object const&
as_object() const noexcept
{
BOOST_ASSERT(is_object());
return obj_;
}
array&
as_array() noexcept
{
BOOST_ASSERT(is_array());
return arr_;
}
array const&
as_array() const noexcept
{
BOOST_ASSERT(is_array());
return arr_;
}
string&
as_string() noexcept
{
BOOST_ASSERT(is_string());
return str_;
}
string const&
as_string() const noexcept
{
BOOST_ASSERT(is_string());
return str_;
}
number&
as_number() noexcept
{
BOOST_ASSERT(is_number());
return nat_.num_;
}
number const&
as_number() const noexcept
{
BOOST_ASSERT(is_number());
return nat_.num_;
}
std::int64_t
get_int64() const noexcept
{
BOOST_ASSERT(is_int64());
return nat_.num_.get_int64();
}
std::uint64_t
get_uint64() const noexcept
{
BOOST_ASSERT(is_uint64());
return nat_.num_.get_uint64();
}
double
get_double() const noexcept
{
BOOST_ASSERT(is_double());
return nat_.num_.get_double();
}
bool&
as_bool() noexcept
{
BOOST_ASSERT(is_bool());
return nat_.bool_;
}
bool const&
as_bool() const noexcept
{
BOOST_ASSERT(is_bool());
return nat_.bool_;
}
//--------------------------------------------------------------------------
//
// Structured
//
//--------------------------------------------------------------------------
using key_type = beast::string_view;
using mapped_type = value;
using value_type = std::pair<key_type, value>;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
using reference = std::pair<key_type, value&>;
using const_reference = std::pair<key_type, value const&>;
class pointer;
class const_pointer;
class iterator;
class const_iterator;
using reverse_iterator =
std::reverse_iterator<iterator>;
using const_reverse_iterator =
std::reverse_iterator<const_iterator>;
//
// Capacity
//
BOOST_BEAST_DECL
bool
empty() const;
BOOST_BEAST_DECL
size_type
size() const;
//
// Iterators
//
BOOST_BEAST_DECL
iterator
begin();
BOOST_BEAST_DECL
const_iterator
begin() const;
BOOST_BEAST_DECL
const_iterator
cbegin();
BOOST_BEAST_DECL
iterator
end();
BOOST_BEAST_DECL
const_iterator
end() const;
BOOST_BEAST_DECL
const_iterator
cend();
BOOST_BEAST_DECL
reverse_iterator
rbegin();
BOOST_BEAST_DECL
const_reverse_iterator
rbegin() const;
BOOST_BEAST_DECL
const_reverse_iterator
crbegin();
BOOST_BEAST_DECL
reverse_iterator
rend();
BOOST_BEAST_DECL
const_reverse_iterator
rend() const;
BOOST_BEAST_DECL
const_reverse_iterator
crend();
//
// Lookup
//
BOOST_BEAST_DECL
value&
at(key_type key);
BOOST_BEAST_DECL
value const&
at(key_type key) const;
BOOST_BEAST_DECL
value&
operator[](key_type key);
BOOST_BEAST_DECL
value const&
operator[](key_type key) const;
BOOST_BEAST_DECL
size_type
count(key_type key) const;
BOOST_BEAST_DECL
iterator
find(key_type key);
BOOST_BEAST_DECL
const_iterator
find(key_type key) const;
BOOST_BEAST_DECL
bool
contains(key_type key) const;
//
// Elements
//
BOOST_BEAST_DECL
reference
at(size_type pos);
BOOST_BEAST_DECL
const_reference
at(size_type pos) const;
BOOST_BEAST_DECL
value&
operator[](size_type i);
BOOST_BEAST_DECL
value const&
operator[](size_type i) const;
BOOST_BEAST_DECL
reference
front();
BOOST_BEAST_DECL
const_reference
front() const;
BOOST_BEAST_DECL
reference
back();
BOOST_BEAST_DECL
const_reference
back() const;
// Modifiers
BOOST_BEAST_DECL
void
clear() noexcept;
template<class M>
std::pair<iterator, bool>
insert_or_assign(
key_type key, M&& obj);
template<class M>
std::pair<iterator, bool>
insert_or_assign(
const_iterator before,
key_type key,
M&& obj);
template<class Arg>
std::pair<iterator, bool>
emplace(key_type key, Arg&& arg);
template<class Arg>
std::pair<iterator, bool>
emplace(
const_iterator before,
key_type key, Arg&& arg);
template<class Arg>
iterator
emplace(
const_iterator before,
Arg&& arg);
BOOST_BEAST_DECL
size_type
erase(key_type key);
BOOST_BEAST_DECL
iterator
erase(const_iterator pos);
BOOST_BEAST_DECL
iterator
erase(
const_iterator first,
const_iterator last);
template<class Arg>
value&
emplace_back(Arg&& arg);
BOOST_BEAST_DECL
void
pop_back();
//--------------------------------------------------------------------------
private:
BOOST_BEAST_DECL
storage_ptr
release_storage() noexcept;
BOOST_BEAST_DECL
void
construct(
json::kind, storage_ptr) noexcept;
BOOST_BEAST_DECL
void
clear_impl() noexcept;
BOOST_BEAST_DECL
void
move(storage_ptr, value&&);
BOOST_BEAST_DECL
void
copy(storage_ptr, value const&);
BOOST_BEAST_DECL
friend
std::ostream&
operator<<(
std::ostream& os,
value const& jv);
};
} // json
} // beast
} // boost
#include <boost/json/impl/array.hpp>
#include <boost/json/impl/object.hpp>
#ifdef BOOST_BEAST_HEADER_ONLY
#include <boost/json/impl/array.ipp>
#include <boost/json/impl/object.ipp>
#endif
// These must come after array and object
#include <boost/json/impl/value.hpp>
#ifdef BOOST_BEAST_HEADER_ONLY
#include <boost/json/impl/value.ipp>
#endif
#endif

40
test/CMakeLists.txt Normal file
View File

@@ -0,0 +1,40 @@
#
# Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
#
# Distributed under the Boost Software License, Version 1.0. (See accompanying
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#
# Official repository: https://github.com/boostorg/json
#
source_group (json FILES ${PROJECT_SOURCE_DIR}/include/boost/json.hpp)
source_group (TREE ${PROJECT_SOURCE_DIR}/include/boost/json PREFIX json FILES ${PROJECT_FILES})
GroupSources(test "/")
add_executable (json-tests
${BEAST_FILES}
${PROJECT_FILES}
Jamfile
lib.cpp
_detail_stack.cpp
allocator.cpp
array.cpp
assign_string.cpp
assign_vector.cpp
basic_parser.cpp
error.cpp
iterator.cpp
json.cpp
kind.cpp
number.cpp
object.cpp
parse_file.cpp
parser.cpp
serializer.cpp
storage.cpp
string.cpp
value.cpp
)
add_test(json-tests json-tests)

51
test/Jamfile Normal file
View File

@@ -0,0 +1,51 @@
#
# Copyright (c) 2013-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
#
# Distributed under the Boost Software License, Version 1.0. (See accompanying
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#
# Official repository: https://github.com/boostorg/json
#
local SOURCES =
_detail_stack.cpp
allocator.cpp
array.cpp
assign_string.cpp
assign_vector.cpp
basic_parser.cpp
error.cpp
iterator.cpp
json.cpp
kind.cpp
number.cpp
object.cpp
parse_file.cpp
parser.cpp
serializer.cpp
storage.cpp
string.cpp
value.cpp
;
local RUN_TESTS ;
for local f in $(SOURCES)
{
RUN_TESTS += [ run $(f) lib.cpp ] ;
}
alias run-tests : $(RUN_TESTS) ;
exe fat-tests :
$(SOURCES)
lib.cpp
;
explicit fat-tests ;
run $(SOURCES)
lib.cpp
: : : : run-fat-tests ;
explicit run-fat-tests ;

55
test/_detail_stack.cpp Normal file
View File

@@ -0,0 +1,55 @@
//
// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/json
//
// Test that header file is self-contained.
#include <boost/json/detail/stack.hpp>
#include <boost/beast/_experimental/unit_test/suite.hpp>
#include <string>
namespace boost {
namespace beast {
namespace json {
namespace detail {
class stack_test : public unit_test::suite
{
public:
void
testStack()
{
stack<std::string, 1> s;
BEAST_EXPECT(s.empty());
BEAST_EXPECT(s.capacity() > 0);
BEAST_EXPECT(s.size() == 0);
s.emplace_front("1");
BEAST_EXPECT(s.size() == 1);
BEAST_EXPECT(s[0] == "1");
s.emplace_front("2");
BEAST_EXPECT(s.size() == 2);
BEAST_EXPECT(s[0] == "2");
s.pop_front();
BEAST_EXPECT(s.size() == 1);
BEAST_EXPECT(s[0] == "1");
s.pop_front();
BEAST_EXPECT(s.empty());
}
void run() override
{
testStack();
}
};
BEAST_DEFINE_TESTSUITE(beast,json,stack);
} // detail
} // json
} // beast
} // boost

51
test/allocator.cpp Normal file
View File

@@ -0,0 +1,51 @@
//
// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/vinniefalco/BeastLounge
//
// Test that header file is self-contained.
#include <boost/json/allocator.hpp>
#include <boost/beast/_experimental/unit_test/suite.hpp>
#include <vector>
namespace boost {
namespace beast {
namespace json {
class allocator_test : public unit_test::suite
{
public:
void
testAllocator()
{
auto a1 = make_storage_ptr(
std::allocator<void>{});
auto a2 = a1;
auto a3 = std::move(a2);
a2 = a1;
a3 = std::move(a2);
std::vector<char, allocator<char>> v(
allocator<char>(make_storage_ptr(
std::allocator<void>{})));
v.resize(100);
BEAST_EXPECT(v.capacity() >= 100);
}
void
run()
{
testAllocator();
}
};
BEAST_DEFINE_TESTSUITE(beast,json,allocator);
} // json
} // beast
} // boost

832
test/array.cpp Normal file
View File

@@ -0,0 +1,832 @@
//
// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/vinniefalco/BeastLounge
//
// Test that header file is self-contained.
#include <boost/json/array.hpp>
#include <boost/beast/_experimental/unit_test/suite.hpp>
namespace boost {
namespace beast {
namespace json {
class array_test : public unit_test::suite
{
public:
struct unique_storage : storage
{
void
addref() noexcept override
{
}
void
release() noexcept override
{
}
void*
allocate(
std::size_t n,
std::size_t) override
{
return std::allocator<
char>{}.allocate(n);
}
void
deallocate(
void* p,
std::size_t n,
std::size_t) noexcept override
{
auto cp =
reinterpret_cast<char*>(p);
return std::allocator<
char>{}.deallocate(cp, n);
}
bool
is_equal(
storage const& other
) const noexcept override
{
auto p = dynamic_cast<
unique_storage const*>(&other);
if(! p)
return false;
return this == p;
}
};
struct fail_storage : storage
{
std::size_t fail_max = 1;
std::size_t fail = 0;
void
addref() noexcept override
{
}
void
release() noexcept override
{
}
void*
allocate(
std::size_t n,
std::size_t) override
{
if(++fail == fail_max)
{
++fail_max;
fail = 0;
throw std::bad_alloc{};
}
return std::allocator<
char>{}.allocate(n);
}
void
deallocate(
void* p,
std::size_t n,
std::size_t) noexcept override
{
auto cp =
reinterpret_cast<char*>(p);
return std::allocator<
char>{}.deallocate(cp, n);
}
bool
is_equal(
storage const& other
) const noexcept override
{
auto p = dynamic_cast<
fail_storage const*>(&other);
if(! p)
return false;
return this == p;
}
};
void
check(array const& arr)
{
BEAST_EXPECT(arr.size() == 3);
BEAST_EXPECT(arr[0].is_number());
BEAST_EXPECT(arr[1].is_bool());
BEAST_EXPECT(arr[2].is_string());
}
void
check(
array const& arr,
storage_ptr const& sp)
{
check(arr);
BEAST_EXPECT(arr.get_storage() == sp);
BEAST_EXPECT(arr[0].get_storage() == sp);
BEAST_EXPECT(arr[1].get_storage() == sp);
BEAST_EXPECT(arr[2].get_storage() == sp);
}
void
testSpecial()
{
unique_storage us;
storage_ptr sp(&us);
storage_ptr sp0 =
default_storage();
BEAST_EXPECT(*sp != *sp0);
// array()
{
array arr;
BEAST_EXPECT(arr.empty());
BEAST_EXPECT(arr.size() == 0);
}
// array(storage)
{
array arr(sp);
BEAST_EXPECT(arr.get_storage() == sp);
BEAST_EXPECT(arr.get_storage() != sp0);
}
// array(size_type)
{
array arr(3);
BEAST_EXPECT(arr.size() == 3);
for(auto const& v : arr)
BEAST_EXPECT(v.is_null());
}
// array(size_type, storage)
{
array arr(3, sp);
BEAST_EXPECT(arr.size() == 3);
for(auto const& v : arr)
BEAST_EXPECT(v.get_storage() == sp);
}
// array(size_type, value)
{
array arr(3, kind::boolean);
BEAST_EXPECT(arr.size() == 3);
for(auto const& v : arr)
BEAST_EXPECT(v.is_bool());
}
// array(size_type, value, storage)
{
array arr(3, kind::boolean, sp);
BEAST_EXPECT(arr.size() == 3);
for(auto const& v : arr)
BEAST_EXPECT(v.get_storage() == sp);
}
// array(InputIt, InputIt)
{
std::initializer_list<value> list =
{ 1, true, "hello" };
array arr(list.begin(), list.end());
check(arr, sp0);
}
// array(InputIt, InputIt, storage)
{
std::initializer_list<value> list =
{ 1, true, "hello" };
array arr(list.begin(), list.end(), sp);
check(arr, sp);
}
// array(array const&)
{
std::initializer_list<value> list =
{ 1, true, "hello" };
array arr1(list.begin(), list.end(), sp);
array arr2 = arr1;
check(arr2, sp);
}
// array(array const&, storage)
{
std::initializer_list<value> list =
{ 1, true, "hello" };
array arr1(list.begin(), list.end());
array arr2(arr1, sp);
BEAST_EXPECT(arr2.size() == 3);
BEAST_EXPECT(
arr1[0].get_storage() !=
arr2[0].get_storage());
BEAST_EXPECT(
arr1[1].get_storage() !=
arr2[1].get_storage());
BEAST_EXPECT(
arr1[2].get_storage() !=
arr2[2].get_storage());
}
// array(array&&)
{
std::initializer_list<value> list =
{ 1, true, "hello" };
array arr1(list.begin(), list.end(), sp);
array arr2 = std::move(arr1);
BEAST_EXPECT(arr1.empty());
BEAST_EXPECT(
arr1.get_storage() ==
arr2.get_storage());
check(arr2, sp);
}
// array(array&&, storage)
{
std::initializer_list<value> list =
{ 1, true, "hello" };
array arr1(list.begin(), list.end());
array arr2(std::move(arr1), sp);
BEAST_EXPECT(! arr1.empty());
BEAST_EXPECT(
arr1.get_storage() !=
arr2.get_storage());
check(arr2, sp);
}
// array(init_list)
{
array arr({1, true, "hello"});
check(arr, sp0);
}
// array(init_list, storage)
{
array arr({1, true, "hello"}, sp);
check(arr, sp);
}
// operator=(array&&)
{
{
array arr1({1, true, "hello"});
array arr2({nullptr, kind::object, 1.f});
arr2 = std::move(arr1);
BEAST_EXPECT(arr1.empty());
BEAST_EXPECT(
arr1.get_storage() ==
arr2.get_storage());
check(arr2, sp0);
}
{
array arr1({1, true, "hello"});
array arr2({nullptr, kind::object, 1.f}, sp);
arr2 = std::move(arr1);
BEAST_EXPECT(! arr1.empty());
BEAST_EXPECT(
arr1.get_storage() !=
arr2.get_storage());
check(arr2, sp);
}
}
// operator=(array const&)
{
{
array arr1({1, true, "hello"});
array arr2({nullptr, kind::object, 1.f});
arr2 = arr1;
BEAST_EXPECT(! arr1.empty());
check(arr2, sp0);
}
{
array arr1({1, true, "hello"});
array arr2({nullptr, kind::object, 1.f}, sp);
arr2 = arr1;
BEAST_EXPECT(! arr1.empty());
BEAST_EXPECT(
arr1.get_storage() !=
arr2.get_storage());
check(arr2, sp);
}
}
// operator=(init_list)
{
{
std::initializer_list<value> list =
{ 1, true, "hello" };
array arr({nullptr, kind::object, 1.f});
arr = list;
check(arr, sp0);
}
{
std::initializer_list<value> list =
{ 1, true, "hello" };
array arr({nullptr, kind::object, 1.f}, sp);
arr = list;
check(arr, sp);
}
}
}
void
testElements()
{
// at(pos)
{
array arr({1, true, "hello"});
BEAST_EXPECT(arr.at(0).is_number());
BEAST_EXPECT(arr.at(1).is_bool());
BEAST_EXPECT(arr.at(2).is_string());
try
{
arr.at(3);
BEAST_FAIL();
}
catch(std::out_of_range const&)
{
BEAST_PASS();
}
}
// at(pos) const
{
array const arr({1, true, "hello"});
BEAST_EXPECT(arr.at(0).is_number());
BEAST_EXPECT(arr.at(1).is_bool());
BEAST_EXPECT(arr.at(2).is_string());
try
{
arr.at(3);
BEAST_FAIL();
}
catch(std::out_of_range const&)
{
BEAST_PASS();
}
}
// operator[](size_type)
{
array arr({1, true, "hello"});
BEAST_EXPECT(arr[0].is_number());
BEAST_EXPECT(arr[1].is_bool());
BEAST_EXPECT(arr[2].is_string());
}
// operator[](size_type) const
{
array const arr({1, true, "hello"});
BEAST_EXPECT(arr[0].is_number());
BEAST_EXPECT(arr[1].is_bool());
BEAST_EXPECT(arr[2].is_string());
}
// front()
{
array arr({1, true, "hello"});
BEAST_EXPECT(arr.front().is_number());
}
// front() const
{
array const arr({1, true, "hello"});
BEAST_EXPECT(arr.front().is_number());
}
// back()
{
array arr({1, true, "hello"});
BEAST_EXPECT(arr.back().is_string());
}
// back() const
{
array const arr({1, true, "hello"});
BEAST_EXPECT(arr.back().is_string());
}
// data()
{
array arr({1, true, "hello"});
BEAST_EXPECT(arr.data() == &arr[0]);
}
// data() const
{
array const arr({1, true, "hello"});
BEAST_EXPECT(arr.data() == &arr[0]);
}
}
void
testIterators()
{
array arr({1, true, "hello"});
auto const& ac(arr);
{
auto it = arr.begin();
BEAST_EXPECT(it->is_number()); ++it;
BEAST_EXPECT(it->is_bool()); it++;
BEAST_EXPECT(it->is_string()); ++it;
BEAST_EXPECT(it == arr.end());
}
{
auto it = arr.cbegin();
BEAST_EXPECT(it->is_number()); ++it;
BEAST_EXPECT(it->is_bool()); it++;
BEAST_EXPECT(it->is_string()); ++it;
BEAST_EXPECT(it == arr.cend());
}
{
auto it = ac.begin();
BEAST_EXPECT(it->is_number()); ++it;
BEAST_EXPECT(it->is_bool()); it++;
BEAST_EXPECT(it->is_string()); ++it;
BEAST_EXPECT(it == ac.end());
}
{
auto it = arr.end();
--it; BEAST_EXPECT(it->is_string());
it--; BEAST_EXPECT(it->is_bool());
--it; BEAST_EXPECT(it->is_number());
BEAST_EXPECT(it == arr.begin());
}
{
auto it = arr.cend();
--it; BEAST_EXPECT(it->is_string());
it--; BEAST_EXPECT(it->is_bool());
--it; BEAST_EXPECT(it->is_number());
BEAST_EXPECT(it == arr.cbegin());
}
{
auto it = ac.end();
--it; BEAST_EXPECT(it->is_string());
it--; BEAST_EXPECT(it->is_bool());
--it; BEAST_EXPECT(it->is_number());
BEAST_EXPECT(it == ac.begin());
}
}
void
testCapacity()
{
// empty()
{
array arr;
BEAST_EXPECT(arr.empty());
arr.emplace_back(1);
BEAST_EXPECT(! arr.empty());
}
// size()
{
array arr;
BEAST_EXPECT(arr.size() == 0);
arr.emplace_back(1);
BEAST_EXPECT(arr.size() == 1);
}
// max_size()
{
array arr;
BEAST_EXPECT(arr.max_size() > 0);
}
// reserve()
{
array arr;
arr.reserve(50);
BEAST_EXPECT(arr.capacity() >= 50);
}
// capacity()
{
array arr;
BEAST_EXPECT(arr.capacity() == 0);
}
// shrink_to_fit()
{
array arr;
arr.reserve(50);
BEAST_EXPECT(arr.capacity() >= 50);
arr.shrink_to_fit();
BEAST_EXPECT(arr.capacity() == 0);
}
}
void
testModifiers()
{
// clear
{
array arr({1, true, "hello"});
arr.clear();
BEAST_EXPECT(arr.capacity() > 0);
}
// insert(before, value_type const&)
{
array arr({1, "hello"});
value v(true);
arr.insert(arr.begin() + 1, v);
check(arr);
}
// insert(before, value_type const&)
{
array arr({1, "hello"});
arr.insert(arr.begin() + 1, true);
check(arr);
}
// insert(before, size_type, value_type const&)
{
array arr({1, "hello"});
arr.insert(arr.begin() + 1, 3, true);
BEAST_EXPECT(arr[0].is_number());
BEAST_EXPECT(arr[1].is_bool());
BEAST_EXPECT(arr[2].is_bool());
BEAST_EXPECT(arr[3].is_bool());
BEAST_EXPECT(arr[4].is_string());
}
// insert(before, InputIt, InputIt)
{
std::initializer_list<
value> list = {1, true};
array arr({"hello"});
arr.insert(arr.begin(),
list.begin(), list.end());
check(arr);
}
// insert(before, init_list)
{
array arr({"hello"});
arr.insert(arr.begin(), {1, true});
check(arr);
}
// emplace(before, arg)
{
array arr({1, "hello"});
auto it = arr.emplace(
arr.begin() + 1, true);
BEAST_EXPECT(it == arr.begin() + 1);
check(arr);
}
// erase(pos)
{
array arr({1, true, nullptr, "hello"});
arr.erase(arr.begin() + 2);
check(arr);
}
// push_back(value const&)
{
array arr({1, true});
value v("hello");
arr.push_back(v);
BEAST_EXPECT(
v.as_string() == "hello");
check(arr);
}
// push_back(value&&)
{
array arr({1, true});
value v("hello");
arr.push_back(std::move(v));
BEAST_EXPECT(v.is_null());
check(arr);
}
// emplace_back(arg)
{
array arr({1, true});
arr.emplace_back("hello");
check(arr);
}
// pop_back()
{
array arr({1, true, "hello", nullptr});
arr.pop_back();
check(arr);
}
// resize(size_type)
{
array arr;
arr.resize(3);
BEAST_EXPECT(arr.size() == 3);
BEAST_EXPECT(arr[0].is_null());
BEAST_EXPECT(arr[1].is_null());
BEAST_EXPECT(arr[2].is_null());
}
// resize(size_type, value_type const&)
{
array arr;
value v(kind::boolean);
arr.resize(3, v);
BEAST_EXPECT(arr.size() == 3);
BEAST_EXPECT(arr[0].is_bool());
BEAST_EXPECT(arr[1].is_bool());
BEAST_EXPECT(arr[2].is_bool());
}
// swap
{
array arr1({1, true, "hello"});
array arr2;
arr1.swap(arr2);
check(arr2);
BEAST_EXPECT(arr1.empty());
}
}
void
testExceptions()
{
// operator=(array const&)
{
array arr0({1, true, "hello"});
fail_storage fs;
storage_ptr sp(&fs);
array arr1;
while(fs.fail < 200)
{
try
{
array arr(sp);
arr.emplace_back(nullptr);
arr = arr0;
arr1 = arr;
break;
}
catch(std::bad_alloc const&)
{
}
}
check(arr1);
}
// operator=(init_list)
{
std::initializer_list<value> list(
{1, true, "hello"});
fail_storage fs;
storage_ptr sp(&fs);
array arr1;
while(fs.fail < 200)
{
try
{
array arr(sp);
arr.emplace_back(nullptr);
arr = list;
arr1 = arr;
break;
}
catch(std::bad_alloc const&)
{
}
}
check(arr1);
}
// insert(before, count, value_type const&)
{
fail_storage fs;
storage_ptr sp(&fs);
array arr1;
while(fs.fail < 200)
{
try
{
array arr({1, true}, sp);
arr.insert(arr.begin() + 1,
3, kind::null);
arr1 = arr;
break;
}
catch(std::bad_alloc const&)
{
}
}
BEAST_EXPECT(arr1.size() == 5);
BEAST_EXPECT(arr1[0].is_number());
BEAST_EXPECT(arr1[1].is_null());
BEAST_EXPECT(arr1[2].is_null());
BEAST_EXPECT(arr1[3].is_null());
BEAST_EXPECT(arr1[4].is_bool());
}
#if _ITERATOR_DEBUG_LEVEL == 0
// insert(before, InputIt, InputIt)
{
std::initializer_list<value> list(
{1, true, "hello"});
fail_storage fs;
storage_ptr sp(&fs);
array arr1;
while(fs.fail < 200)
{
try
{
array arr(sp);
arr.insert(arr.end(),
list.begin(), list.end());
arr1 = arr;
break;
}
catch(std::bad_alloc const&)
{
}
}
check(arr1);
}
#endif
// emplace(before, arg)
{
fail_storage fs;
storage_ptr sp(&fs);
array arr1;
while(fs.fail < 200)
{
try
{
array arr({1, nullptr}, sp);
arr.emplace(arr.begin() + 1, true);
arr1 = arr;
break;
}
catch(std::bad_alloc const&)
{
}
}
BEAST_EXPECT(arr1.size() == 3);
BEAST_EXPECT(arr1[0].is_number());
BEAST_EXPECT(arr1[1].is_bool());
BEAST_EXPECT(arr1[2].is_null());
}
#if _ITERATOR_DEBUG_LEVEL == 0
// emplace(before, arg)
{
fail_storage fs;
storage_ptr sp(&fs);
array arr1;
while(fs.fail < 200)
{
try
{
array arr({1, "hello"}, sp);
arr.emplace(arr.begin() + 1, true);
arr1 = arr;
break;
}
catch(std::bad_alloc const&)
{
}
}
check(arr1);
BEAST_EXPECT(arr1.size() == 3);
BEAST_EXPECT(arr1[0].is_number());
BEAST_EXPECT(arr1[1].is_bool());
BEAST_EXPECT(arr1[2].is_string());
}
#endif
}
void
run() override
{
testSpecial();
testElements();
testIterators();
testCapacity();
testModifiers();
testExceptions();
}
};
BEAST_DEFINE_TESTSUITE(beast,json,array);
} // json
} // beast
} // boost

49
test/assign_string.cpp Normal file
View File

@@ -0,0 +1,49 @@
//
// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/json
//
// Test that header file is self-contained.
#include <boost/json/assign_string.hpp>
#include <boost/beast/_experimental/unit_test/suite.hpp>
#include <type_traits>
namespace boost {
namespace beast {
namespace json {
class assign_string_test : public unit_test::suite
{
public:
void
testAssign()
{
value jv = "test";
std::string s;
try
{
jv.store(s);
BEAST_EXPECT(s == "test");
}
catch(std::exception const&)
{
BEAST_FAIL();
}
}
void run() override
{
testAssign();
}
};
BEAST_DEFINE_TESTSUITE(beast,json,assign_string);
} // json
} // beast
} // boost

58
test/assign_vector.cpp Normal file
View File

@@ -0,0 +1,58 @@
//
// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/json
//
// Test that header file is self-contained.
#include <boost/json/assign_vector.hpp>
#include <boost/beast/_experimental/unit_test/suite.hpp>
#include <type_traits>
namespace boost {
namespace beast {
namespace json {
class assign_vector_test : public unit_test::suite
{
public:
void
testAssign()
{
value jv(kind::array);
{
auto& a = jv.as_array();
a.push_back(1);
a.push_back(2);
a.push_back(3);
}
std::vector<int> v;
try
{
jv.store(v);
BEAST_EXPECT(v.size() == 3);
BEAST_EXPECT(v[0] == 1);
BEAST_EXPECT(v[1] == 2);
BEAST_EXPECT(v[2] == 3);
}
catch(std::exception const&)
{
BEAST_FAIL();
}
}
void run() override
{
testAssign();
}
};
BEAST_DEFINE_TESTSUITE(beast,json,assign_vector);
} // json
} // beast
} // boost

322
test/basic_parser.cpp Normal file
View File

@@ -0,0 +1,322 @@
//
// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/json
//
// Test that header file is self-contained.
#include <boost/json/basic_parser.hpp>
#include <boost/beast/_experimental/unit_test/suite.hpp>
#include <boost/beast/core/buffers_range.hpp>
#include <boost/beast/core/error.hpp>
#include <boost/beast/core/string.hpp>
#include <boost/asio/buffer.hpp>
namespace boost {
namespace beast {
namespace json {
class basic_parser_test : public beast::unit_test::suite
{
public:
struct test_parser
: basic_parser
{
test_parser() = default;
void
on_document_begin(
error_code&) override
{
}
void
on_object_begin(
error_code&) override
{
}
void
on_object_end(
error_code&) override
{
}
void
on_array_begin(
error_code&) override
{
}
void
on_array_end(
error_code&) override
{
}
void
on_key_data(
string_view,
error_code&) override
{
}
void
on_key_end(
string_view,
error_code&) override
{
}
void
on_string_data(
string_view,
error_code&) override
{
}
void
on_string_end(
string_view,
error_code&) override
{
}
void
on_number(
number,
error_code&) override
{
}
void
on_bool(
bool,
error_code&) override
{
}
void
on_null(error_code&) override
{
}
};
void
good(string_view s)
{
error_code ec;
for(std::size_t i = 0;
i < s.size() - 1; ++i)
{
// write_some with 1 buffer
{
test_parser p;
auto used = p.write_some(
net::const_buffer(s.data(), i), ec);
BEAST_EXPECT(used == i);
BEAST_EXPECT(! p.is_done());
if(! BEAST_EXPECTS(! ec, ec.message()))
continue;
used = p.write_some(net::const_buffer(
s.data() + i, s.size() - i), ec);
BEAST_EXPECT(used == s.size() - i);
if(! BEAST_EXPECTS(! ec, ec.message()))
continue;
p.write({}, ec);
BEAST_EXPECTS(! ec, ec.message());
BEAST_EXPECT(p.is_done());
}
// write_some with 1 buffer sequence
{
test_parser p;
std::array<
net::const_buffer, 2> b;
b[0] = {s.data(), i};
b[1] = {s.data()+i, s.size()-i};
auto used = p.write_some(b, ec);
BEAST_EXPECT(used = s.size());
BEAST_EXPECTS(! ec, ec.message());
p.write({}, ec);
BEAST_EXPECTS(! ec, ec.message());
}
// write with 1 buffer sequence
{
test_parser p;
std::array<
net::const_buffer, 2> b;
b[0] = {s.data(), i};
b[1] = {s.data()+i, s.size()-i};
auto used = p.write(b, ec);
BEAST_EXPECT(used = s.size());
BEAST_EXPECTS(! ec, ec.message());
}
// write with 1 buffer
{
test_parser p;
auto used = p.write(
{s.data(), s.size()}, ec);
BEAST_EXPECT(used = s.size());
BEAST_EXPECTS(! ec, ec.message());
}
}
}
void
bad(string_view s)
{
error_code ec;
test_parser p;
auto const used = p.write_some(
boost::asio::const_buffer(
s.data(), s.size()), ec);
if(! ec)
{
if(p.is_done())
{
if(BEAST_EXPECT(used != s.size()))
return;
}
else
{
p.write_eof(ec);
if(BEAST_EXPECT(ec))
return;
}
}
else
{
pass();
return;
}
log << "fail: \"" << s << "\"\n";
}
void
testObject()
{
good("{}");
good("{ }");
good("{ \t }");
good("{ \"x\" : null }");
good("{ \"x\" : {} }");
good("{ \"x\" : { \"y\" : null } }");
bad ("{");
bad ("{{}}");
}
void
testArray()
{
good("[]");
good("[ ]");
good("[ \t ]");
good("[ \"\" ]");
good("[ \" \" ]");
good("[ \"x\" ]");
good("[ \"x\", \"y\" ]");
bad ("[");
bad ("[ \"x\", ]");
}
void
testString()
{
good("\"" "x" "\"");
good("\"" "xy" "\"");
good("\"" "x y" "\"");
bad ("\"" "\t" "\"");
}
void
testNumber()
{
good("0");
good("0.0");
good("0.10");
good("0.01");
good("1");
good("10");
good("1.5");
good("10.5");
good("10.25");
good("10.25e0");
good("1e1");
good("1e10");
good("1e+0");
good("1e+1");
good("0e+10");
good("0e-0");
good("0e-1");
good("0e-10");
good("1E+1");
good("-0");
good("-1");
good("-1e1");
bad ("");
bad ("-");
bad ("00");
bad ("00.");
bad ("00.0");
bad ("1a");
bad (".");
bad ("1.");
bad ("1+");
bad ("0.0+");
bad ("0.0e+");
bad ("0.0e-");
bad ("0.0e0-");
bad ("0.0e");
}
void
testMonostates()
{
good("true");
good(" true");
good("true ");
good("\ttrue");
good("true\t");
good("\r\n\t true\r\n\t ");
bad ("truu");
bad ("tu");
bad ("t");
good("false");
bad ("fals");
bad ("fel");
bad ("f");
good("null");
bad ("nul");
bad ("no");
bad ("n");
}
void run() override
{
log <<
"sizeof(basic_parser) == " <<
sizeof(basic_parser) << "\n";
testObject();
testArray();
testString();
testNumber();
testMonostates();
}
};
BEAST_DEFINE_TESTSUITE(beast,json,basic_parser);
} // json
} // beast
} // boost

70
test/error.cpp Normal file
View File

@@ -0,0 +1,70 @@
//
// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/json
//
// Test that header file is self-contained.
#include <boost/json/error.hpp>
#include <boost/beast/_experimental/unit_test/suite.hpp>
#include <memory>
namespace boost {
namespace beast {
namespace json {
class error_test : public unit_test::suite
{
public:
void check(error e)
{
auto const ec = make_error_code(e);
ec.category().name();
BEAST_EXPECT(! ec.message().empty());
}
void check(condition c, error e)
{
{
auto const ec = make_error_code(e);
BEAST_EXPECT(ec.category().name() != nullptr);
BEAST_EXPECT(! ec.message().empty());
BEAST_EXPECT(ec == c);
}
{
auto ec = make_error_condition(c);
BEAST_EXPECT(ec.category().name() != nullptr);
BEAST_EXPECT(! ec.message().empty());
BEAST_EXPECT(ec == c);
}
}
void run() override
{
check(condition::parse_error, error::syntax);
check(condition::parse_error, error::extra_data);
check(condition::parse_error, error::mantissa_overflow);
check(condition::parse_error, error::exponent_overflow);
check(condition::parse_error, error::too_deep);
check(condition::assign_error, error::integer_overflow);
check(condition::assign_error, error::expected_object);
check(condition::assign_error, error::expected_array);
check(condition::assign_error, error::expected_string);
check(condition::assign_error, error::expected_number);
check(condition::assign_error, error::expected_bool);
check(condition::assign_error, error::expected_null);
check(error::key_not_found);
}
};
BEAST_DEFINE_TESTSUITE(beast,json,error);
} // json
} // beast
} // boost

119
test/iterator.cpp Normal file
View File

@@ -0,0 +1,119 @@
//
// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/json
//
// Test that header file is self-contained.
#include <boost/json/iterator.hpp>
#include <boost/beast/_experimental/unit_test/suite.hpp>
namespace boost {
namespace beast {
namespace json {
class iterator_test : public beast::unit_test::suite
{
public:
void
testIterator()
{
value jv = {
{"pi", 3.141},
{"happy", true},
{"name", "Niels"},
{"nothing", nullptr},
{"answer", {
{"everything", 42}
}},
#if 0
{"list", {1, 0, 2}},
{"object", {
{"currency", "USD"},
{"value", 42.99}
}}
#endif
};
auto& arr = jv.as_object().
emplace("arr", kind::array).first->second.as_array();
arr.emplace_back(1);
arr.emplace_back(2);
arr.emplace_back(3);
const_iterator it(jv);
while(it != end)
{
auto const& e = *it;
log << std::string(e.depth*4, ' ');
if(! e.end)
{
if(! e.key.empty())
log << "\"" << e.key << "\" : ";
switch(e.value.kind())
{
case kind::object:
log << "{";
break;
case kind::array:
log << "[";
break;
case kind::string:
log << '\"' << e.value.as_string() << "\"";
if(! e.last)
log << ",";
break;
case kind::number:
log << e.value.as_number();
if(! e.last)
log << ",";
break;
case kind::boolean:
log << (e.value.as_bool() ?
"true" : "false");
if(! e.last)
log << ",";
break;
case kind::null:
log << "null";
if(! e.last)
log << ",";
break;
}
log.flush();
}
else if(e->value.is_object())
{
log << "}";
if(! e.last)
log << ",";
}
else if(e->value.is_array())
{
log << "]";
if(! e.last)
log << ",";
}
log << "\n";
log.flush();
++it;
}
}
void
run() override
{
testIterator();
pass();
}
};
BEAST_DEFINE_TESTSUITE(beast,json,iterator);
} // json
} // beast
} // boost

11
test/json.cpp Normal file
View File

@@ -0,0 +1,11 @@
//
// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/vinniefalco/BeastLounge
//
// Test that header file is self-contained.
#include <boost/json.hpp>

42
test/kind.cpp Normal file
View File

@@ -0,0 +1,42 @@
//
// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/json
//
// Test that header file is self-contained.
#include <boost/json/kind.hpp>
#include <boost/beast/_experimental/unit_test/suite.hpp>
#include <type_traits>
namespace boost {
namespace beast {
namespace json {
class kind_test : public unit_test::suite
{
public:
BOOST_STATIC_ASSERT(
std::is_enum<kind>::value);
void
testEnum()
{
pass();
}
void run() override
{
testEnum();
}
};
BEAST_DEFINE_TESTSUITE(beast,json,kind);
} // json
} // beast
} // boost

11
test/lib.cpp Normal file
View File

@@ -0,0 +1,11 @@
//
// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/json
//
#include <boost/beast/_experimental/unit_test/main.ipp>

324
test/number.cpp Normal file
View File

@@ -0,0 +1,324 @@
//
// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/json
//
// Test that header file is self-contained.
#include <boost/json/number.hpp>
#include <boost/beast/_experimental/unit_test/suite.hpp>
#include <boost/beast/core/static_string.hpp>
#include <cmath>
namespace boost {
namespace beast {
namespace json {
class number_test : public unit_test::suite
{
public:
template<class I>
void
check(I v
,typename std::enable_if<
std::is_signed<I>::value &&
std::is_integral<I>::value
>::type* = 0) noexcept
{
number n(v);
number n2(0);
n2 = n;
BEAST_EXPECT(n == n2);
BEAST_EXPECT(n.is_int64());
BEAST_EXPECT(n.get_int64() == v);
BEAST_EXPECT(n.get_double() == v);
}
template<class U>
void
check(U v
,typename std::enable_if<
std::is_unsigned<U>::value
>::type* = 0) noexcept
{
number n(v);
number n2(0);
n2 = n;
BEAST_EXPECT(n == n2);
BEAST_EXPECT(n.is_uint64());
BEAST_EXPECT(number(static_cast<
number::mantissa_type>(v),
0, false) == n);
BEAST_EXPECT(n.get_uint64() == v);
BEAST_EXPECT(n.get_double() == v);
}
template<class F>
void
check(F v
,typename std::enable_if<
std::is_floating_point<
F>::value>::type* = 0) noexcept
{
number n(v);
number n2(0);
n2 = n;
BEAST_EXPECT(n == n2);
BEAST_EXPECT(static_cast<F>(
n.get_double()) == v);
}
template<class F>
void
approx(F v) noexcept
{
number n(v);
number n2(0);
n2 = n;
BEAST_EXPECT(n == n2);
// VFALCO Unfortunately the results are not
// quite exact due to power of 10 conversion.
#if 0
auto v1 = n.get_double();
auto const d = std::fabs(v1 - v);
BEAST_EXPECT(static_cast<F>(
n.get_double()) == v);
#endif
}
void
testConstruction()
{
// Only perform light checking on
// the result of the construction.
{
number n((short)1);
BEAST_EXPECT(n.get_int64() == 1);
}
{
number n((int)2);
BEAST_EXPECT(n.get_int64() == 2);
}
{
number n((long)3);
BEAST_EXPECT(n.get_int64() == 3);
}
{
number n((long long)4);
BEAST_EXPECT(n.get_int64() == 4);
}
{
number n((unsigned short)1);
BEAST_EXPECT(n.get_uint64() == 1);
}
{
number n((unsigned int)2);
BEAST_EXPECT(n.get_uint64() == 2);
}
{
number n((unsigned long)3);
BEAST_EXPECT(n.get_uint64() == 3);
}
{
number n((unsigned long long)4);
BEAST_EXPECT(n.get_uint64() == 4);
}
{
number n((float)1.5f);
BEAST_EXPECT(n.get_double() == 1.5);
}
{
number n((double)2.5);
BEAST_EXPECT(n.get_double() == 2.5);
}
}
void
testAssignment()
{
// Only perform light checking on
// the result of the construction.
{
number n;
n = (short)1;
BEAST_EXPECT(n.get_int64() == 1);
n = (int)2;
BEAST_EXPECT(n.get_int64() == 2);
n = (long)3;
BEAST_EXPECT(n.get_int64() == 3);
n = (long long)4;
BEAST_EXPECT(n.get_int64() == 4);
n = (unsigned short)5;
BEAST_EXPECT(n.get_uint64() == 5);
n = (unsigned int)6;
BEAST_EXPECT(n.get_uint64() == 6);
n = (unsigned long)7;
BEAST_EXPECT(n.get_uint64() == 7);
n = (unsigned long long)8;
BEAST_EXPECT(n.get_uint64() == 8);
n = (float)1.5;
BEAST_EXPECT(n.get_double() == 1.5);
n = (double)2.5;
BEAST_EXPECT(n.get_double() == 2.5);
n = (double)3.5l;
BEAST_EXPECT(n.get_double() == 3.5);
}
}
void
testComparison()
{
// Only perform light checking on
// the result of the comparison.
number n = 1;
BEAST_EXPECT(n == ((short)1));
BEAST_EXPECT(n == ((int)1));
BEAST_EXPECT(n == ((long)1));
BEAST_EXPECT(n == ((long long)1));
BEAST_EXPECT(n == ((unsigned short)1));
BEAST_EXPECT(n == ((unsigned int)1));
BEAST_EXPECT(n == ((unsigned long)1));
BEAST_EXPECT(n == ((unsigned long long)1));
n = 1.f;
BEAST_EXPECT(n == 1.f);
n = 1.;
BEAST_EXPECT(n == 1.);
}
void
testValues()
{
// Test the range of each convertible numeric
// type, make sure they round-trip correctly.
check(1.0/7);
check((std::numeric_limits<short>::min)());
check((std::numeric_limits<short>::max)());
check((std::numeric_limits<short>::min)());
check((std::numeric_limits<short>::max)());
check((std::numeric_limits<int>::min)());
check((std::numeric_limits<int>::max)());
check((std::numeric_limits<int>::min)()/2);
check((std::numeric_limits<int>::max)()/2);
check((std::numeric_limits<long>::min)());
check((std::numeric_limits<long>::max)());
check((std::numeric_limits<long>::min)()/2);
check((std::numeric_limits<long>::max)()/2);
check((std::numeric_limits<long long>::min)());
check((std::numeric_limits<long long>::max)());
check((std::numeric_limits<long long>::min)()/2);
check((std::numeric_limits<long long>::max)()/2);
check((std::numeric_limits<unsigned short>::min)());
check((std::numeric_limits<unsigned short>::max)());
check((std::numeric_limits<unsigned short>::min)()/2);
check((std::numeric_limits<unsigned short>::max)()/2);
check((std::numeric_limits<unsigned int>::min)());
check((std::numeric_limits<unsigned int>::max)());
check((std::numeric_limits<unsigned int>::min)()/2);
check((std::numeric_limits<unsigned int>::max)()/2);
check((std::numeric_limits<unsigned long>::min)());
check((std::numeric_limits<unsigned long>::max)());
check((std::numeric_limits<unsigned long>::min)()/2);
check((std::numeric_limits<unsigned long>::max)()/2);
check((std::numeric_limits<unsigned long long>::min)());
check((std::numeric_limits<unsigned long long>::max)());
check((std::numeric_limits<unsigned long long>::min)()/2);
check((std::numeric_limits<unsigned long long>::max)()/2);
check((std::numeric_limits<float>::min)());
check((std::numeric_limits<float>::max)());
check((std::numeric_limits<float>::min)()/2);
check((std::numeric_limits<float>::max)()/2);
check((std::numeric_limits<double>::min)());
check((std::numeric_limits<double>::max)());
check((std::numeric_limits<double>::min)()/2);
// not exact
approx((std::numeric_limits<double>::max)()/2);
}
template<class V>
void
check_output(V v)
{
char buf[number::max_string_chars];
auto const s = number(v).print(buf, sizeof(buf));
BEAST_EXPECTS(
s == std::to_string(v).c_str(),
std::string(s.data(), s.size()));
}
void
testOstream()
{
check_output(1);
check_output(2);
check_output(3);
// These don't match std::to_string
/*
check_output(1.5f);
check_output(2.5);
check_output(3.5l);
*/
check_output((std::numeric_limits<short>::min)());
check_output((std::numeric_limits<short>::max)());
check_output((std::numeric_limits<short>::min)());
check_output((std::numeric_limits<short>::max)());
check_output((std::numeric_limits<int>::min)());
check_output((std::numeric_limits<int>::max)());
check_output((std::numeric_limits<int>::min)()/2);
check_output((std::numeric_limits<int>::max)()/2);
check_output((std::numeric_limits<long>::min)());
check_output((std::numeric_limits<long>::max)());
check_output((std::numeric_limits<long>::min)()/2);
check_output((std::numeric_limits<long>::max)()/2);
check_output((std::numeric_limits<long long>::min)());
check_output((std::numeric_limits<long long>::max)());
check_output((std::numeric_limits<long long>::min)()/2);
check_output((std::numeric_limits<long long>::max)()/2);
check_output((std::numeric_limits<unsigned short>::min)());
check_output((std::numeric_limits<unsigned short>::max)());
check_output((std::numeric_limits<unsigned short>::min)()/2);
check_output((std::numeric_limits<unsigned short>::max)()/2);
check_output((std::numeric_limits<unsigned int>::min)());
check_output((std::numeric_limits<unsigned int>::max)());
check_output((std::numeric_limits<unsigned int>::min)()/2);
check_output((std::numeric_limits<unsigned int>::max)()/2);
check_output((std::numeric_limits<unsigned long>::min)());
check_output((std::numeric_limits<unsigned long>::max)());
check_output((std::numeric_limits<unsigned long>::min)()/2);
check_output((std::numeric_limits<unsigned long>::max)()/2);
check_output((std::numeric_limits<unsigned long long>::min)());
check_output((std::numeric_limits<unsigned long long>::max)());
check_output((std::numeric_limits<unsigned long long>::min)()/2);
check_output((std::numeric_limits<unsigned long long>::max)()/2);
}
void
run() override
{
testConstruction();
testAssignment();
testComparison();
testValues();
testOstream();
}
};
BEAST_DEFINE_TESTSUITE(beast,json,number);
} // json
} // beast
} // boost

1060
test/object.cpp Normal file

File diff suppressed because it is too large Load Diff

11
test/parse_file.cpp Normal file
View File

@@ -0,0 +1,11 @@
//
// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/vinniefalco/BeastLounge
//
// Test that header file is self-contained.
#include <boost/json/parse_file.hpp>

84
test/parser.cpp Normal file
View File

@@ -0,0 +1,84 @@
//
// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/vinniefalco/BeastLounge
//
// Test that header file is self-contained.
#include <boost/json/parser.hpp>
#include <boost/beast/_experimental/unit_test/suite.hpp>
#include <boost/json/parser.hpp>
#include <sstream>
namespace boost {
namespace beast {
namespace json {
class parser_test : public unit_test::suite
{
public:
void
testParser()
{
string_view in =
R"xx({
"glossary": {
"title": "example glossary",
"GlossDiv": {
"title": "S",
"GlossList": {
"GlossEntry": {
"ID": "SGML",
"SortAs": "SGML",
"GlossTerm": "Standard Generalized Markup Language",
"Acronym": "SGML",
"Abbrev": "ISO 8879:1986",
"GlossDef": {
"para": "A meta-markup language, used to create markup languages such as DocBook.",
"GlossSeeAlso": ["GML", "XML"]
},
"GlossSee": "markup"
}
}
}
}
})xx"
;
parser p;
error_code ec;
p.write({in.data(), in.size()}, ec);
if(BEAST_EXPECTS(! ec, ec.message()))
{
std::stringstream ss;
ss << p.get();
BEAST_EXPECT(ss.str() ==
"{\"glossary\":{\"title\":\"example glossary\",\"GlossDiv\":"
"{\"title\":\"S\",\"GlossList\":{\"GlossEntry\":{\"ID\":\"SGML\","
"\"SortAs\":\"SGML\",\"GlossTerm\":\"Standard Generalized Markup "
"Language\",\"Acronym\":\"SGML\",\"Abbrev\":\"ISO 8879:1986\","
"\"GlossDef\":{\"para\":\"A meta-markup language, used to create "
"markup languages such as DocBook.\",\"GlossSeeAlso\":[\"GML\",\"XML\"]},"
"\"GlossSee\":\"markup\"}}}}}"
);
}
}
void
run()
{
log <<
"sizeof(parser) == " <<
sizeof(parser) << "\n";
testParser();
}
};
BEAST_DEFINE_TESTSUITE(beast,json,parser);
} // json
} // beast
} // boost

68
test/serializer.cpp Normal file
View File

@@ -0,0 +1,68 @@
//
// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/vinniefalco/BeastLounge
//
// Test that header file is self-contained.
#include <boost/json/serializer.hpp>
#include <boost/beast/_experimental/unit_test/suite.hpp>
namespace boost {
namespace beast {
namespace json {
class serializer_test : public unit_test::suite
{
public:
void
testSerializer()
{
value jv = {
{"pi", 3.141},
{"happy", true},
{"name", "Niels"},
{"nothing", nullptr},
{"answer", {
{"everything", 42}
}},
#if 0
{"list", {1, 0, 2}},
{"object", {
{"currency", "USD"},
{"value", 42.99}
}}
#endif
};
auto& arr = jv.as_object().
emplace("arr", kind::array).first->second.as_array();
arr.emplace_back(1);
arr.emplace_back(2);
arr.emplace_back(3);
serializer sr(jv);
char buf[2048];
auto const n =
sr.next({buf, sizeof(buf)});
string_view s(buf, n);
log << s << "\n";
}
void
run()
{
testSerializer();
pass();
}
};
BEAST_DEFINE_TESTSUITE(beast,json,serializer);
} // json
} // beast
} // boost

191
test/storage.cpp Normal file
View File

@@ -0,0 +1,191 @@
//
// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/json
//
// Test that header file is self-contained.
#include <boost/json/storage.hpp>
#include <boost/beast/_experimental/unit_test/suite.hpp>
#include <boost/json/detail/storage_adaptor.hpp>
namespace boost {
namespace beast {
namespace json {
class storage_test : public unit_test::suite
{
public:
struct unique_storage : storage
{
void
addref() noexcept override
{
}
void
release() noexcept override
{
}
void*
allocate(
std::size_t n,
std::size_t) override
{
return std::allocator<
char>{}.allocate(n);
}
void
deallocate(
void* p,
std::size_t n,
std::size_t) noexcept override
{
auto cp =
reinterpret_cast<char*>(p);
return std::allocator<
char>{}.deallocate(cp, n);
}
bool
is_equal(
storage const& other
) const noexcept override
{
auto p = dynamic_cast<
unique_storage const*>(&other);
if(! p)
return false;
return this == p;
}
};
void
testStoragePtr()
{
auto p = new detail::storage_adaptor<
std::allocator<char>>({});
// default ctor
{
storage_ptr s;
BEAST_EXPECT(s == nullptr);
}
// move ctor
{
p->addref();
storage_ptr s1(p);
storage_ptr s2(std::move(s1));
BEAST_EXPECT(s1 == nullptr);
BEAST_EXPECT(s2 == p);
}
// copy ctor
{
p->addref();
storage_ptr s1(p);
storage_ptr s2(s1);
BEAST_EXPECT(s1 == p);
BEAST_EXPECT(s2 == p);
BEAST_EXPECT(s1 == s2);
}
// move assign
{
p->addref();
storage_ptr s1(p);
storage_ptr s2;
s2 = std::move(s1);
BEAST_EXPECT(s1 == nullptr);
BEAST_EXPECT(s2 == p);
}
// copy assign
{
p->addref();
storage_ptr s1(p);
storage_ptr s2;
s2 = s1;
BEAST_EXPECT(s1 == p);
BEAST_EXPECT(s2 == p);
BEAST_EXPECT(s1 == s2);
}
// construction
{
p->addref();
storage_ptr sp(p);
BEAST_EXPECT(sp == p);
}
// release
{
p->addref();
storage_ptr sp(
storage_ptr{p}.release());
BEAST_EXPECT(sp == p);
}
// bool, get, ->, *
{
p->addref();
storage_ptr sp(p);
BEAST_EXPECT(sp);
BEAST_EXPECT(sp.get() == p);
BEAST_EXPECT(sp.operator->() == p);
BEAST_EXPECT(&sp.operator*() == p);
sp = nullptr;
BEAST_EXPECT(! sp);
}
// converting assignment
{
p->addref();
storage_ptr sp;
sp = p;
BEAST_EXPECT(sp == p);
sp = nullptr;
BEAST_EXPECT(! sp);
}
// equality
{
unique_storage us1;
unique_storage us2;
storage_ptr spu1(&us1);
storage_ptr spu2(&us2);
storage_ptr sp = make_storage_ptr(
std::allocator<void>{});
storage_ptr spd =
default_storage();
BEAST_EXPECT(us1 != us2);
BEAST_EXPECT(us1 != *spd);
BEAST_EXPECT(us2 != *spd);
BEAST_EXPECT(us1 != *sp);
BEAST_EXPECT(us2 != *sp);
BEAST_EXPECT(
*spd == *default_storage());
BEAST_EXPECT(
*sp != *default_storage());
}
p->release();
}
void run() override
{
testStoragePtr();
}
};
BEAST_DEFINE_TESTSUITE(beast,json,storage);
} // json
} // beast
} // boost

33
test/string.cpp Normal file
View File

@@ -0,0 +1,33 @@
//
// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/vinniefalco/BeastLounge
//
// Test that header file is self-contained.
#include <boost/json/string.hpp>
#include <boost/beast/_experimental/unit_test/suite.hpp>
namespace boost {
namespace beast {
namespace json {
class string_test : public unit_test::suite
{
public:
void
run() override
{
pass();
}
};
BEAST_DEFINE_TESTSUITE(beast,json,string);
} // json
} // beast
} // boost

725
test/value.cpp Normal file
View File

@@ -0,0 +1,725 @@
//
// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/json
//
// Test that header file is self-contained.
#include <boost/json/value.hpp>
#include <boost/beast/_experimental/unit_test/suite.hpp>
#include <memory>
#include <vector>
namespace boost {
namespace beast {
namespace json {
namespace value_test_ns {
struct T1
{
void
to_json(value&) const
{
}
};
struct T2
{
};
void
to_json(T2 const&, value&)
{
}
struct T3
{
};
} // value_test_ns
template<>
struct value_exchange<value_test_ns::T3>
{
static
void
to_json(value_test_ns::T3, value&)
{
}
};
//------------------------------------------------------------------------------
class value_test : public unit_test::suite
{
public:
struct unique_storage : storage
{
void
addref() noexcept override
{
}
void
release() noexcept override
{
}
void*
allocate(
std::size_t n,
std::size_t) override
{
return std::allocator<
char>{}.allocate(n);
}
void
deallocate(
void* p,
std::size_t n,
std::size_t) noexcept override
{
auto cp =
reinterpret_cast<char*>(p);
return std::allocator<
char>{}.deallocate(cp, n);
}
bool
is_equal(
storage const& other
) const noexcept override
{
auto p = dynamic_cast<
unique_storage const*>(&other);
if(! p)
return false;
return this == p;
}
};
void
testSpecial()
{
// move ctor
{
value jv1;
value jv2(std::move(jv1));
}
// copy ctor
{
value jv1;
value jv2(jv1);
}
// move assign
{
value jv1;
value jv2;
jv2 = std::move(jv1);
}
// copy assign
{
value jv1;
value jv2;
jv2 = jv1;
}
}
void
testConstruct()
{
unique_storage us;
storage_ptr sp(&us);
storage_ptr sp0 =
default_storage();
// default ctor
{
value jv;
BEAST_EXPECT(jv.is_null());
BEAST_EXPECT(jv.get_storage() != sp);
BEAST_EXPECT(jv.get_storage() == sp0);
}
// storage ctor
{
value jv1(sp);
BEAST_EXPECT(jv1.is_null());
BEAST_EXPECT(jv1.get_storage() == sp);
BEAST_EXPECT(jv1.get_storage() != sp0);
auto sp2 = sp;
value jv2(std::move(sp2));
BEAST_EXPECT(jv2.is_null());
BEAST_EXPECT(jv1.get_storage() == sp);
BEAST_EXPECT(jv1.get_storage() != sp0);
BEAST_EXPECT(jv2.get_storage() == sp);
BEAST_EXPECT(jv2.get_storage() != sp0);
}
// kind construct
{
value jv(kind::object);
BEAST_EXPECT(jv.is_object());
BEAST_EXPECT(jv.get_storage() != sp);
BEAST_EXPECT(jv.get_storage() == sp0);
}
{
value jv(kind::array);
BEAST_EXPECT(jv.is_array());
BEAST_EXPECT(jv.get_storage() != sp);
BEAST_EXPECT(jv.get_storage() == sp0);
}
{
value jv(kind::string);
BEAST_EXPECT(jv.is_string());
BEAST_EXPECT(jv.get_storage() != sp);
BEAST_EXPECT(jv.get_storage() == sp0);
}
{
value jv(kind::number);
BEAST_EXPECT(jv.is_number());
BEAST_EXPECT(jv.get_storage() != sp);
BEAST_EXPECT(jv.get_storage() == sp0);
}
{
value jv(kind::boolean);
BEAST_EXPECT(jv.is_bool());
BEAST_EXPECT(jv.get_storage() != sp);
BEAST_EXPECT(jv.get_storage() == sp0);
}
{
value jv(kind::null);
BEAST_EXPECT(jv.is_null());
BEAST_EXPECT(jv.get_storage() != sp);
BEAST_EXPECT(jv.get_storage() == sp0);
}
// kind, storage construct
{
value jv(kind::object, sp);
BEAST_EXPECT(jv.is_object());
BEAST_EXPECT(jv.get_storage() == sp);
BEAST_EXPECT(jv.get_storage() != sp0);
}
{
value jv(kind::array, sp);
BEAST_EXPECT(jv.is_array());
BEAST_EXPECT(jv.get_storage() == sp);
BEAST_EXPECT(jv.get_storage() != sp0);
}
{
value jv(kind::string, sp);
BEAST_EXPECT(jv.is_string());
BEAST_EXPECT(jv.get_storage() == sp);
BEAST_EXPECT(jv.get_storage() != sp0);
}
{
value jv(kind::number, sp);
BEAST_EXPECT(jv.is_number());
BEAST_EXPECT(jv.get_storage() == sp);
BEAST_EXPECT(jv.get_storage() != sp0);
}
{
value jv(kind::boolean, sp);
BEAST_EXPECT(jv.is_bool());
BEAST_EXPECT(jv.get_storage() == sp);
BEAST_EXPECT(jv.get_storage() != sp0);
}
{
value jv(kind::null, sp);
BEAST_EXPECT(jv.is_null());
BEAST_EXPECT(jv.get_storage() == sp);
BEAST_EXPECT(jv.get_storage() != sp0);
}
// construct from containers
{
{
object obj;
value jv(obj);
BEAST_EXPECT(jv.is_object());
BEAST_EXPECT(jv.get_storage() != sp);
BEAST_EXPECT(jv.get_storage() == sp0);
}
{
array arr;
value jv(arr);
BEAST_EXPECT(jv.is_array());
BEAST_EXPECT(jv.get_storage() != sp);
BEAST_EXPECT(jv.get_storage() == sp0);
}
{
string str;
value jv(str);
BEAST_EXPECT(jv.is_string());
BEAST_EXPECT(jv.get_storage() != sp);
BEAST_EXPECT(jv.get_storage() == sp0);
}
{
value jv(number(1));
BEAST_EXPECT(jv.is_number());
BEAST_EXPECT(jv.is_int64());
BEAST_EXPECT(jv.is_uint64());
BEAST_EXPECT(jv.is_double());
BEAST_EXPECT(jv.get_int64() == 1);
BEAST_EXPECT(jv.get_uint64() == 1);
BEAST_EXPECT(jv.get_double() == 1);
BEAST_EXPECT(jv.as_number() == 1);
BEAST_EXPECT(jv.get_storage() != sp);
BEAST_EXPECT(jv.get_storage() == sp0);
}
//
{
object obj;
value jv(obj, sp);
BEAST_EXPECT(jv.is_object());
BEAST_EXPECT(jv.get_storage() == sp);
BEAST_EXPECT(jv.get_storage() != sp0);
}
{
array arr;
value jv(arr, sp);
BEAST_EXPECT(jv.is_array());
BEAST_EXPECT(jv.get_storage() == sp);
BEAST_EXPECT(jv.get_storage() != sp0);
}
{
string str;
value jv(str, sp);
BEAST_EXPECT(jv.is_string());
BEAST_EXPECT(jv.get_storage() == sp);
BEAST_EXPECT(jv.get_storage() != sp0);
}
{
value jv(number(1), sp);
BEAST_EXPECT(jv.is_number());
BEAST_EXPECT(jv.is_int64());
BEAST_EXPECT(jv.is_uint64());
BEAST_EXPECT(jv.is_double());
BEAST_EXPECT(jv.get_int64() == 1);
BEAST_EXPECT(jv.get_uint64() == 1);
BEAST_EXPECT(jv.get_double() == 1);
BEAST_EXPECT(jv.as_number() == 1);
BEAST_EXPECT(jv.get_storage() == sp);
BEAST_EXPECT(jv.get_storage() != sp0);
}
}
// assign from containers
{
{
object obj;
value jv;
jv = obj;
BEAST_EXPECT(jv.is_object());
BEAST_EXPECT(jv.get_storage() != sp);
BEAST_EXPECT(jv.get_storage() == sp0);
jv.reset();
BEAST_EXPECT(jv.is_null());
BEAST_EXPECT(jv.get_storage() != sp);
BEAST_EXPECT(jv.get_storage() == sp0);
jv = std::move(obj);
BEAST_EXPECT(jv.is_object());
BEAST_EXPECT(jv.get_storage() != sp);
BEAST_EXPECT(jv.get_storage() == sp0);
}
{
object obj;
value jv(sp);
jv = obj;
BEAST_EXPECT(jv.is_object());
BEAST_EXPECT(jv.get_storage() == sp);
BEAST_EXPECT(jv.get_storage() != sp0);
jv.reset();
BEAST_EXPECT(jv.is_null());
BEAST_EXPECT(jv.get_storage() == sp);
BEAST_EXPECT(jv.get_storage() != sp0);
jv = std::move(obj);
BEAST_EXPECT(jv.is_object());
BEAST_EXPECT(jv.get_storage() == sp);
BEAST_EXPECT(jv.get_storage() != sp0);
}
{
array arr;
value jv;
jv = arr;
BEAST_EXPECT(jv.is_array());
BEAST_EXPECT(jv.get_storage() != sp);
BEAST_EXPECT(jv.get_storage() == sp0);
jv.reset();
BEAST_EXPECT(jv.is_null());
BEAST_EXPECT(jv.get_storage() != sp);
BEAST_EXPECT(jv.get_storage() == sp0);
jv = std::move(arr);
BEAST_EXPECT(jv.is_array());
BEAST_EXPECT(jv.get_storage() != sp);
BEAST_EXPECT(jv.get_storage() == sp0);
}
{
array arr;
value jv(sp);
jv = arr;
BEAST_EXPECT(jv.is_array());
BEAST_EXPECT(jv.get_storage() == sp);
BEAST_EXPECT(jv.get_storage() != sp0);
jv.reset();
BEAST_EXPECT(jv.is_null());
BEAST_EXPECT(jv.get_storage() == sp);
BEAST_EXPECT(jv.get_storage() != sp0);
jv = std::move(arr);
BEAST_EXPECT(jv.is_array());
BEAST_EXPECT(jv.get_storage() == sp);
BEAST_EXPECT(jv.get_storage() != sp0);
}
{
string str;
value jv;
jv = str;
BEAST_EXPECT(jv.is_string());
BEAST_EXPECT(jv.get_storage() != sp);
BEAST_EXPECT(jv.get_storage() == sp0);
jv.reset();
BEAST_EXPECT(jv.is_null());
BEAST_EXPECT(jv.get_storage() != sp);
BEAST_EXPECT(jv.get_storage() == sp0);
jv = std::move(str);
BEAST_EXPECT(jv.is_string());
BEAST_EXPECT(jv.get_storage() != sp);
BEAST_EXPECT(jv.get_storage() == sp0);
}
{
string str;
value jv(sp);
jv = str;
BEAST_EXPECT(jv.is_string());
BEAST_EXPECT(jv.get_storage() == sp);
BEAST_EXPECT(jv.get_storage() != sp0);
jv.reset();
BEAST_EXPECT(jv.is_null());
BEAST_EXPECT(jv.get_storage() == sp);
BEAST_EXPECT(jv.get_storage() != sp0);
jv = std::move(str);
BEAST_EXPECT(jv.is_string());
BEAST_EXPECT(jv.get_storage() == sp);
BEAST_EXPECT(jv.get_storage() != sp0);
}
{
number n(1);
value jv;
jv = n;
BEAST_EXPECT(jv.is_number());
BEAST_EXPECT(jv.is_int64());
BEAST_EXPECT(jv.is_uint64());
BEAST_EXPECT(jv.is_double());
BEAST_EXPECT(jv.get_int64() == 1);
BEAST_EXPECT(jv.get_uint64() == 1);
BEAST_EXPECT(jv.get_double() == 1);
BEAST_EXPECT(jv.as_number() == 1);
BEAST_EXPECT(jv.get_storage() != sp);
BEAST_EXPECT(jv.get_storage() == sp0);
}
{
number n(1);
value jv(sp);
jv = n;
BEAST_EXPECT(jv.is_number());
BEAST_EXPECT(jv.is_int64());
BEAST_EXPECT(jv.is_uint64());
BEAST_EXPECT(jv.is_double());
BEAST_EXPECT(jv.get_int64() == 1);
BEAST_EXPECT(jv.get_uint64() == 1);
BEAST_EXPECT(jv.get_double() == 1);
BEAST_EXPECT(jv.as_number() == 1);
BEAST_EXPECT(jv.get_storage() == sp);
BEAST_EXPECT(jv.get_storage() != sp0);
}
}
}
void
testModifiers()
{
// reset
{
value jv;
jv.reset(kind::object);
BEAST_EXPECT(jv.is_object());
jv.reset();
BEAST_EXPECT(jv.is_null());
jv.reset(kind::array);
BEAST_EXPECT(jv.is_array());
jv.reset(kind::string);
BEAST_EXPECT(jv.is_string());
jv.reset(kind::number);
BEAST_EXPECT(jv.is_number());
jv.reset(kind::boolean);
BEAST_EXPECT(jv.is_bool());
jv.reset(kind::null);
BEAST_EXPECT(jv.is_null());
}
// assign
{
value jv;
jv = kind::object;
BEAST_EXPECT(jv.is_object());
jv = kind::null;
BEAST_EXPECT(jv.is_null());
jv = kind::array;
BEAST_EXPECT(jv.is_array());
jv = kind::string;
BEAST_EXPECT(jv.is_string());
jv = kind::number;
BEAST_EXPECT(jv.is_number());
jv = kind::boolean;
BEAST_EXPECT(jv.is_bool());
jv = kind::null;
BEAST_EXPECT(jv.is_null());
}
// emplace
{
{
value jv;
object& obj = jv.emplace_object();
BEAST_EXPECT(jv.is_object());
obj.clear();
}
{
value jv;
array& arr = jv.emplace_array();
BEAST_EXPECT(jv.is_array());
arr.clear();
}
{
value jv;
string& str = jv.emplace_string();
BEAST_EXPECT(jv.is_string());
str.clear();
}
{
value jv;
number& n= jv.emplace_number();
BEAST_EXPECT(jv.is_number());
n = 0;
}
{
value jv;
bool& b= jv.emplace_bool();
BEAST_EXPECT(jv.is_bool());
b = false;
}
}
}
void
testExchange()
{
// construct from T
{
value v3("Hello!");
value(std::string("Hello!"));
value(short{0});
value(int{0});
value(long{0});
value((long long)0);
value((unsigned short)0);
value((unsigned int)0);
value((unsigned long)0);
value((unsigned long long)0);
value(float{0});
value(double{0});
value(true);
value(false);
value v4(null);
value(nullptr);
}
// assign from T
{
value jv;
jv = "Hello!";
jv = std::string("Hello!");
jv = short{};
jv = int{};
jv = long{};
jv = (long long)0;
jv = (unsigned short)0;
jv = (unsigned int)0;
jv = (unsigned long)0;
jv = (unsigned long long)0;
jv = float{};
jv = double{};
jv = true;
jv = false;
jv = null;
jv = nullptr;
}
}
void
testAccessors()
{
// raw
value jv;
value const& jc(jv);
{
jv = kind::object;
BEAST_EXPECT(
jv.as_object().size() == 0);
jc.as_object();
}
{
jv = kind::array;
BEAST_EXPECT(
jv.as_array().size() == 0);
jc.as_array();
}
{
jv = "x";
jv.as_string() = "y";
BEAST_EXPECT(jc.as_string() == "y");
}
{
jv = signed{};
BEAST_EXPECT(jc.get_int64() == 0);
jv.as_number() = -1;
BEAST_EXPECT(jc.get_int64() == -1);
}
{
jv = unsigned{};
jv.as_number() = 2;
BEAST_EXPECT(jc.get_uint64() == 2);
}
{
jv = bool{};
jv.as_bool() = true;
BEAST_EXPECT(jc.as_bool());
}
}
void
testStructured()
{
// empty()
{
value v;
v = kind::object;
BEAST_EXPECT(v.empty());
v = kind::array;
BEAST_EXPECT(v.empty());
}
// size()
{
value v;
v = kind::object;
v.as_object().emplace("x", 1);
BEAST_EXPECT(v.size() == 1);
v = kind::array;
v.as_array().emplace_back(1);
BEAST_EXPECT(v.size() == 1);
}
}
void
testCustomization()
{
using namespace value_test_ns;
// to_json
{
T1 t;
value jv(t);
}
{
T2 t;
value jv(t);
}
{
T3 t;
value jv(t);
}
}
BOOST_STATIC_ASSERT(
detail::is_range<std::vector<int>>::value);
BOOST_STATIC_ASSERT(
detail::is_range<std::initializer_list<int>>::value);
void run() override
{
log <<
"sizeof(value) == " <<
sizeof(value) << "\n";
log <<
"sizeof(object) == " <<
sizeof(object) << "\n";
log <<
"sizeof(array) == " <<
sizeof(array) << "\n";
log <<
"sizeof(string) == " <<
sizeof(string) << "\n";
log <<
"sizeof(number) == " <<
sizeof(number) << "\n";
testSpecial();
testConstruct();
testModifiers();
testExchange();
testAccessors();
testStructured();
testCustomization();
}
};
BEAST_DEFINE_TESTSUITE(beast,json,value);
} // json
} // beast
} // boost