diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index f8f6e76450..b1959460d3 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -20,8 +20,8 @@ jobs: EXTRA_CMAKE_ARGS: "" MARCH: "" PLATFORM: amd64 - LIB: "" - LIB_VERSION: "" + UHD_VERSION: "" + DPDK_VERSION: "" DOCKERFILE: ./docker/metrics_server/Dockerfile CONTEXT: ./docker/metrics_server # --> grafana @@ -30,64 +30,45 @@ jobs: EXTRA_CMAKE_ARGS: "" MARCH: "" PLATFORM: amd64 - LIB: "" - LIB_VERSION: "" + UHD_VERSION: "" + DPDK_VERSION: "" DOCKERFILE: ./docker/grafana/Dockerfile CONTEXT: ./docker/grafana - # --> split72 + # --> gnb # AMD AVX2 - - TAGNAME: split72_release_avx2 + - TAGNAME: release_avx2 REPOSITORY: srsran-project MARCH: x86-64-v3 PLATFORM: amd64 - LIB: dpdk - LIB_VERSION: "23.11.1" + UHD_VERSION: "4.7.0.0" + DPDK_VERSION: "23.11.1" DOCKERFILE: ./docker/Dockerfile CONTEXT: ./ - - TAGNAME: split72_release_with_debug_avx2 + - TAGNAME: release_with_debug_avx2 REPOSITORY: srsran-project EXTRA_CMAKE_ARGS: -DFORCE_DEBUG_INFO=On MARCH: x86-64-v3 PLATFORM: amd64 - LIB: dpdk - LIB_VERSION: "23.11.1" + UHD_VERSION: "4.7.0.0" + DPDK_VERSION: "23.11.1" DOCKERFILE: ./docker/Dockerfile CONTEXT: ./ # AMD AVX512 - - TAGNAME: split72_release_avx512 + - TAGNAME: release_avx512 REPOSITORY: srsran-project MARCH: x86-64-v4 PLATFORM: amd64 - LIB: dpdk - LIB_VERSION: "23.11.1" + UHD_VERSION: "4.7.0.0" + DPDK_VERSION: "23.11.1" DOCKERFILE: ./docker/Dockerfile CONTEXT: ./ - - TAGNAME: split72_release_with_debug_avx512 + - TAGNAME: release_with_debug_avx512 REPOSITORY: srsran-project EXTRA_CMAKE_ARGS: -DFORCE_DEBUG_INFO=On MARCH: x86-64-v4 PLATFORM: amd64 - LIB: dpdk - LIB_VERSION: "23.11.1" - DOCKERFILE: ./docker/Dockerfile - CONTEXT: ./ - # --> split8 - # AMD AVX2 - - TAGNAME: split8_release_avx2 - REPOSITORY: srsran-project - MARCH: x86-64-v3 - PLATFORM: amd64 - LIB: uhd - LIB_VERSION: "4.7.0.0" - DOCKERFILE: ./docker/Dockerfile - CONTEXT: ./ - - TAGNAME: split8_release_with_debug_avx2 - REPOSITORY: srsran-project - EXTRA_CMAKE_ARGS: -DFORCE_DEBUG_INFO=On - MARCH: x86-64-v3 - PLATFORM: amd64 - LIB: uhd - LIB_VERSION: "4.7.0.0" + UHD_VERSION: "4.7.0.0" + DPDK_VERSION: "23.11.1" DOCKERFILE: ./docker/Dockerfile CONTEXT: ./ env: @@ -142,6 +123,6 @@ jobs: context: ${{ matrix.CONTEXT }} build-args: | NAME="${{ env.NAME }}" - LIB=${{ matrix.LIB }} - LIB_VERSION=${{ matrix.LIB_VERSION }} + UHD_VERSION=${{ matrix.UHD_VERSION }} + DPDK_VERSION=${{ matrix.DPDK_VERSION }} MARCH=${{ matrix.MARCH }} diff --git a/.gitlab/ci-shared/build.yml b/.gitlab/ci-shared/build.yml index d8ebd804c1..3765a449a6 100644 --- a/.gitlab/ci-shared/build.yml +++ b/.gitlab/ci-shared/build.yml @@ -31,9 +31,6 @@ variables: BUILD_ARGS: description: It will be passed to cmake value: "" - MAKE_ARGS: - description: It will be passed to make - value: "" UHD_VERSION: description: must be one version supported in the specified OS value: "" @@ -85,6 +82,7 @@ variables: ENABLE_FFTW ENABLE_MKL ENABLE_ARMPL \ ENABLE_UHD ENABLE_DPDK ENABLE_ZEROMQ \ ENABLE_ASAN ENABLE_TSAN ENABLE_GCOV \ + ENABLE_UBSAN ENABLE_UBSAN_MIN ENABLE_RTSAN \ ENABLE_WERROR FORCE_DEBUG_INFO \ MARCH MTUNE \ ; do diff --git a/.gitlab/ci/build.yml b/.gitlab/ci/build.yml index 7b0c6c3590..a10cee792b 100644 --- a/.gitlab/ci/build.yml +++ b/.gitlab/ci/build.yml @@ -66,7 +66,6 @@ variables: echo "COMPILER=${COMPILER}" echo "TEST_MODE=${TEST_MODE}" echo "BUILD_ARGS=${CMAKE_FLAGS_CMD} ${BUILD_ARGS}" - echo "MAKE_ARGS=${MAKE_ARGS}" echo "UHD_VERSION=${UHD_VERSION}" echo "DPDK_VERSION=${DPDK_VERSION}" echo "SRS_TARGET=${SRS_TARGET}" @@ -269,17 +268,6 @@ variables: MARCH: x86-64-v3 INFRASTRUCTURE_TAG: amd64-avx2 -.smoke rhel: - extends: .build_and_unit - variables: - OS: rhel-8 - COMPILER: gcc - CMAKE_BUILD_TYPE: Release - ASSERT_LEVEL: PARANOID - TEST_MODE: default - MARCH: x86-64-v3 - INFRASTRUCTURE_TAG: amd64-avx2 - .smoke archlinux: extends: .build_and_unit variables: @@ -397,20 +385,6 @@ smoke tsan cached: cache: - *cache_build_get -smoke rhel cached: - extends: .smoke rhel - stage: manual - timeout: 1 hour - rules: - - if: $CI_MERGE_REQUEST_LABELS =~ /ci-no-cache/ - when: never - - if: $ON_MR == "true" && $CI_MERGE_REQUEST_APPROVED == "true" - - if: $ON_MR - when: manual - allow_failure: false - cache: - - *cache_build_get - smoke archlinux cached: extends: .smoke archlinux stage: manual @@ -514,11 +488,6 @@ smoke tsan clean: rules: - if: $CI_MERGE_REQUEST_LABELS =~ /ci-no-cache/ -smoke rhel clean: - extends: .smoke rhel - rules: - - if: $CI_MERGE_REQUEST_LABELS =~ /ci-no-cache/ - smoke archlinux clean: extends: .smoke archlinux rules: @@ -681,17 +650,6 @@ smoke tsan update cache: cache: - *cache_build_set -smoke rhel update cache: - extends: .smoke rhel - rules: - - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests Plugin/ - when: delayed - start_in: 45 minutes - retry: 2 - interruptible: false - cache: - - *cache_build_set - smoke archlinux update cache: extends: .smoke archlinux rules: @@ -996,6 +954,27 @@ ubuntu dpdk: COMPILER: [gcc, clang] DPDK_VERSION: ["22.11.6_avx2", "23.11.1_avx2"] +# Nightly Sanitizers + +ubsan avx2: + extends: .build_and_unit + rules: + - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests/ + when: delayed + start_in: 45 minutes + variables: + OS: ubuntu-24.10 + COMPILER: gcc + CMAKE_BUILD_TYPE: Debug + ASSERT_LEVEL: PARANOID + ENABLE_UBSAN: "True" + TEST_MODE: default + MARCH: x86-64-v3 + INFRASTRUCTURE_TAG: amd64-avx2-docker + KUBERNETES_EPHEMERAL_STORAGE_REQUEST: "50G" + KUBERNETES_EPHEMERAL_STORAGE_LIMIT: "50G" + timeout: 2 hours + ################### # Alternative OSs # ################### @@ -1103,28 +1082,6 @@ debian 12 amd64 avx512: variables: ASSERT_LEVEL: PARANOID CMAKE_BUILD_TYPE: Debug - parallel: - matrix: - # ubuntu-22.04 disabled due to https://github.com/google/sanitizers/issues/1259#issuecomment-642312392 - - OS: [ubuntu-24.10, ubuntu-24.04] - SANITIZER: tsan - COMPILER: [gcc, clang] - ENABLE_TSAN: "True" - TEST_MODE: default - - OS: [ubuntu-22.04] - SANITIZER: asan - COMPILER: [gcc, clang] - ENABLE_ASAN: "True" - TEST_MODE: default - - OS: [ubuntu-24.10, ubuntu-24.04] - SANITIZER: asan - COMPILER: clang - ENABLE_ASAN: "True" - TEST_MODE: default - - OS: [ubuntu-24.10, ubuntu-24.04] - SANITIZER: valgrind - COMPILER: gcc - TEST_MODE: valgrind sanitizers amd64 native: extends: .weekly sanitizers @@ -1149,6 +1106,14 @@ sanitizers amd64 native: ENABLE_ASAN: "True" TEST_MODE: default # Valgrind doesn't support AVX512 instruction set + - OS: [ubuntu-24.10, ubuntu-24.04] + SANITIZER: ubsan + COMPILER: [gcc, clang] + ENABLE_UBSAN: "True" + TEST_MODE: default + INFRASTRUCTURE_TAG: amd64-docker + KUBERNETES_EPHEMERAL_STORAGE_REQUEST: "50G" + KUBERNETES_EPHEMERAL_STORAGE_LIMIT: "50G" sanitizers amd64 avx2: extends: .weekly sanitizers @@ -1177,6 +1142,14 @@ sanitizers amd64 avx2: SANITIZER: valgrind COMPILER: gcc TEST_MODE: valgrind + - OS: [ubuntu-24.10, ubuntu-24.04] + SANITIZER: ubsan + COMPILER: [gcc, clang] + ENABLE_UBSAN: "True" + TEST_MODE: default + INFRASTRUCTURE_TAG: amd64-avx2-docker + KUBERNETES_EPHEMERAL_STORAGE_REQUEST: "50G" + KUBERNETES_EPHEMERAL_STORAGE_LIMIT: "50G" sanitizers amd64 avx512: extends: .weekly sanitizers @@ -1202,17 +1175,54 @@ sanitizers amd64 avx512: ENABLE_ASAN: "True" TEST_MODE: default # Valgrind doesn't support AVX512 instruction set + - OS: [ubuntu-24.10, ubuntu-24.04] + SANITIZER: ubsan + COMPILER: [gcc, clang] + ENABLE_UBSAN: "True" + TEST_MODE: default + INFRASTRUCTURE_TAG: amd64-avx2-avx512-docker + KUBERNETES_EPHEMERAL_STORAGE_REQUEST: "50G" + KUBERNETES_EPHEMERAL_STORAGE_LIMIT: "50G" sanitizers arm native: extends: .weekly sanitizers variables: INFRASTRUCTURE_TAG: arm64 + parallel: + matrix: + # ubuntu-22.04 disabled due to https://github.com/google/sanitizers/issues/1259#issuecomment-642312392 + - OS: [ubuntu-24.10, ubuntu-24.04] + SANITIZER: tsan + COMPILER: [gcc, clang] + ENABLE_TSAN: "True" + TEST_MODE: default + - OS: [ubuntu-22.04] + SANITIZER: asan + COMPILER: [gcc, clang] + ENABLE_ASAN: "True" + TEST_MODE: default + - OS: [ubuntu-24.10, ubuntu-24.04] + SANITIZER: asan + COMPILER: clang + ENABLE_ASAN: "True" + TEST_MODE: default + - OS: [ubuntu-24.10, ubuntu-24.04] + SANITIZER: valgrind + COMPILER: gcc + TEST_MODE: valgrind + - OS: [ubuntu-24.10, ubuntu-24.04] + SANITIZER: ubsan + COMPILER: [gcc, clang] + ENABLE_UBSAN: "True" + TEST_MODE: default + INFRASTRUCTURE_TAG: arm64-docker + KUBERNETES_EPHEMERAL_STORAGE_REQUEST: "50G" + KUBERNETES_EPHEMERAL_STORAGE_LIMIT: "50G" sanitizers arm neon: - extends: .weekly sanitizers + extends: sanitizers arm native variables: MARCH: armv8.2-a+crypto+fp16+dotprod - INFRASTRUCTURE_TAG: arm64 # UHD Alternatives @@ -1344,7 +1354,7 @@ ubuntu-24.04 amd64 avx512 TRACE: OS: ubuntu-24.04 MARCH: x86-64-v4 INFRASTRUCTURE_TAG: amd64-avx2-avx512 - BUILD_ARGS: -DCMAKE_CXX_FLAGS="-D SRSRAN_L2_TRACE -D SRSRAN_L1_TRACE -D SRSRAN_L2_LATE_TRACE -D SRSRAN_OFH_TRACE -D SRSRAN_UP_TRACE" + CXXFLAGS: -D SRSRAN_L2_TRACE -D SRSRAN_L1_TRACE -D SRSRAN_L2_LATE_TRACE -D SRSRAN_OFH_TRACE -D SRSRAN_UP_TRACE parallel: matrix: - <<: *basic_combinations @@ -1603,6 +1613,8 @@ ubuntu-24.10 amd64 avx512 dpdk: ############### basic package: extends: .deb-package + tags: + - ${INFRASTRUCTURE_TAG} stage: build and unit tests rules: - if: $CI_DESCRIPTION =~ /Nightly E2E Tests OpenSource/ diff --git a/.gitlab/ci/docker.yml b/.gitlab/ci/docker.yml index a3ab3b5f1c..23c1bb305b 100644 --- a/.gitlab/ci/docker.yml +++ b/.gitlab/ci/docker.yml @@ -35,16 +35,6 @@ variables: - docker/scripts/**/* - docker/Dockerfile -.uhd_params: - variables: &uhd_params - LIB: uhd - LIB_VERSION: "4.7.0.0" - -.dpdk_params: - variables: &dpdk_params - LIB: dpdk - LIB_VERSION: "23.11.1" - ################################################################################ # Static ################################################################################ @@ -132,8 +122,13 @@ metrics version check in retina: tags: - amd64-avx2 timeout: 2h + retry: 2 variables: GIT_LFS_SKIP_SMUDGE: 1 + KUBERNETES_CPU_REQUEST: ${SRS_CPU_LIMIT} + KUBERNETES_CPU_LIMIT: ${SRS_CPU_LIMIT} + KUBERNETES_MEMORY_REQUEST: ${SRS_MEMORY_LIMIT} + KUBERNETES_MEMORY_LIMIT: ${SRS_MEMORY_LIMIT} before_script: &docker_setup - dockerd-entrypoint.sh & - | @@ -142,13 +137,11 @@ metrics version check in retina: sleep 1 done -.gnb docker compose: +gnb docker compose: extends: .docker compose - variables: &build_in_compose_variables - KUBERNETES_CPU_REQUEST: ${SRS_CPU_LIMIT} - KUBERNETES_CPU_LIMIT: ${SRS_CPU_LIMIT} - KUBERNETES_MEMORY_REQUEST: ${SRS_MEMORY_LIMIT} - KUBERNETES_MEMORY_LIMIT: ${SRS_MEMORY_LIMIT} + variables: &gnb_build_args + DOCKER_UHD_VERSION: "4.7.0.0" + DOCKER_DPDK_VERSION: "23.11.1" rules: - if: $ON_MR changes: @@ -161,29 +154,21 @@ metrics version check in retina: interruptible: false before_script: - *docker_setup - - docker compose -f docker/docker-compose.yml build --build-arg NUM_JOBS=${KUBERNETES_CPU_LIMIT} --build-arg LIB=${LIB} --build-arg LIB_VERSION=${LIB_VERSION} gnb + script: + - docker compose -f docker/docker-compose.yml build --build-arg NUM_JOBS=${KUBERNETES_CPU_LIMIT} --build-arg UHD_VERSION=${DOCKER_UHD_VERSION} --build-arg DPDK_VERSION=${DOCKER_DPDK_VERSION} gnb - sh -c "docker compose -f docker/docker-compose.yml run --no-deps gnb which srscu" - sh -c "docker compose -f docker/docker-compose.yml run --no-deps gnb which srsdu" - -gnb docker compose uhd: - extends: .gnb docker compose - variables: - <<: *uhd_params - script: - - sh -c "docker compose -f docker/docker-compose.yml run --no-deps gnb gnb cu_cp amf --no_core=true ru_sdr --device_driver uhd | grep 'Failed to open device with address'" - -gnb docker compose dpdk: - extends: .gnb docker compose - variables: - <<: *dpdk_params - script: + - sh -c "docker compose -f docker/docker-compose.yml run --no-deps gnb which srsdu_split_8" + - sh -c "docker compose -f docker/docker-compose.yml run --no-deps gnb which srsdu_split_7_2" + - sh -c "docker compose -f docker/docker-compose.yml run --no-deps gnb which gnb" + - sh -c "docker compose -f docker/docker-compose.yml run --no-deps gnb which gnb_split_8" + - sh -c "docker compose -f docker/docker-compose.yml run --no-deps gnb which gnb_split_7_2" - sh -c "docker compose -f docker/docker-compose.yml run --no-deps gnb which ru_emulator" + - sh -c "docker compose -f docker/docker-compose.yml run --no-deps gnb gnb cu_cp amf --no_core=true ru_sdr --device_driver uhd | grep 'Failed to open device with address'" - sh -c "docker compose -f docker/docker-compose.yml run --no-deps gnb gnb cu_cp amf --no_core=true hal --eal_args='--help'" 5gc docker compose: extends: .docker compose - variables: - <<: *build_in_compose_variables rules: - if: $ON_MR changes: @@ -292,13 +277,15 @@ grafana server image latest: - | export VERSION=latest -.srsran image: +srsran image: extends: .docker-builder stage: publish rules: - if: $CI_DESCRIPTION =~ /Nightly Build Unit Tests/ interruptible: false + retry: 2 variables: + # CI GIT_LFS_SKIP_SMUDGE: 1 KUBERNETES_CPU_REQUEST: ${SRS_CPU_LIMIT} KUBERNETES_CPU_LIMIT: ${SRS_CPU_LIMIT} @@ -306,24 +293,20 @@ grafana server image latest: KUBERNETES_MEMORY_LIMIT: ${SRS_MEMORY_LIMIT} KUBERNETES_EPHEMERAL_STORAGE_REQUEST: "50G" KUBERNETES_EPHEMERAL_STORAGE_LIMIT: "50G" + # Docker REGISTRY_URI: $GITLAB_REGISTRY_URI CONTEXT: ${CI_PROJECT_DIR} DOCKERFILE: docker MODE: build + <<: *gnb_build_args timeout: 2 hours tags: - - ${TAG} + - ${TAG}-docker before_script: - | export NAME="srsran-project" export VERSION="${SPLIT}_${SUFFIX}" - export BUILD_ARGS="LIB=${LIB};LIB_VERSION=${LIB_VERSION};MARCH=${MARCH};NUM_JOBS=${KUBERNETES_CPU_LIMIT};EXTRA_CMAKE_ARGS=\"${EXTRA_CMAKE_ARGS}\"" - -srsran image split72: - extends: .srsran image - variables: - SPLIT: split72 - <<: *dpdk_params + export BUILD_ARGS="UHD_VERSION=${DOCKER_UHD_VERSION};DPDK_VERSION=${DOCKER_DPDK_VERSION};MARCH=${MARCH};NUM_JOBS=${KUBERNETES_CPU_LIMIT};EXTRA_CMAKE_ARGS=\"${EXTRA_CMAKE_ARGS}\"" parallel: matrix: # AMD AVX2 @@ -357,38 +340,6 @@ srsran image split72: TAG: arm64 PLATFORM: arm64 needs: - - job: gnb docker compose dpdk - optional: true - artifacts: false - -srsran image split8: - extends: .srsran image - variables: - SPLIT: split8 - <<: *uhd_params - parallel: - matrix: - # AMD AVX2 - - SUFFIX: release_avx2 - MARCH: x86-64-v3 - TAG: amd64-avx2 - PLATFORM: amd64 - - SUFFIX: release_with_debug_avx2 - EXTRA_CMAKE_ARGS: -DFORCE_DEBUG_INFO=On - MARCH: x86-64-v3 - TAG: amd64-avx2 - PLATFORM: amd64 - # ARM - - SUFFIX: release_arm - MARCH: armv8.2-a+crypto+fp16+dotprod - TAG: arm64 - PLATFORM: arm64 - - SUFFIX: release_with_debug_arm - EXTRA_CMAKE_ARGS: -DFORCE_DEBUG_INFO=On - MARCH: armv8.2-a+crypto+fp16+dotprod - TAG: arm64 - PLATFORM: arm64 - needs: - - job: gnb docker compose uhd + - job: gnb docker compose optional: true artifacts: false diff --git a/.gitlab/ci/e2e.yml b/.gitlab/ci/e2e.yml index 3f922410e8..3a0415d6b2 100644 --- a/.gitlab/ci/e2e.yml +++ b/.gitlab/ci/e2e.yml @@ -513,14 +513,18 @@ viavi: - job: "basic avx512 dpdk" artifacts: true - *retina-needs + rules: + - if: $CI_DESCRIPTION =~ /Nightly E2E Tests Plugin/ parallel: matrix: - KEYWORDS: [ - "ideal and 1UE", + "ideal and 1UE and not MIMO", + "ideal and 1UE and MIMO", "ideal and 32UE and not experimental and not tdd and not extended", "tdd", - "fading and 1UE", + "fading and 1UE and not MIMO", + "fading and 1UE and MIMO", "fading and 32UE", "birth-death and 1UE", "32UE and experimental and not extended", diff --git a/.gitlab/ci/e2e/.env b/.gitlab/ci/e2e/.env index 8d4c55e491..78dda71aa9 100644 --- a/.gitlab/ci/e2e/.env +++ b/.gitlab/ci/e2e/.env @@ -1,6 +1,6 @@ SRSGNB_REGISTRY_URI=registry.gitlab.com/softwareradiosystems/srsgnb RETINA_REGISTRY_PREFIX=registry.gitlab.com/softwareradiosystems/ci/retina -RETINA_VERSION=0.60.15 +RETINA_VERSION=0.62.4 UBUNTU_VERSION=24.04 AMARISOFT_VERSION=2023-09-08 SRSUE_VERSION=23.11 @@ -10,6 +10,6 @@ PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin METRICS_SERVER_VERSION=1.7.3 DPDK_VERSION=23.11.1 ZMQ_HOSTLABEL_0=kubernetes.io/hostname=hp-generic-2 -ZMQ_HOSTLABEL_1=kubernetes.io/hostname=srskit2 +ZMQ_HOSTLABEL_1=kubernetes.io/hostname=ci-buildmaster AMARISOFT_TXRX_BINARY_PATH=../../build_trx_srsran/libtrx_srsran.so GNB_BUILD_PATH=../../build diff --git a/.gitlab/ci/e2e/retina_request_android_b200.yml b/.gitlab/ci/e2e/retina_request_android_b200.yml index fd06021b01..fa77e40fb5 100644 --- a/.gitlab/ci/e2e/retina_request_android_b200.yml +++ b/.gitlab/ci/e2e/retina_request_android_b200.yml @@ -51,7 +51,7 @@ - name: open5gs type: 5gc image: ${RETINA_REGISTRY_PREFIX}/open5gs:${OPEN5GS_VERSION}_${RETINA_VERSION} - taints: ["purpose=retina"] + labels: ["kubernetes.io/hostname=k8s-worker-uhd1"] requirements: arch: amd64 cpu: diff --git a/.gitlab/ci/e2e/retina_request_rf_b200.yml b/.gitlab/ci/e2e/retina_request_rf_b200.yml index aa677b2a7b..e8fd858c6e 100644 --- a/.gitlab/ci/e2e/retina_request_rf_b200.yml +++ b/.gitlab/ci/e2e/retina_request_rf_b200.yml @@ -9,7 +9,7 @@ - name: amarisoft-ue type: ue image: ${RETINA_REGISTRY_PREFIX}/amarisoftue:${AMARISOFT_VERSION}_${RETINA_VERSION} - labels: ["kubernetes.io/hostname=ci-buildmaster"] + labels: ["kubernetes.io/hostname=sdr6"] nof_ports: 4 requirements: arch: amd64 @@ -20,8 +20,8 @@ requests: "20G" limits: "20G" ephemeral-storage: - requests: "6G" - limits: "6G" + requests: "9G" + limits: "9G" resources: - type: sdr model: b200 @@ -31,15 +31,15 @@ - name: srs-gnb type: gnb image: ${RETINA_REGISTRY_PREFIX}/srsgnb:${RETINA_VERSION} - labels: ["kubernetes.io/hostname=sdr6"] + labels: ["kubernetes.io/hostname=sdr4"] requirements: arch: amd64 cpu: - requests: 12 - limits: 12 + requests: 8 + limits: 8 memory: - requests: "20G" - limits: "20G" + requests: "12G" + limits: "12G" ephemeral-storage: requests: "9G" limits: "9G" diff --git a/.gitlab/ci/e2e/retina_request_test_mode_acc100.yml b/.gitlab/ci/e2e/retina_request_test_mode_acc100.yml index b1bb27fa67..94308f7415 100644 --- a/.gitlab/ci/e2e/retina_request_test_mode_acc100.yml +++ b/.gitlab/ci/e2e/retina_request_test_mode_acc100.yml @@ -32,19 +32,3 @@ - local_path: ${GNB_BUILD_PATH}/apps/gnb/gnb remote_path: /usr/local/bin/gnb is_executable: true - -- name: open5gs - type: 5gc - requirements: - arch: amd64 - cpu: - requests: 1 - limits: 1 - memory: - requests: "8G" - limits: "8G" - ephemeral-storage: - requests: "6G" - limits: "6G" - image: ${RETINA_REGISTRY_PREFIX}/open5gs:${OPEN5GS_VERSION}_${RETINA_VERSION} - labels: ["kubernetes.io/hostname=k8s-worker-uhd1"] diff --git a/.gitlab/ci/e2e/retina_request_zmq_uesim.yml b/.gitlab/ci/e2e/retina_request_zmq_uesim.yml index 7d3657c78d..324083bf87 100644 --- a/.gitlab/ci/e2e/retina_request_zmq_uesim.yml +++ b/.gitlab/ci/e2e/retina_request_zmq_uesim.yml @@ -9,7 +9,7 @@ - name: amarisoft-ue type: ue image: ${RETINA_REGISTRY_PREFIX}/amarisoftue-remote:${RETINA_VERSION} - taints: ["machine=srskit2"] + taints: ["machine=ci-buildmaster"] labels: - ${ZMQ_HOSTLABEL_1} nof_ports: 32 @@ -36,15 +36,15 @@ - name: srs-gnb type: gnb image: ${RETINA_REGISTRY_PREFIX}/srsgnb:${RETINA_VERSION} - taints: ["machine=srskit2"] + taints: ["machine=ci-buildmaster"] labels: - ${ZMQ_HOSTLABEL_1} force_external_ip: true requirements: arch: amd64 cpu: - requests: 16 - limits: 16 + requests: 8 + limits: 8 memory: requests: "10G" limits: "10G" diff --git a/.gitlab/run_viavi_pipeline.py b/.gitlab/run_viavi_pipeline.py index 1a500669d1..4579e67f1c 100755 --- a/.gitlab/run_viavi_pipeline.py +++ b/.gitlab/run_viavi_pipeline.py @@ -1,9 +1,10 @@ #!/usr/bin/env python3 import argparse -from dataclasses import dataclass +from dataclasses import dataclass, field import pathlib -from typing import List +import sys +from typing import Dict, List try: import yaml @@ -30,6 +31,7 @@ class _TestDefinition: campaign_filename: str = "" test_name: str = "" description: str = "" + gnb_extra_config: Dict = field(default_factory=dict) # pylint: disable=too-many-instance-attributes @@ -43,11 +45,24 @@ class _ArgsDefinition: testid: str = "" campaign_path: str = "" timeout: int = "" - gnb_extra: str = "" + gnb_cli: str = "" build_args: str = DEFAULT_BUILD_ARGS dpdk_version: str = DEFAULT_DPDK_VERSION +def _convert_extra_config_into_command(extra_config: dict) -> str: + """ + Convert extra config into command + """ + cmd_args = "" + for key, value in sorted(extra_config.items(), key=lambda item: isinstance(item[1], dict)): + if isinstance(value, dict): + cmd_args += f"{key} " + _convert_extra_config_into_command(value) + else: + cmd_args += f"--{key}={value} " + return cmd_args + + def get_viavi_tests(): viavi_test_declaration = ( pathlib.Path(__file__).parent / ".." / "tests" / "e2e" / "tests" / "viavi" / "test_declaration.yml" @@ -62,6 +77,7 @@ def get_viavi_tests(): test_definition.campaign_filename = test["campaign_filename"] test_definition.test_name = test["test_name"] test_definition.description = test.get("description", "") + test_definition.gnb_extra_config = test.get("gnb_extra_config", "") test_list.append(test_definition) return test_list @@ -73,7 +89,7 @@ def validate_args(args) -> _ArgsDefinition: args_definition.branch = args.branch args_definition.testid = args.testid args_definition.timeout = args.timeout - args_definition.gnb_extra = args.srsgnb_extra + args_definition.gnb_cli = args.srsgnb_cli args_definition.build_args = args.build_args args_definition.dpdk_version = args.dpdk_version @@ -114,7 +130,6 @@ def run_test(args_definition: _ArgsDefinition, test_definition: _TestDefinition) COMPILER = "gcc" TESTMODE = "none" - MAKE_ARGS = "-j6" BUILD_ARGS = args_definition.build_args DPDK_VERSION = args_definition.dpdk_version @@ -122,8 +137,19 @@ def run_test(args_definition: _ArgsDefinition, test_definition: _TestDefinition) MARKERS = "viavi_manual" PYARGS = f'--viavi-manual-campaign-filename "{test_definition.campaign_filename}" --viavi-manual-test-name "{test_definition.id}" --viavi-manual-test-timeout {timeout} --retina-pod-timeout 900' - if args_definition.gnb_extra: - PYARGS += f' --viavi-manual-extra-gnb-arguments "{args_definition.gnb_extra}"' + if args_definition.gnb_cli: + PYARGS += f' --viavi-manual-gnb-arguments "{args_definition.gnb_cli}"' + print("") + print( + "⚠️ Using srsgnb-cli overwrites the configuration defined in the test_declaration.yml for the test. Please review your new config carefully!!" + ) + print("⚠️ OLD configuration: ", _convert_extra_config_into_command(test_definition.gnb_extra_config)) + print("⚠️ NEW configuration: ", args_definition.gnb_cli) + print("") + if input("Do you want to continue with the new configuration? (yes/no): ").strip().lower() not in ("y", "yes"): + print("Exiting as per user request.") + sys.exit(0) + print("") RETINA_ARGS = "gnb.all.pcap=True gnb.all.rlc_enable=True gnb.all.rlc_rb_type=srb" @@ -133,7 +159,6 @@ def run_test(args_definition: _ArgsDefinition, test_definition: _TestDefinition) {"key": "COMPILER", "value": COMPILER}, {"key": "TEST_MODE", "value": TESTMODE}, {"key": "BUILD_ARGS", "value": BUILD_ARGS}, - {"key": "MAKE_ARGS", "value": MAKE_ARGS}, {"key": "SRS_TARGET", "value": "gnb_split_7_2"}, {"key": "PLUGIN_BRANCH", "value": "main"}, {"key": "UHD_VERSION", "value": ""}, @@ -150,10 +175,9 @@ def run_test(args_definition: _ArgsDefinition, test_definition: _TestDefinition) print(f"Creating Viavi pipeline for branch {branch}...") print(f" - Test ID: {test_definition.id}") - print(f" - Extra arguments to gnb binary: {args_definition.gnb_extra}") + print(f" - OS {OS_NAME}") print(f" - BUILD_ARGS {BUILD_ARGS}") print(f" - DPDK_VERSION {DPDK_VERSION}") - print(f" - OS {OS_NAME}") gl = gitlab.Gitlab("https://gitlab.com", private_token=private_token) project = gl.projects.get("softwareradiosystems/srsgnb") @@ -161,7 +185,7 @@ def run_test(args_definition: _ArgsDefinition, test_definition: _TestDefinition) pipeline_url = pipeline.web_url - print(f"Pipeline created: {pipeline_url}") + print(f"🟢 Pipeline created: {pipeline_url}") def main(): @@ -188,9 +212,9 @@ def main(): ) parser.add_argument( - "--srsgnb-extra", + "--srsgnb-cli", default="", - help='Extra agruments passed to the gnb binary. E.g: "log --metrics_level=info"', + help='Arguments passed to the gnb binary. E.g: "log --metrics_level=info". This overwrites the arguments in the test_declaration.yml file.', ) parser.add_argument( diff --git a/COPYRIGHT b/COPYRIGHT index 98de17f87b..f80c42f096 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -5,6 +5,7 @@ License: See LICENSE file The following files are used within srsRAN: + Files: docs/doxygen-awesome-sidebar-only.css docs/doxygen-awesome.css Copyright: 2021-2024 jothepro @@ -16,23 +17,22 @@ Copyright: 2013-2017 Google Inc. License: MIT -Files: external/fmt/args.h - external/fmt/base.h - external/fmt/chrono.h - external/fmt/color.h - external/fmt/compile.h - external/fmt/core.h - external/fmt/format.h - external/fmt/format-inl.h - external/fmt/LICENSE.rst - external/fmt/os.h - external/fmt/ostream.h - external/fmt/printf.h - external/fmt/ranges.h - external/fmt/std.h - external/fmt/xchar.h - external/fmt/format.cc - external/fmt/os.cc +Files: external/fmt/include/fmt/args.h + external/fmt/include/fmt/base.h + external/fmt/include/fmt/chrono.h + external/fmt/include/fmt/color.h + external/fmt/include/fmt/compile.h + external/fmt/include/fmt/core.h + external/fmt/include/fmt/format.h + external/fmt/include/fmt/format-inl.h + external/fmt/include/fmt/os.h + external/fmt/include/fmt/ostream.h + external/fmt/include/fmt/printf.h + external/fmt/include/fmt/ranges.h + external/fmt/include/fmt/std.h + external/fmt/include/fmt/xchar.h + external/fmt/src/format.cc + external/fmt/src/os.cc Copyright: 2012-present Victor Zverovich and {fmt} contributors License: MIT @@ -62,6 +62,68 @@ Copyright: 2017 Sy Brand License: CC0 1.0 Universal +Files: external/uWebSockets/App.h + external/uWebSockets/AsyncSocket.h + external/uWebSockets/AsyncSocketData.h + external/uWebSockets/BloomFilter.h + external/uWebSockets/CachingApp.h + external/uWebSockets/ChunkedEncoding.h + external/uWebSockets/ClientApp.h + external/uWebSockets/Http3App.h + external/uWebSockets/Http3Context.h + external/uWebSockets/Http3ContextData.h + external/uWebSockets/Http3Request.h + external/uWebSockets/Http3Response.h + external/uWebSockets/Http3ResponseData.h + external/uWebSockets/HttpContext.h + external/uWebSockets/HttpContextData.h + external/uWebSockets/HttpErrors.h + external/uWebSockets/HttpParser.h + external/uWebSockets/HttpResponse.h + external/uWebSockets/HttpResponseData.h + external/uWebSockets/HttpRouter.h + external/uWebSockets/LocalCluster.h + external/uWebSockets/Loop.h + external/uWebSockets/LoopData.h + external/uWebSockets/MessageParser.h + external/uWebSockets/MoveOnlyFunction.h + external/uWebSockets/Multipart.h + external/uWebSockets/PerMessageDeflate.h + external/uWebSockets/ProxyParser.h + external/uWebSockets/QueryParser.h + external/uWebSockets/TopicTree.h + external/uWebSockets/Utilities.h + external/uWebSockets/WebSocket.h + external/uWebSockets/WebSocketContext.h + external/uWebSockets/WebSocketContextData.h + external/uWebSockets/WebSocketData.h + external/uWebSockets/WebSocketExtensions.h + external/uWebSockets/WebSocketHandshake.h + external/uWebSockets/WebSocketProtocol.h + external/uWebSockets/uSockets/eventing/epoll_kqueue.c + external/uWebSockets/uSockets/internal/eventing/asio.h + external/uWebSockets/uSockets/internal/eventing/epoll_kqueue.h + external/uWebSockets/uSockets/internal/eventing/gcd.h + external/uWebSockets/uSockets/internal/eventing/libuv.h + external/uWebSockets/uSockets/internal/networking/bsd.h + external/uWebSockets/uSockets/internal/internal.h + external/uWebSockets/uSockets/internal/loop_data.h + external/uWebSockets/uSockets/bsd.c + external/uWebSockets/uSockets/context.c + external/uWebSockets/uSockets/libusockets.h + external/uWebSockets/uSockets/loop.c + external/uWebSockets/uSockets/socket.c + external/uWebSockets/uSockets/udp.c +Copyright: 2018-2020 Alex Hultman +License: Apache License, Version 2.0 + + +Files: external/nlohmann/json.hpp + external/nlohmann/json_fwd.hpp +Copyright: 2013-2023 Niels Lohmann +License: MIT + + License: MIT Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -289,3 +351,201 @@ License: CC0 1.0 Universal d. Affirmer understands and acknowledges that Creative Commons is not a party to this document and has no duty or obligation with respect to this CC0 or use of the Work. + + +License: Apache Version 2.0, January 2004 + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/apps/cu/cu.cpp b/apps/cu/cu.cpp index 46a4faf0b7..419358f221 100644 --- a/apps/cu/cu.cpp +++ b/apps/cu/cu.cpp @@ -24,9 +24,10 @@ #include "apps/services/application_message_banners.h" #include "apps/services/application_tracer.h" #include "apps/services/buffer_pool/buffer_pool_manager.h" +#include "apps/services/cmdline/cmdline_command_dispatcher.h" #include "apps/services/metrics/metrics_manager.h" #include "apps/services/metrics/metrics_notifier_proxy.h" -#include "apps/services/stdin_command_dispatcher.h" +#include "apps/services/remote_control/remote_server.h" #include "apps/services/worker_manager/worker_manager.h" #include "apps/services/worker_manager/worker_manager_config.h" #include "apps/units/o_cu_cp/o_cu_cp_application_unit.h" @@ -375,8 +376,8 @@ int main(int argc, char** argv) srs_cu_cp::o_cu_cp& o_cucp_obj = *o_cucp_unit.unit; // Create console helper object for commands and metrics printing. - app_services::stdin_command_dispatcher command_parser( - *epoll_broker, *workers.non_rt_low_prio_exec, o_cucp_unit.commands); + app_services::cmdline_command_dispatcher command_parser( + *epoll_broker, *workers.non_rt_low_prio_exec, o_cucp_unit.commands.cmdline); std::vector metrics_configs = std::move(o_cucp_unit.metrics); // Connect E1AP to O-CU-CP. @@ -417,6 +418,10 @@ int main(int argc, char** argv) metrics_notifier_forwarder.connect(metrics_mngr); o_cuup_unit.unit->get_operation_controller().start(); + + std::unique_ptr remote_control_server = + app_services::create_remote_server(cu_cfg.remote_control_config, {}); + { app_services::application_message_banners app_banner(app_name); @@ -425,6 +430,10 @@ int main(int argc, char** argv) } } + if (remote_control_server) { + remote_control_server->stop(); + } + // Stop O-CU-UP activity. o_cuup_unit.unit->get_operation_controller().stop(); diff --git a/apps/cu/cu_appconfig.h b/apps/cu/cu_appconfig.h index 20c1672027..77c79449dc 100644 --- a/apps/cu/cu_appconfig.h +++ b/apps/cu/cu_appconfig.h @@ -25,15 +25,16 @@ #include "apps/services/buffer_pool/buffer_pool_appconfig.h" #include "apps/services/f1u/f1u_cli11_schema.h" #include "apps/services/logger/logger_appconfig.h" +#include "apps/services/remote_control/remote_control_appconfig.h" #include "apps/services/worker_manager/worker_manager_appconfig.h" #include namespace srsran { namespace srs_cu { -/// F1AP configuration +/// F1AP configuration. struct cu_f1ap_appconfig { - /// F1-C bind address + /// F1-C bind address. std::string bind_addr = "127.0.10.1"; }; @@ -47,12 +48,14 @@ struct cu_appconfig { logger_appconfig log_cfg; /// Expert configuration. expert_execution_appconfig expert_execution_cfg; - /// F1-U + /// F1-U configuration. f1u_sockets_appconfig f1u_cfg; - /// F1AP + /// F1AP configuration. srs_cu::cu_f1ap_appconfig f1ap_cfg; /// Buffer pool configuration. buffer_pool_appconfig buffer_pool_config; + /// Remote control configuration. + remote_control_appconfig remote_control_config; }; } // namespace srsran diff --git a/apps/cu/cu_appconfig_cli11_schema.cpp b/apps/cu/cu_appconfig_cli11_schema.cpp index 5e75257ce9..d972c1cf58 100644 --- a/apps/cu/cu_appconfig_cli11_schema.cpp +++ b/apps/cu/cu_appconfig_cli11_schema.cpp @@ -23,6 +23,7 @@ #include "cu_appconfig_cli11_schema.h" #include "apps/services/buffer_pool/buffer_pool_appconfig_cli11_schema.h" #include "apps/services/logger/logger_appconfig_cli11_schema.h" +#include "apps/services/remote_control/remote_control_appconfig_cli11_schema.h" #include "apps/services/worker_manager/worker_manager_cli11_schema.h" #include "cu_appconfig.h" #include "srsran/support/cli11_utils.h" @@ -45,6 +46,9 @@ void srsran::configure_cli11_with_cu_appconfig_schema(CLI::App& app, cu_appconfi // Expert execution section. configure_cli11_with_worker_manager_appconfig_schema(app, cu_cfg.expert_execution_cfg); + // Remote control section. + configure_cli11_with_remote_control_appconfig_schema(app, cu_cfg.remote_control_config); + // F1AP section. CLI::App* cu_cp_subcmd = add_subcommand(app, "cu_cp", "CU-UP parameters")->configurable(); CLI::App* f1ap_subcmd = add_subcommand(*cu_cp_subcmd, "f1ap", "F1AP parameters")->configurable(); diff --git a/apps/cu/cu_appconfig_yaml_writer.cpp b/apps/cu/cu_appconfig_yaml_writer.cpp index 7945afd09d..a84ec23965 100644 --- a/apps/cu/cu_appconfig_yaml_writer.cpp +++ b/apps/cu/cu_appconfig_yaml_writer.cpp @@ -33,6 +33,13 @@ static void fill_cu_appconfig_buffer_pool_section(YAML::Node node, const buffer_ node["segment_size"] = config.segment_size; } +static void fill_cu_appconfig_remote_control_section(YAML::Node node, const remote_control_appconfig& config) +{ + node["enabled"] = config.enabled; + node["bind_address"] = config.bind_addr; + node["port"] = config.port; +} + static void fill_cu_appconfig_f1ap_section(YAML::Node node, const srs_cu::cu_f1ap_appconfig& config) { YAML::Node cu_cp_node = node["cu_cp"]; @@ -50,6 +57,7 @@ void srsran::fill_cu_appconfig_in_yaml_schema(YAML::Node& node, const cu_appconf { fill_logger_appconfig_in_yaml_schema(node, config.log_cfg); fill_cu_appconfig_buffer_pool_section(node["buffer_pool"], config.buffer_pool_config); + fill_cu_appconfig_remote_control_section(node["remote_control"], config.remote_control_config); fill_cu_appconfig_f1ap_section(node, config.f1ap_cfg); fill_cu_appconfig_f1u_section(node, config.f1u_cfg); } diff --git a/apps/du/du.cpp b/apps/du/du.cpp index ac3bd13c71..61e3ad26ae 100644 --- a/apps/du/du.cpp +++ b/apps/du/du.cpp @@ -21,13 +21,16 @@ */ #include "adapters/f1_gateways.h" +#include "apps/services/app_resource_usage/app_resource_usage.h" #include "apps/services/application_message_banners.h" #include "apps/services/application_tracer.h" #include "apps/services/buffer_pool/buffer_pool_manager.h" +#include "apps/services/cmdline/cmdline_command_dispatcher.h" #include "apps/services/core_isolation_manager.h" #include "apps/services/metrics/metrics_manager.h" #include "apps/services/metrics/metrics_notifier_proxy.h" -#include "apps/services/stdin_command_dispatcher.h" +#include "apps/services/periodic_metrics_report_controller.h" +#include "apps/services/remote_control/remote_server.h" #include "apps/services/worker_manager/worker_manager.h" #include "apps/units/flexible_o_du/flexible_o_du_application_unit.h" #include "apps/units/flexible_o_du/o_du_high/du_high/du_high_config.h" @@ -323,7 +326,14 @@ int main(int argc, char** argv) E2_DU_PPID)); app_services::metrics_notifier_proxy_impl metrics_notifier_forwarder; - o_du_unit_dependencies du_dependencies; + + // Create app-level resource usage service and metrics. + auto app_resource_usage_service = app_services::build_app_resource_usage_service( + metrics_notifier_forwarder, du_cfg.log_cfg.metrics_level.level, json_sink); + + std::vector app_metrics = std::move(app_resource_usage_service.metrics); + + o_du_unit_dependencies du_dependencies; du_dependencies.workers = &workers; du_dependencies.f1c_client_handler = f1c_gw.get(); du_dependencies.f1u_gw = du_f1u_conn.get(); @@ -336,20 +346,38 @@ int main(int argc, char** argv) auto du_inst_and_cmds = o_du_app_unit->create_flexible_o_du_unit(du_dependencies); + // Move app-units metrics to the application metrics. + std::move(du_inst_and_cmds.metrics.begin(), du_inst_and_cmds.metrics.end(), std::back_inserter(app_metrics)); + + // Create periodic metrics report controller. + std::vector producers; + for (auto& metric_cfg : app_metrics) { + for (auto& producer : metric_cfg.producers) { + producers.push_back(producer.get()); + } + } + auto app_metrics_timer = app_timers.create_unique_timer(*workers.non_rt_low_prio_exec); + app_services::periodic_metrics_report_controller periodic_metrics_controller( + producers, std::move(app_metrics_timer), std::chrono::milliseconds(du_cfg.metrics_cfg.rusage_report_period)); + // Only DU has metrics now. - app_services::metrics_manager metrics_mngr( - srslog::fetch_basic_logger("GNB"), *workers.metrics_hub_exec, du_inst_and_cmds.metrics); + app_services::metrics_manager metrics_mngr(srslog::fetch_basic_logger("GNB"), *workers.metrics_hub_exec, app_metrics); // Connect the forwarder to the metrics manager. metrics_notifier_forwarder.connect(metrics_mngr); srs_du::du& du_inst = *du_inst_and_cmds.unit; // Register the commands. - app_services::stdin_command_dispatcher command_parser( - *epoll_broker, *workers.non_rt_low_prio_exec, du_inst_and_cmds.commands); + app_services::cmdline_command_dispatcher command_parser( + *epoll_broker, *workers.non_rt_low_prio_exec, du_inst_and_cmds.commands.cmdline); // Start processing. du_inst.get_operation_controller().start(); + + std::unique_ptr remote_control_server = + app_services::create_remote_server(du_cfg.remote_control_config, du_inst_and_cmds.commands.remote); + + periodic_metrics_controller.start(); { app_services::application_message_banners app_banner(app_name); @@ -357,6 +385,11 @@ int main(int argc, char** argv) std::this_thread::sleep_for(std::chrono::milliseconds(250)); } } + periodic_metrics_controller.stop(); + + if (remote_control_server) { + remote_control_server->stop(); + } // Stop DU activity. du_inst.get_operation_controller().stop(); diff --git a/apps/du/du_appconfig.h b/apps/du/du_appconfig.h index 14548c480d..5f85fefdbb 100644 --- a/apps/du/du_appconfig.h +++ b/apps/du/du_appconfig.h @@ -26,6 +26,7 @@ #include "apps/services/f1u/f1u_cli11_schema.h" #include "apps/services/hal/hal_appconfig.h" #include "apps/services/logger/logger_appconfig.h" +#include "apps/services/remote_control/remote_control_appconfig.h" #include "apps/services/worker_manager/worker_manager_appconfig.h" #include @@ -49,6 +50,8 @@ struct f1u_appconfig { struct metrics_appconfig { std::string addr = "127.0.0.1"; uint16_t port = 55555; + /// Resource usage report period in milliseconds. + unsigned rusage_report_period = 0; }; } // namespace srs_du @@ -71,6 +74,8 @@ struct du_appconfig { expert_execution_appconfig expert_execution_cfg; /// HAL configuration. std::optional hal_config; + /// Remote control configuration. + remote_control_appconfig remote_control_config; }; } // namespace srsran diff --git a/apps/du/du_appconfig_cli11_schema.cpp b/apps/du/du_appconfig_cli11_schema.cpp index 3313c5ef53..267d3ebbaf 100644 --- a/apps/du/du_appconfig_cli11_schema.cpp +++ b/apps/du/du_appconfig_cli11_schema.cpp @@ -24,6 +24,7 @@ #include "apps/services/buffer_pool/buffer_pool_appconfig_cli11_schema.h" #include "apps/services/hal/hal_cli11_schema.h" #include "apps/services/logger/logger_appconfig_cli11_schema.h" +#include "apps/services/remote_control/remote_control_appconfig_cli11_schema.h" #include "apps/services/worker_manager/worker_manager_cli11_schema.h" #include "du_appconfig.h" #include "srsran/adt/interval.h" @@ -37,6 +38,11 @@ static void configure_cli11_metrics_args(CLI::App& app, srs_du::metrics_appconfi app.add_option("--port", metrics_params.port, "Metrics UDP port.") ->capture_default_str() ->check(CLI::Range(0, 65535)); + add_option(app, + "--resource_usage_report_period", + metrics_params.rusage_report_period, + "Resource usage metrics report period (in milliseconds)") + ->capture_default_str(); } static void configure_cli11_f1ap_args(CLI::App& app, srs_du::f1ap_appconfig& f1c_params) @@ -79,6 +85,9 @@ void srsran::configure_cli11_with_du_appconfig_schema(CLI::App& app, du_appconfi // HAL section. du_cfg.hal_config.emplace(); configure_cli11_with_hal_appconfig_schema(app, *du_cfg.hal_config); + + // Remote control section. + configure_cli11_with_remote_control_appconfig_schema(app, du_cfg.remote_control_config); } static void manage_hal_optional(CLI::App& app, du_appconfig& du_cfg) diff --git a/apps/du/du_appconfig_yaml_writer.cpp b/apps/du/du_appconfig_yaml_writer.cpp index a24c8abd95..582b559732 100644 --- a/apps/du/du_appconfig_yaml_writer.cpp +++ b/apps/du/du_appconfig_yaml_writer.cpp @@ -29,8 +29,9 @@ using namespace srsran; static void fill_du_appconfig_metrics_section(YAML::Node node, const srs_du::metrics_appconfig& config) { - node["addr"] = config.addr; - node["port"] = config.port; + node["addr"] = config.addr; + node["port"] = config.port; + node["resource_usage_report_period"] = config.rusage_report_period; } static void fill_du_appconfig_hal_section(YAML::Node node, const std::optional& config) @@ -73,6 +74,13 @@ static void fill_du_appconfig_buffer_pool_section(YAML::Node node, const buffer_ node["segment_size"] = config.segment_size; } +static void fill_du_appconfig_remote_control_section(YAML::Node node, const remote_control_appconfig& config) +{ + node["enabled"] = config.enabled; + node["bind_address"] = config.bind_addr; + node["port"] = config.port; +} + static void fill_du_appconfig_f1u_section(YAML::Node node, const srs_du::f1u_appconfig& config) { node["queue_size"] = config.pdu_queue_size; @@ -92,6 +100,7 @@ void srsran::fill_du_appconfig_in_yaml_schema(YAML::Node& node, const du_appconf fill_du_appconfig_hal_section(node, config.hal_config); fill_du_appconfig_expert_execution_section(node["expert_execution"], config.expert_execution_cfg); fill_du_appconfig_buffer_pool_section(node["buffer_pool"], config.buffer_pool_config); + fill_du_appconfig_remote_control_section(node["remote_control"], config.remote_control_config); fill_du_appconfig_f1u_section(node["f1u"], config.f1u_cfg); fill_du_appconfig_f1ap_section(node["f1ap"], config.f1ap_cfg); } diff --git a/apps/examples/phy/upper_phy_ssb_example.cpp b/apps/examples/phy/upper_phy_ssb_example.cpp index c45443f69c..0c17259a3b 100644 --- a/apps/examples/phy/upper_phy_ssb_example.cpp +++ b/apps/examples/phy/upper_phy_ssb_example.cpp @@ -302,7 +302,7 @@ std::unique_ptr srsran::upper_phy_ssb_example::create(con std::shared_ptr crc_calc_factory = create_crc_calculator_factory_sw("lut"); ASSERT_FACTORY(crc_calc_factory); - std::shared_ptr modulator_factory = create_channel_modulation_sw_factory(); + std::shared_ptr modulator_factory = create_modulation_mapper_factory(); ASSERT_FACTORY(modulator_factory); std::shared_ptr prg_factory = create_pseudo_random_generator_sw_factory(); @@ -384,8 +384,8 @@ std::unique_ptr srsran::upper_phy_ssb_example::create(con } // Create modulation mapper for random data. - std::shared_ptr data_modulator_factory = create_channel_modulation_sw_factory(); - std::unique_ptr data_modulator = data_modulator_factory->create_modulation_mapper(); + std::shared_ptr data_modulator_factory = create_modulation_mapper_factory(); + std::unique_ptr data_modulator = data_modulator_factory->create(); // Create resource grid mapper. std::unique_ptr mapper = rg_mapper_factory->create(); diff --git a/apps/gnb/gnb.cpp b/apps/gnb/gnb.cpp index e2a2def738..b539d8219c 100644 --- a/apps/gnb/gnb.cpp +++ b/apps/gnb/gnb.cpp @@ -23,11 +23,12 @@ #include "apps/services/application_message_banners.h" #include "apps/services/application_tracer.h" #include "apps/services/buffer_pool/buffer_pool_manager.h" +#include "apps/services/cmdline/cmdline_command_dispatcher.h" #include "apps/services/core_isolation_manager.h" #include "apps/services/e2/e2_metric_connector_manager.h" #include "apps/services/metrics/metrics_manager.h" #include "apps/services/metrics/metrics_notifier_proxy.h" -#include "apps/services/stdin_command_dispatcher.h" +#include "apps/services/remote_control/remote_server.h" #include "apps/services/worker_manager/worker_manager.h" #include "apps/units/flexible_o_du/flexible_o_du_application_unit.h" #include "apps/units/flexible_o_du/o_du_high/du_high/du_high_config.h" @@ -454,15 +455,15 @@ int main(int argc, char** argv) // Connect the forwarder to the metrics manager. metrics_notifier_forwarder.connect(metrics_mngr); - std::vector> commands; - for (auto& cmd : o_cucp_unit.commands) { + std::vector> commands; + for (auto& cmd : o_cucp_unit.commands.cmdline) { commands.push_back(std::move(cmd)); } - for (auto& cmd : du_inst_and_cmds.commands) { + for (auto& cmd : du_inst_and_cmds.commands.cmdline) { commands.push_back(std::move(cmd)); } - app_services::stdin_command_dispatcher command_parser(*epoll_broker, *workers.non_rt_low_prio_exec, commands); + app_services::cmdline_command_dispatcher command_parser(*epoll_broker, *workers.non_rt_low_prio_exec, commands); // Connect E1AP to O-CU-CP. e1_gw->attach_cu_cp(o_cucp_obj.get_cu_cp().get_e1_handler()); @@ -484,6 +485,9 @@ int main(int argc, char** argv) // Start processing. du_inst.get_operation_controller().start(); + std::unique_ptr remote_control_server = + app_services::create_remote_server(gnb_cfg.remote_control_config, du_inst_and_cmds.commands.remote); + { app_services::application_message_banners app_banner(app_name); @@ -492,6 +496,10 @@ int main(int argc, char** argv) } } + if (remote_control_server) { + remote_control_server->stop(); + } + // Stop DU activity. du_inst.get_operation_controller().stop(); diff --git a/apps/gnb/gnb_appconfig.h b/apps/gnb/gnb_appconfig.h index 8efe2f9285..de189034a9 100644 --- a/apps/gnb/gnb_appconfig.h +++ b/apps/gnb/gnb_appconfig.h @@ -25,6 +25,7 @@ #include "apps/services/buffer_pool/buffer_pool_appconfig.h" #include "apps/services/hal/hal_appconfig.h" #include "apps/services/logger/logger_appconfig.h" +#include "apps/services/remote_control/remote_control_appconfig.h" #include "apps/services/worker_manager/worker_manager_appconfig.h" #include "srsran/ran/gnb_id.h" #include @@ -61,6 +62,8 @@ struct gnb_appconfig { expert_execution_appconfig expert_execution_cfg; /// HAL configuration. std::optional hal_config; + /// Remote control configuration. + remote_control_appconfig remote_control_config; }; } // namespace srsran diff --git a/apps/gnb/gnb_appconfig_cli11_schema.cpp b/apps/gnb/gnb_appconfig_cli11_schema.cpp index e48b42e70b..15a47017c4 100644 --- a/apps/gnb/gnb_appconfig_cli11_schema.cpp +++ b/apps/gnb/gnb_appconfig_cli11_schema.cpp @@ -24,6 +24,7 @@ #include "apps/services/buffer_pool/buffer_pool_appconfig_cli11_schema.h" #include "apps/services/hal/hal_cli11_schema.h" #include "apps/services/logger/logger_appconfig_cli11_schema.h" +#include "apps/services/remote_control/remote_control_appconfig_cli11_schema.h" #include "apps/services/worker_manager/worker_manager_cli11_schema.h" #include "gnb_appconfig.h" #include "srsran/support/cli11_utils.h" @@ -71,6 +72,9 @@ void srsran::configure_cli11_with_gnb_appconfig_schema(CLI::App& app, gnb_appcon // HAL section. gnb_cfg.hal_config.emplace(); configure_cli11_with_hal_appconfig_schema(app, *gnb_cfg.hal_config); + + // Remote control section. + configure_cli11_with_remote_control_appconfig_schema(app, gnb_cfg.remote_control_config); } void srsran::autoderive_gnb_parameters_after_parsing(CLI::App& app, gnb_appconfig& config) diff --git a/apps/gnb/gnb_appconfig_yaml_writer.cpp b/apps/gnb/gnb_appconfig_yaml_writer.cpp index 607cf025e6..b7c633e945 100644 --- a/apps/gnb/gnb_appconfig_yaml_writer.cpp +++ b/apps/gnb/gnb_appconfig_yaml_writer.cpp @@ -72,6 +72,13 @@ static void fill_gnb_appconfig_buffer_pool_section(YAML::Node node, const buffer node["segment_size"] = config.segment_size; } +static void fill_gnb_appconfig_remote_control_section(YAML::Node node, const remote_control_appconfig& config) +{ + node["enabled"] = config.enabled; + node["bind_address"] = config.bind_addr; + node["port"] = config.port; +} + void srsran::fill_gnb_appconfig_in_yaml_schema(YAML::Node& node, const gnb_appconfig& config) { node["gnb_id"] = config.gnb_id.id; @@ -83,4 +90,5 @@ void srsran::fill_gnb_appconfig_in_yaml_schema(YAML::Node& node, const gnb_appco fill_gnb_appconfig_hal_section(node, config.hal_config); fill_gnb_appconfig_expert_execution_section(node["expert_execution"], config.expert_execution_cfg); fill_gnb_appconfig_buffer_pool_section(node["buffer_pool"], config.buffer_pool_config); + fill_gnb_appconfig_remote_control_section(node["remote_control"], config.remote_control_config); } diff --git a/apps/services/CMakeLists.txt b/apps/services/CMakeLists.txt index 5912d00cd6..fb15a718a7 100644 --- a/apps/services/CMakeLists.txt +++ b/apps/services/CMakeLists.txt @@ -21,24 +21,26 @@ # Do not build by default. set_directory_properties(PROPERTIES EXCLUDE_FROM_ALL TRUE) +add_subdirectory(app_resource_usage) add_subdirectory(buffer_pool) +add_subdirectory(cmdline) add_subdirectory(e2) add_subdirectory(f1u) add_subdirectory(hal) add_subdirectory(logger) add_subdirectory(network) +add_subdirectory(remote_control) add_subdirectory(worker_manager) -set(SOURCES - stdin_command_dispatcher.cpp) - -add_library(srsran_app_services STATIC ${SOURCES}) -target_include_directories(srsran_app_services PRIVATE ${CMAKE_SOURCE_DIR}) -target_link_libraries(srsran_app_services +add_library(srsran_app_services INTERFACE) +target_link_libraries(srsran_app_services INTERFACE srsran_buffer_pool_app_service + srsran_cmdline_app_service srsran_e2_app_service srsran_f1u_app_service - srsran_network_app_service srsran_hal_app_service srsran_logger_app_service + srsran_network_app_service + srsran_remote_control_app_service + srsran_resource_usage_app_service srsran_worker_manager_app_service) diff --git a/apps/services/app_resource_usage/CMakeLists.txt b/apps/services/app_resource_usage/CMakeLists.txt new file mode 100644 index 0000000000..497df5e661 --- /dev/null +++ b/apps/services/app_resource_usage/CMakeLists.txt @@ -0,0 +1,25 @@ +# +# Copyright 2021-2025 Software Radio Systems Limited +# +# This file is part of srsRAN +# +# srsRAN is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# srsRAN is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# A copy of the GNU Affero General Public License can be found in +# the LICENSE file in the top-level directory of this distribution +# and at http://www.gnu.org/licenses/. +# + +set(SOURCES + app_resource_usage.cpp) + +add_library(srsran_resource_usage_app_service STATIC ${SOURCES}) +target_include_directories(srsran_resource_usage_app_service PRIVATE ${CMAKE_SOURCE_DIR}) diff --git a/apps/services/app_resource_usage/app_resource_usage.cpp b/apps/services/app_resource_usage/app_resource_usage.cpp new file mode 100644 index 0000000000..6a40f3ba14 --- /dev/null +++ b/apps/services/app_resource_usage/app_resource_usage.cpp @@ -0,0 +1,84 @@ +/* + * + * Copyright 2021-2025 Software Radio Systems Limited + * + * This file is part of srsRAN. + * + * srsRAN is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsRAN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include "apps/services/app_resource_usage/app_resource_usage.h" +#include "apps/services/app_resource_usage/metrics/app_resource_usage_metrics_consumer.h" +#include "apps/services/app_resource_usage/metrics/app_resource_usage_metrics_producer.h" + +using namespace srsran; +using namespace app_services; + +app_resource_usage::app_resource_usage() +{ + last_snapshot = now(resource_usage_utils::rusage_measurement_type::PROCESS); + if (!last_snapshot) { + srslog::fetch_basic_logger("METRICS").warning( + "Application resource usage service failed to query current resource usage, errno={}", last_snapshot.error()); + } +} + +resource_usage_metrics app_resource_usage::get_new_metrics() +{ + auto current_snapshot = now(resource_usage_utils::rusage_measurement_type::PROCESS); + if (!current_snapshot) { + srslog::fetch_basic_logger("METRICS").warning( + "Application resource usage service failed to query current resource usage, errno={}", + current_snapshot.error()); + return {}; + } + if (!last_snapshot) { + last_snapshot = current_snapshot.value(); + return {}; + } + + resource_usage_utils::measurements measurements; + measurements.duration = std::chrono::duration_cast( + current_snapshot.value().tp - last_snapshot.value().tp); + measurements.user_time = (current_snapshot.value().user_time - last_snapshot.value().user_time); + measurements.system_time = (current_snapshot.value().system_time - last_snapshot.value().system_time); + measurements.max_rss = current_snapshot.value().max_rss; + + last_snapshot = current_snapshot.value(); + return res_usage_measurements_to_metrics(measurements, measurements.duration); +} + +app_resource_usage_service +app_services::build_app_resource_usage_service(app_services::metrics_notifier& metrics_notifier, + srslog::basic_levels metrics_level, + srslog::sink& json_sink) +{ + app_resource_usage_service app_res_usage; + if (metrics_level != srslog::basic_levels::info) { + return app_res_usage; + } + app_res_usage.service = std::make_unique(); + + app_services::metrics_config& app_res_usage_metrics = app_res_usage.metrics.emplace_back(); + app_res_usage_metrics.metric_name = resource_usage_metrics_properties_impl().name(); + app_res_usage_metrics.callback = rusage_metrics_callback; + app_res_usage_metrics.producers.emplace_back( + std::make_unique(metrics_notifier, *app_res_usage.service)); + app_res_usage_metrics.consumers.push_back( + std::make_unique(srslog::fetch_basic_logger("METRICS"))); + + return app_res_usage; +} diff --git a/apps/services/app_resource_usage/app_resource_usage.h b/apps/services/app_resource_usage/app_resource_usage.h new file mode 100644 index 0000000000..232bc96517 --- /dev/null +++ b/apps/services/app_resource_usage/app_resource_usage.h @@ -0,0 +1,58 @@ +/* + * + * Copyright 2021-2025 Software Radio Systems Limited + * + * This file is part of srsRAN. + * + * srsRAN is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsRAN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#pragma once + +#include "apps/services/metrics/metrics_config.h" +#include "srsran/support/resource_usage/resource_usage_utils.h" + +namespace srsran { +namespace app_services { + +class metrics_notifier; + +/// This class can be periodically polled for the new app-level resource usage metrics. +class app_resource_usage +{ +public: + app_resource_usage(); + + /// Returns new metrics measured from the last time this method has been called. + resource_usage_metrics get_new_metrics(); + +private: + expected last_snapshot; +}; + +/// Aggregates application resource usage service with the related metrics. +struct app_resource_usage_service { + std::unique_ptr service; + std::vector metrics; +}; + +/// Builds application resource usage service and related metrics. +app_resource_usage_service build_app_resource_usage_service(app_services::metrics_notifier& metrics_notifier, + srslog::basic_levels metrics_level, + srslog::sink& json_sink); + +} // namespace app_services +} // namespace srsran diff --git a/apps/services/app_resource_usage/metrics/app_resource_usage_metrics.h b/apps/services/app_resource_usage/metrics/app_resource_usage_metrics.h new file mode 100644 index 0000000000..42ae579b99 --- /dev/null +++ b/apps/services/app_resource_usage/metrics/app_resource_usage_metrics.h @@ -0,0 +1,72 @@ +/* + * + * Copyright 2021-2025 Software Radio Systems Limited + * + * This file is part of srsRAN. + * + * srsRAN is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsRAN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#pragma once + +#include "apps/services/metrics/metrics_consumer.h" +#include "apps/services/metrics/metrics_properties.h" +#include "apps/services/metrics/metrics_set.h" +#include "srsran/srslog/logger.h" +#include "srsran/support/executors/task_executor.h" +#include "srsran/support/resource_usage/resource_usage_metrics.h" + +namespace srsran { + +/// System resources usage metrics properties. +class resource_usage_metrics_properties_impl : public app_services::metrics_properties +{ +public: + std::string_view name() const override { return "Resource usage metrics"; } +}; + +class resource_usage_metrics_impl : public app_services::metrics_set +{ + resource_usage_metrics_properties_impl properties; + resource_usage_metrics metrics; + +public: + explicit resource_usage_metrics_impl(const resource_usage_metrics& metrics_) : metrics(metrics_) {} + + // See interface for documentation. + const app_services::metrics_properties& get_properties() const override { return properties; } + + const resource_usage_metrics& get_metrics() const { return metrics; } +}; + +/// Callback for the Resource usage metrics. +// TODO: replace with better solution that doesn't allocate memory. +inline auto rusage_metrics_callback = [](const app_services::metrics_set& report, + span consumers, + task_executor& executor, + srslog::basic_logger& logger) { + const auto& metric = static_cast(report); + + if (!executor.defer([metric, consumers]() { + for (auto& consumer : consumers) { + consumer->handle_metric(metric); + } + })) { + logger.error("Failed to dispatch the metric '{}'", metric.get_properties().name()); + } +}; + +} // namespace srsran diff --git a/apps/services/app_resource_usage/metrics/app_resource_usage_metrics_consumer.h b/apps/services/app_resource_usage/metrics/app_resource_usage_metrics_consumer.h new file mode 100644 index 0000000000..ac025c9573 --- /dev/null +++ b/apps/services/app_resource_usage/metrics/app_resource_usage_metrics_consumer.h @@ -0,0 +1,51 @@ +/* + * + * Copyright 2021-2025 Software Radio Systems Limited + * + * This file is part of srsRAN. + * + * srsRAN is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsRAN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#pragma once + +#include "apps/services/app_resource_usage/metrics/app_resource_usage_metrics.h" +#include "srsran/srslog/logger.h" + +namespace srsran { + +/// Consumer for the log resource usage metrics. +class resource_usage_metrics_consumer_log : public app_services::metrics_consumer +{ +public: + explicit resource_usage_metrics_consumer_log(srslog::basic_logger& logger_) : logger(logger_) {} + + // See interface for documentation. + void handle_metric(const app_services::metrics_set& metric) override + { + const resource_usage_metrics& sys_metrics = static_cast(metric).get_metrics(); + + logger.info("Application CPU usage: {}%, {} CPUs", + sys_metrics.cpu_stats.cpu_usage_percentage, + sys_metrics.cpu_stats.cpu_utilization_nof_cpus); + logger.info("Application memory usage: {} Bytes", sys_metrics.memory_stats.memory_usage.value()); + } + +private: + srslog::basic_logger& logger; +}; + +} // namespace srsran diff --git a/apps/services/app_resource_usage/metrics/app_resource_usage_metrics_producer.h b/apps/services/app_resource_usage/metrics/app_resource_usage_metrics_producer.h new file mode 100644 index 0000000000..07f4a819d4 --- /dev/null +++ b/apps/services/app_resource_usage/metrics/app_resource_usage_metrics_producer.h @@ -0,0 +1,53 @@ +/* + * + * Copyright 2021-2025 Software Radio Systems Limited + * + * This file is part of srsRAN. + * + * srsRAN is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsRAN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#pragma once + +#include "apps/services/app_resource_usage/app_resource_usage.h" +#include "apps/services/metrics/metrics_notifier.h" +#include "apps/services/metrics/metrics_producer.h" +#include "srsran/support/timers.h" + +namespace srsran { + +/// Resource usage metrics producer implementation. +class resource_usage_metrics_producer_impl : public app_services::metrics_producer +{ +public: + resource_usage_metrics_producer_impl(app_services::metrics_notifier& notifier_, + app_services::app_resource_usage& app_resource_usage_) : + notifier(notifier_), app_resource_usage(app_resource_usage_) + { + } + + void on_new_report_period() override + { + resource_usage_metrics new_metrics = app_resource_usage.get_new_metrics(); + notifier.on_new_metric(resource_usage_metrics_impl(new_metrics)); + } + +private: + app_services::metrics_notifier& notifier; + app_services::app_resource_usage& app_resource_usage; +}; + +} // namespace srsran diff --git a/apps/services/buffer_pool/buffer_pool_appconfig_cli11_schema.h b/apps/services/buffer_pool/buffer_pool_appconfig_cli11_schema.h index f5c0e49e62..4ed3408d92 100644 --- a/apps/services/buffer_pool/buffer_pool_appconfig_cli11_schema.h +++ b/apps/services/buffer_pool/buffer_pool_appconfig_cli11_schema.h @@ -22,13 +22,13 @@ #pragma once -#include +#include "CLI/CLI11.hpp" namespace srsran { struct buffer_pool_appconfig; -/// Configures the given CLI11 application with the logger application configuration schema. +/// Configures the given CLI11 application with the buffer pool application configuration schema. void configure_cli11_with_buffer_pool_appconfig_schema(CLI::App& app, buffer_pool_appconfig& config); } // namespace srsran diff --git a/apps/services/cmdline/CMakeLists.txt b/apps/services/cmdline/CMakeLists.txt new file mode 100644 index 0000000000..b928b1e28d --- /dev/null +++ b/apps/services/cmdline/CMakeLists.txt @@ -0,0 +1,28 @@ +# +# Copyright 2021-2025 Software Radio Systems Limited +# +# This file is part of srsRAN +# +# srsRAN is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# srsRAN is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# A copy of the GNU Affero General Public License can be found in +# the LICENSE file in the top-level directory of this distribution +# and at http://www.gnu.org/licenses/. +# + +# Do not build by default. +set_directory_properties(PROPERTIES EXCLUDE_FROM_ALL TRUE) + +set(SOURCES + cmdline_command_dispatcher.cpp) + +add_library(srsran_cmdline_app_service STATIC ${SOURCES}) +target_include_directories(srsran_cmdline_app_service PRIVATE ${CMAKE_SOURCE_DIR}) diff --git a/apps/services/application_command.h b/apps/services/cmdline/cmdline_command.h similarity index 85% rename from apps/services/application_command.h rename to apps/services/cmdline/cmdline_command.h index ebab49bc46..c9ac281266 100644 --- a/apps/services/application_command.h +++ b/apps/services/cmdline/cmdline_command.h @@ -28,14 +28,14 @@ namespace srsran { namespace app_services { -/// \brief Application command interface. +/// \brief Command-line command interface. /// -/// This interface allows to define commands that change the behavior of the application. -class application_command +/// This interface allows to define commands for the command line that change the behavior of the application. +class cmdline_command { public: /// Default destructor. - virtual ~application_command() = default; + virtual ~cmdline_command() = default; /// Returns the name of this command. virtual std::string_view get_name() const = 0; diff --git a/apps/services/stdin_command_dispatcher.cpp b/apps/services/cmdline/cmdline_command_dispatcher.cpp similarity index 88% rename from apps/services/stdin_command_dispatcher.cpp rename to apps/services/cmdline/cmdline_command_dispatcher.cpp index b3802e1354..69e1a16c2f 100644 --- a/apps/services/stdin_command_dispatcher.cpp +++ b/apps/services/cmdline/cmdline_command_dispatcher.cpp @@ -20,8 +20,8 @@ * */ -#include "stdin_command_dispatcher.h" -#include "stdin_command_dispatcher_utils.h" +#include "cmdline_command_dispatcher.h" +#include "cmdline_command_dispatcher_utils.h" #include "srsran/srslog/srslog.h" #include #include @@ -33,7 +33,7 @@ using namespace app_services; namespace { /// Command that manages closing the application. -class close_app_command : public application_command +class close_app_command : public cmdline_command { public: // See interface for documentation. @@ -43,11 +43,11 @@ class close_app_command : public application_command std::string_view get_description() const override { return ": quit application"; } // See interface for documentation. - void execute(span args) override { ::raise(SIGTERM); } + void execute(span args) override { std::raise(SIGTERM); } }; /// Command that sleeps the application. -class sleep_app_command : public application_command +class sleep_app_command : public cmdline_command { public: // See interface for documentation. @@ -89,9 +89,9 @@ class sleep_app_command : public application_command } // namespace -stdin_command_dispatcher::stdin_command_dispatcher(io_broker& io_broker, - task_executor& executor, - span> commands_) : +cmdline_command_dispatcher::cmdline_command_dispatcher(io_broker& io_broker, + task_executor& executor, + span> commands_) : logger(srslog::fetch_basic_logger("APP")) { // Add the sleep command. @@ -143,7 +143,7 @@ static void string_parse_list(const std::string& input, char delimiter, std::vec } } -void stdin_command_dispatcher::parse_stdin() +void cmdline_command_dispatcher::parse_stdin() { static constexpr size_t read_chunk = 256; unsigned total_bytes_read = 0; @@ -183,7 +183,7 @@ void stdin_command_dispatcher::parse_stdin() } } -void stdin_command_dispatcher::handle_command(const std::string& command) +void cmdline_command_dispatcher::handle_command(const std::string& command) { // Print help message if the command is empty. if (command.empty()) { @@ -204,7 +204,7 @@ void stdin_command_dispatcher::handle_command(const std::string& command) } } -void stdin_command_dispatcher::print_help() +void cmdline_command_dispatcher::print_help() { fmt::print("Available commands:\n"); for (const auto& command : commands) { diff --git a/apps/services/stdin_command_dispatcher.h b/apps/services/cmdline/cmdline_command_dispatcher.h similarity index 66% rename from apps/services/stdin_command_dispatcher.h rename to apps/services/cmdline/cmdline_command_dispatcher.h index 2b4e631160..38c03703a4 100644 --- a/apps/services/stdin_command_dispatcher.h +++ b/apps/services/cmdline/cmdline_command_dispatcher.h @@ -22,7 +22,7 @@ #pragma once -#include "application_command.h" +#include "cmdline_command.h" #include "srsran/adt/span.h" #include "srsran/srslog/logger.h" #include "srsran/support/io/io_broker.h" @@ -32,31 +32,31 @@ namespace srsran { namespace app_services { -/// \brief Standard input command dispatcher. +/// \brief Command-line command dispatcher. /// -/// The STDIN command dispatcher parses commands from the STDIN and executes them if they were registered upon creation, -/// otherwise prints a list of the registered commands with their description. -class stdin_command_dispatcher +/// The command-line command dispatcher parses commands from the STDIN and executes them if they were registered upon +/// creation, otherwise prints a list of the registered commands with their description. +class cmdline_command_dispatcher { public: - stdin_command_dispatcher(io_broker& io_broker, - task_executor& executor, - span> commands_); + cmdline_command_dispatcher(io_broker& io_broker, + task_executor& executor, + span> commands_); private: /// Parses any contents in the STDIN file descriptor. void parse_stdin(); - /// Handles the given command; + /// Handles the given command. void handle_command(const std::string& command); /// Prints the registered events registered in this console. void print_help(); private: - srslog::basic_logger& logger; - io_broker::subscriber stdin_handle; - std::unordered_map> commands; + srslog::basic_logger& logger; + io_broker::subscriber stdin_handle; + std::unordered_map> commands; }; } // namespace app_services diff --git a/apps/services/stdin_command_dispatcher_utils.h b/apps/services/cmdline/cmdline_command_dispatcher_utils.h similarity index 94% rename from apps/services/stdin_command_dispatcher_utils.h rename to apps/services/cmdline/cmdline_command_dispatcher_utils.h index 55883dec48..398088e62a 100644 --- a/apps/services/stdin_command_dispatcher_utils.h +++ b/apps/services/cmdline/cmdline_command_dispatcher_utils.h @@ -34,7 +34,7 @@ namespace app_services { template inline expected parse_int(std::string_view value) { - static_assert(std::is_integral::value, "Template type is not an integral"); + static_assert(std::is_integral_v, "Template type is not an integral"); Integer out_value; auto [ptr, errorcode] = std::from_chars(value.begin(), value.end(), out_value); @@ -50,7 +50,7 @@ inline expected parse_int(std::string_view value) template inline expected parse_unsigned_hex(std::string_view value) { - static_assert(std::is_integral::value, "Template type is not an integral"); + static_assert(std::is_integral_v, "Template type is not an integral"); // Skip '0x' or '0X' as std::from_chars does not manage it. auto start_pos = value.find('x'); diff --git a/apps/services/f1u/f1u_cli11_schema.h b/apps/services/f1u/f1u_cli11_schema.h index 15d9f982b0..61eae59bc3 100644 --- a/apps/services/f1u/f1u_cli11_schema.h +++ b/apps/services/f1u/f1u_cli11_schema.h @@ -29,19 +29,21 @@ namespace srsran { -/// F1-U sockets configuration +/// F1-U sockets configuration. struct f1u_socket_appconfig { - std::string bind_addr = "127.0.10.1"; /// Bind address used by the F1-U interface - std::optional five_qi; /// If the 5QI is not present, the socket will be used by default. + /// Bind address used by the F1-U interface. + std::string bind_addr = "127.0.10.1"; + /// If the 5QI is not present, the socket will be used by default. + std::optional five_qi; udp_appconfig udp_config; }; -/// F1-U configuration +/// F1-U configuration. struct f1u_sockets_appconfig { std::vector f1u_socket_cfg; }; -/// \brief TODO write docs. +/// Configures the given CLI11 application with the F1U sockets application configuration schema. void configure_cli11_f1u_sockets_args(CLI::App& app, f1u_sockets_appconfig& f1u_params); } // namespace srsran diff --git a/apps/services/logger/CMakeLists.txt b/apps/services/logger/CMakeLists.txt index f91fa65f73..119ba06534 100644 --- a/apps/services/logger/CMakeLists.txt +++ b/apps/services/logger/CMakeLists.txt @@ -18,8 +18,6 @@ # and at http://www.gnu.org/licenses/. # - - add_library(srsran_metrics_logger_utils STATIC metrics_logger_appconfig_cli11_schema.cpp metrics_logger_appconfig_yaml_writer.cpp) target_include_directories(srsran_metrics_logger_utils PRIVATE ${CMAKE_SOURCE_DIR}) diff --git a/apps/services/logger/logger_appconfig_cli11_schema.h b/apps/services/logger/logger_appconfig_cli11_schema.h index 0c5c482520..5b659caee8 100644 --- a/apps/services/logger/logger_appconfig_cli11_schema.h +++ b/apps/services/logger/logger_appconfig_cli11_schema.h @@ -22,7 +22,7 @@ #pragma once -#include +#include "CLI/CLI11.hpp" namespace srsran { diff --git a/apps/services/logger/metrics_logger_appconfig_cli11_schema.h b/apps/services/logger/metrics_logger_appconfig_cli11_schema.h index a6d4e490dc..f1acc796bd 100644 --- a/apps/services/logger/metrics_logger_appconfig_cli11_schema.h +++ b/apps/services/logger/metrics_logger_appconfig_cli11_schema.h @@ -22,7 +22,7 @@ #pragma once -#include +#include "CLI/CLI11.hpp" namespace srsran { diff --git a/apps/services/metrics/metrics_producer.h b/apps/services/metrics/metrics_producer.h index 02e849a8f0..4d28f72689 100644 --- a/apps/services/metrics/metrics_producer.h +++ b/apps/services/metrics/metrics_producer.h @@ -35,6 +35,10 @@ class metrics_producer public: /// Default destructor. virtual ~metrics_producer() = default; + + /// This method can be called periodically to process accumulated metrics and produce the metrics to be consumed by + /// the corresponding metrics consumers. + virtual void on_new_report_period() = 0; }; } // namespace app_services diff --git a/apps/services/network/udp_cli11_schema.h b/apps/services/network/udp_cli11_schema.h index 146b514847..d26ba4f5ae 100644 --- a/apps/services/network/udp_cli11_schema.h +++ b/apps/services/network/udp_cli11_schema.h @@ -35,7 +35,7 @@ struct udp_appconfig { float pool_threshold = 0.9; /// Differentiated Services Code Point value. std::optional dscp; - // External address advertised by the UDP-GW. + /// External address advertised by the UDP-GW. std::string ext_addr = "auto"; }; diff --git a/apps/services/periodic_metrics_report_controller.h b/apps/services/periodic_metrics_report_controller.h new file mode 100644 index 0000000000..c8cb112bcd --- /dev/null +++ b/apps/services/periodic_metrics_report_controller.h @@ -0,0 +1,96 @@ +/* + * + * Copyright 2021-2025 Software Radio Systems Limited + * + * This file is part of srsRAN. + * + * srsRAN is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsRAN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#pragma once + +#include "apps/services/metrics/metrics_config.h" +#include "srsran/support/srsran_assert.h" +#include "srsran/support/timers.h" + +namespace srsran { +namespace app_services { + +/// This controller class uses unique timer and triggers new metrics generation by the registered producers based on a +/// configured period. +class periodic_metrics_report_controller +{ +public: + /// Constructor receives timer object, report period and application metric configs. + periodic_metrics_report_controller(const std::vector& producers_, + unique_timer timer_, + std::chrono::milliseconds report_period_) : + timer(std::move(timer_)), report_period(report_period_) + { + srsran_assert(timer.is_valid(), "Invalid timer passed to metrics controller"); + timer.set(report_period, [this](timer_id_t tid) { report_metrics(); }); + + // Save pointers to the given metrics producers. + producers.assign(producers_.begin(), producers_.end()); + } + + /// Starts the metrics report timer. + void start() + { + if (!report_period.count()) { + return; + } + stopped.store(false, std::memory_order_relaxed); + timer.run(); + } + + /// Stops the metrics report timer. + void stop() + { + if (!report_period.count()) { + return; + } + stopped.store(true, std::memory_order_relaxed); + timer.stop(); + } + +private: + /// Trigger metrics report in all registered producers. + void report_metrics() + { + if (stopped.load(std::memory_order_relaxed)) { + return; + } + // Rearm the timer. + timer.run(); + + // Command the producers to report their accumulated metrics. + for (auto* producer : producers) { + producer->on_new_report_period(); + } + } + + /// Timer object armed for configured report period. + unique_timer timer; + /// Metrics report period. + std::chrono::milliseconds report_period{0}; + std::atomic stopped{true}; + /// List of metrics producers managed by this controller. + std::vector producers; +}; + +} // namespace app_services +} // namespace srsran diff --git a/apps/services/remote_control/CMakeLists.txt b/apps/services/remote_control/CMakeLists.txt new file mode 100644 index 0000000000..bd77912cb8 --- /dev/null +++ b/apps/services/remote_control/CMakeLists.txt @@ -0,0 +1,29 @@ +# +# Copyright 2021-2025 Software Radio Systems Limited +# +# This file is part of srsRAN +# +# srsRAN is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# srsRAN is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# A copy of the GNU Affero General Public License can be found in +# the LICENSE file in the top-level directory of this distribution +# and at http://www.gnu.org/licenses/. +# + +add_definitions(-DUWS_NO_ZLIB) + +set(SOURCES + remote_control_appconfig_cli11_schema.cpp + remote_server.cpp) + +add_library(srsran_remote_control_app_service STATIC ${SOURCES}) +target_include_directories(srsran_remote_control_app_service PRIVATE ${CMAKE_SOURCE_DIR}) +target_link_libraries(srsran_remote_control_app_service PRIVATE uSockets) diff --git a/apps/services/remote_control/remote_command.h b/apps/services/remote_control/remote_command.h new file mode 100644 index 0000000000..d66bf31663 --- /dev/null +++ b/apps/services/remote_control/remote_command.h @@ -0,0 +1,53 @@ +/* + * + * Copyright 2021-2025 Software Radio Systems Limited + * + * This file is part of srsRAN. + * + * srsRAN is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsRAN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#pragma once + +#include "nlohmann/json_fwd.hpp" +#include "srsran/adt/expected.h" +#include +#include + +namespace srsran { +namespace app_services { + +/// \brief Remote command interface. +/// +/// This interface allows to define commands executed by the remote control server. +class remote_command +{ +public: + /// Default destructor. + virtual ~remote_command() = default; + + /// Returns the name of this command. + virtual std::string_view get_name() const = 0; + + /// Returns the description of this command. + virtual std::string_view get_description() const = 0; + + /// Execute this command using the parameters encoded in the given JSON. + virtual error_type execute(const nlohmann::json& json) = 0; +}; + +} // namespace app_services +} // namespace srsran diff --git a/apps/services/remote_control/remote_control_appconfig.h b/apps/services/remote_control/remote_control_appconfig.h new file mode 100644 index 0000000000..0a6ddb0da4 --- /dev/null +++ b/apps/services/remote_control/remote_control_appconfig.h @@ -0,0 +1,37 @@ +/* + * + * Copyright 2021-2025 Software Radio Systems Limited + * + * This file is part of srsRAN. + * + * srsRAN is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsRAN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#pragma once + +#include +#include + +namespace srsran { + +/// Remote control application configuration. +struct remote_control_appconfig { + bool enabled = false; + std::string bind_addr = "127.0.0.1"; + uint16_t port = 8001; +}; + +} // namespace srsran diff --git a/apps/services/remote_control/remote_control_appconfig_cli11_schema.cpp b/apps/services/remote_control/remote_control_appconfig_cli11_schema.cpp new file mode 100644 index 0000000000..2c95245346 --- /dev/null +++ b/apps/services/remote_control/remote_control_appconfig_cli11_schema.cpp @@ -0,0 +1,43 @@ +/* + * + * Copyright 2021-2025 Software Radio Systems Limited + * + * This file is part of srsRAN. + * + * srsRAN is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsRAN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include "apps/services/remote_control/remote_control_appconfig_cli11_schema.h" +#include "apps/services/remote_control/remote_control_appconfig.h" + +using namespace srsran; + +static void configure_cli11_remote_control_args(CLI::App& app, remote_control_appconfig& config) +{ + app.add_option("--enabled", config.enabled, "Enables the Remote Control Server")->always_capture_default(); + app.add_option("--bind_addr", config.bind_addr, "Remote Control Server bind address")->capture_default_str(); + app.add_option("--port", config.port, "Port where the remote control server listens for incoming connections") + ->capture_default_str() + ->check(CLI::Range(0, 65535)); +} + +void srsran::configure_cli11_with_remote_control_appconfig_schema(CLI::App& app, remote_control_appconfig& config) +{ + // Remote control section. + CLI::App* remote_control_subcmd = + app.add_subcommand("remote_control", "Remote control configuration")->configurable(); + configure_cli11_remote_control_args(*remote_control_subcmd, config); +} diff --git a/apps/services/remote_control/remote_control_appconfig_cli11_schema.h b/apps/services/remote_control/remote_control_appconfig_cli11_schema.h new file mode 100644 index 0000000000..10a0a631fd --- /dev/null +++ b/apps/services/remote_control/remote_control_appconfig_cli11_schema.h @@ -0,0 +1,34 @@ +/* + * + * Copyright 2021-2025 Software Radio Systems Limited + * + * This file is part of srsRAN. + * + * srsRAN is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsRAN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#pragma once + +#include "CLI/CLI11.hpp" + +namespace srsran { + +struct remote_control_appconfig; + +/// Configures the given CLI11 application with the remote control application configuration schema. +void configure_cli11_with_remote_control_appconfig_schema(CLI::App& app, remote_control_appconfig& config); + +} // namespace srsran diff --git a/apps/services/remote_control/remote_server.cpp b/apps/services/remote_control/remote_server.cpp new file mode 100644 index 0000000000..21c23dcd35 --- /dev/null +++ b/apps/services/remote_control/remote_server.cpp @@ -0,0 +1,196 @@ +/* + * + * Copyright 2021-2025 Software Radio Systems Limited + * + * This file is part of srsRAN. + * + * srsRAN is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsRAN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include "apps/services/remote_control/remote_server.h" +#include "apps/services/remote_control/remote_command.h" +#include "apps/services/remote_control/remote_control_appconfig.h" +#include "nlohmann/json.hpp" +#include "uWebSockets/App.h" +#include "srsran/support/executors/unique_thread.h" +#include + +using namespace srsran; +using namespace app_services; + +/// Builds an error response encoded in JSON format. +static std::string build_error_response(std::string_view error, std::optional cmd = std::nullopt) +{ + nlohmann::json response; + response["error"] = error; + if (cmd) { + response["cmd"] = std::move(*cmd); + } + return response.dump(); +} + +/// Builds a successful response encoded in JSON format. +static std::string build_success_response(std::string_view cmd) +{ + nlohmann::json response; + response["cmd"] = cmd; + return response.dump(); +} + +namespace { + +/// Command that manages closing the application. +class quit_remote_command : public remote_command +{ +public: + // See interface for documentation. + std::string_view get_name() const override { return "quit"; } + + // See interface for documentation. + std::string_view get_description() const override { return "Quit application"; } + + // See interface for documentation. + error_type execute(const nlohmann::json& json) override + { + std::raise(SIGTERM); + return {}; + } +}; + +/// Remote server implementation. +class remote_server_impl : public remote_server +{ +public: + remote_server_impl(const std::string& bind_addr, unsigned port, span> commands_) + { + // Add the quit command. + { + auto quit_cmd = std::make_unique(); + auto& cmd = commands[std::string(quit_cmd->get_name())]; + cmd = std::move(quit_cmd); + } + + // Store the remote commands. + for (auto& remote_cmd : commands_) { + auto& cmd = commands[std::string(remote_cmd->get_name())]; + cmd = std::move(remote_cmd); + } + + thread = unique_thread("ws_server", [this, bind_addr, port]() { + uWS::App ws_server; + struct dummy_type {}; + ws_server + .ws("/*", + {.compression = uWS::CompressOptions(uWS::DISABLED), + .maxPayloadLength = 16 * 1024, + .idleTimeout = 120, + .maxBackpressure = 16 * 1024 * 1024, + .closeOnBackpressureLimit = false, + .resetIdleTimeoutOnSend = false, + .sendPingsAutomatically = true, + .upgrade = nullptr, + .message = + [this](auto* ws, std::string_view message, uWS::OpCode opCode) { + // Only parse text based messages. + if (opCode != uWS::OpCode::TEXT) { + ws->send( + build_error_response("This WebSocket server only supports opcode TEXT messages"), + uWS::OpCode::TEXT, + false); + return; + } + + // Handle the incoming message and return back the response. + std::string response = handle_command(message); + ws->send(response, uWS::OpCode::TEXT, false); + }}) + .listen(bind_addr, port, [bind_addr, port](auto* listen_socket) { + if (listen_socket) { + fmt::println("Remote control server listening on {}:{}", bind_addr, port); + } else { + fmt::println("Remote control server cannot listen on {}:{}", bind_addr, port); + } + }); + + server = &ws_server; + server_loop = uWS::Loop::get(); + ws_server.run(); + }); + } + + // See interface for documentation. + ~remote_server_impl() override { stop(); } + + // See interface for documentation. + void stop() override + { + // Wait for completion. + if (thread.running()) { + server_loop.load()->defer([this]() { server->close(); }); + thread.join(); + } + } + + /// Handles the given command. + std::string handle_command(std::string_view command) + { + nlohmann::json req; + + try { + req = nlohmann::json::parse(command); + } catch (const nlohmann::json::parse_error& e) { + return build_error_response(e.what()); + } + + auto cmd_key = req.find("cmd"); + if (cmd_key == req.end()) { + return build_error_response("'cmd' object is missing and it is mandatory"); + } + + if (!cmd_key->is_string()) { + return build_error_response("'cmd' object value type should be a string"); + } + + const auto& cmd_value = cmd_key.value().get_ref(); + if (auto cmd = commands.find(cmd_value); cmd != commands.end()) { + if (auto response_str = cmd->second->execute(req); !response_str) { + return build_error_response(response_str.error(), cmd_value); + } + + return build_success_response(cmd_value); + } + + return build_error_response(fmt::format("Unknown command type: {}", cmd_value), cmd_value); + } + +private: + unique_thread thread; + std::atomic server_loop; + uWS::App* server; + std::unordered_map> commands; +}; + +} // namespace + +std::unique_ptr +srsran::app_services::create_remote_server(const remote_control_appconfig& cfg, + span> commands) +{ + if (!cfg.enabled) { + return nullptr; + } + return std::make_unique(cfg.bind_addr, cfg.port, commands); +} diff --git a/apps/services/remote_control/remote_server.h b/apps/services/remote_control/remote_server.h new file mode 100644 index 0000000000..8973ad2316 --- /dev/null +++ b/apps/services/remote_control/remote_server.h @@ -0,0 +1,53 @@ +/* + * + * Copyright 2021-2025 Software Radio Systems Limited + * + * This file is part of srsRAN. + * + * srsRAN is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsRAN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#pragma once + +#include "apps/services/remote_control/remote_command.h" +#include "srsran/adt/span.h" +#include + +namespace srsran { + +struct remote_control_appconfig; + +namespace app_services { + +/// \brief Remote server interface. +/// +/// WebSocket server that listens for external incoming requests. +class remote_server +{ +public: + /// Default destructor. + virtual ~remote_server() = default; + + /// Stops listening new requests. + virtual void stop() = 0; +}; + +/// Creates a Remote Server instance with a give list of commands. +std::unique_ptr create_remote_server(const remote_control_appconfig& cfg, + span> commands); + +} // namespace app_services +} // namespace srsran diff --git a/apps/units/application_unit_commands.h b/apps/units/application_unit_commands.h new file mode 100644 index 0000000000..3a0f335b87 --- /dev/null +++ b/apps/units/application_unit_commands.h @@ -0,0 +1,40 @@ +/* + * + * Copyright 2021-2025 Software Radio Systems Limited + * + * This file is part of srsRAN. + * + * srsRAN is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsRAN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#pragma once + +#include "apps/services/cmdline/cmdline_command.h" +#include "apps/services/remote_control/remote_command.h" +#include +#include + +namespace srsran { + +/// \brief Application unit commands. +/// +/// This container structure stores the commands (both command-line and remote) that the application unit provides. +struct application_unit_commands { + std::vector> cmdline; + std::vector> remote; +}; + +} // namespace srsran diff --git a/apps/units/flexible_o_du/flexible_o_du_commands.h b/apps/units/flexible_o_du/flexible_o_du_commands.h index a49be7b1e7..e5f58cbc33 100644 --- a/apps/units/flexible_o_du/flexible_o_du_commands.h +++ b/apps/units/flexible_o_du/flexible_o_du_commands.h @@ -22,8 +22,8 @@ #pragma once -#include "apps/services/application_command.h" -#include "apps/services/stdin_command_dispatcher_utils.h" +#include "apps/services/cmdline/cmdline_command.h" +#include "apps/services/cmdline/cmdline_command_dispatcher_utils.h" #include "srsran/adt/expected.h" #include "srsran/adt/to_array.h" #include "srsran/ru/ru_controller.h" @@ -32,7 +32,7 @@ namespace srsran { /// Application command to change the transmission gain. -class tx_gain_app_command : public app_services::application_command +class tx_gain_app_command : public app_services::cmdline_command { ru_gain_controller& controller; @@ -74,7 +74,7 @@ class tx_gain_app_command : public app_services::application_command }; /// Application command to change the reception gain. -class rx_gain_app_command : public app_services::application_command +class rx_gain_app_command : public app_services::cmdline_command { ru_gain_controller& controller; @@ -116,7 +116,7 @@ class rx_gain_app_command : public app_services::application_command }; /// Application command to change display the Radio Unit metrics. -class ru_metrics_app_command : public app_services::application_command +class ru_metrics_app_command : public app_services::cmdline_command { ru_controller& controller; @@ -134,7 +134,7 @@ class ru_metrics_app_command : public app_services::application_command }; /// Application command to change the DU log level. -class change_log_level_app_command : public app_services::application_command +class change_log_level_app_command : public app_services::cmdline_command { /// List of possible log channels that can be dynamically changed. static constexpr auto dynamic_log_channels = to_array({"PHY"}); @@ -201,7 +201,7 @@ class change_log_level_app_command : public app_services::application_command }; /// Application command to set the carrier frequency offset. -class cfo_app_command : public app_services::application_command +class cfo_app_command : public app_services::cmdline_command { ru_cfo_controller& controller; @@ -233,12 +233,14 @@ class cfo_app_command : public app_services::application_command return; } - if (!controller.set_tx_cfo(sector_id.value(), cfo.value())) { + cfo_compensation_request cfo_reqs; + cfo_reqs.cfo_hz = cfo.value(); + if (!controller.set_tx_cfo(sector_id.value(), cfo_reqs)) { fmt::print("Setting TX CFO was not successful. The radio may not support this feature.\n"); return; } - if (!controller.set_rx_cfo(sector_id.value(), cfo.value())) { + if (!controller.set_rx_cfo(sector_id.value(), cfo_reqs)) { fmt::print("Setting RX CFO was not successful. The radio may not support this feature.\n"); return; } @@ -246,4 +248,5 @@ class cfo_app_command : public app_services::application_command fmt::print("CFO set to {}Hz for sector {}.\n", cfo.value(), sector_id.value()); } }; + } // namespace srsran diff --git a/apps/units/flexible_o_du/o_du_high/du_high/CMakeLists.txt b/apps/units/flexible_o_du/o_du_high/du_high/CMakeLists.txt index 7ed8ce4796..f699794bc9 100644 --- a/apps/units/flexible_o_du/o_du_high/du_high/CMakeLists.txt +++ b/apps/units/flexible_o_du/o_du_high/du_high/CMakeLists.txt @@ -24,7 +24,8 @@ set(SOURCES du_high_config_cli11_schema.cpp du_high_config_translators.cpp du_high_config_validator.cpp - du_high_config_yaml_writer.cpp) + du_high_config_yaml_writer.cpp + commands/du_high_remote_commands.cpp) add_library(srsran_du_high_unit_helpers STATIC ${SOURCES}) target_include_directories(srsran_du_high_unit_helpers PRIVATE ${CMAKE_SOURCE_DIR}) diff --git a/apps/units/flexible_o_du/o_du_high/du_high/du_high_commands.h b/apps/units/flexible_o_du/o_du_high/du_high/commands/du_high_cmdline_commands.h similarity index 86% rename from apps/units/flexible_o_du/o_du_high/du_high/du_high_commands.h rename to apps/units/flexible_o_du/o_du_high/du_high/commands/du_high_cmdline_commands.h index b242f88bb2..c9d4d4b04a 100644 --- a/apps/units/flexible_o_du/o_du_high/du_high/du_high_commands.h +++ b/apps/units/flexible_o_du/o_du_high/du_high/commands/du_high_cmdline_commands.h @@ -22,13 +22,13 @@ #pragma once -#include "apps/services/application_command.h" -#include "metrics/du_high_scheduler_cell_metrics_consumers.h" +#include "apps/services/cmdline/cmdline_command.h" +#include "apps/units/flexible_o_du/o_du_high/du_high/metrics/du_high_scheduler_cell_metrics_consumers.h" namespace srsran { /// Application command to display/hide the DU high metrics in STDOUT. -class toggle_stdout_metrics_app_command : public app_services::application_command +class toggle_stdout_metrics_app_command : public app_services::cmdline_command { scheduler_cell_metrics_consumer_stdout& printer; diff --git a/apps/units/flexible_o_du/o_du_high/du_high/commands/du_high_remote_commands.cpp b/apps/units/flexible_o_du/o_du_high/du_high/commands/du_high_remote_commands.cpp new file mode 100644 index 0000000000..f64cbfc09c --- /dev/null +++ b/apps/units/flexible_o_du/o_du_high/du_high/commands/du_high_remote_commands.cpp @@ -0,0 +1,94 @@ +/* + * + * Copyright 2021-2025 Software Radio Systems Limited + * + * This file is part of srsRAN. + * + * srsRAN is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsRAN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include "apps/units/flexible_o_du/o_du_high/du_high/commands/du_high_remote_commands.h" +#include "nlohmann/json.hpp" + +using namespace srsran; + +error_type ssb_modify_remote_command::execute(const nlohmann::json& json) +{ + auto cells_key = json.find("cells"); + if (cells_key == json.end()) { + return make_unexpected("'cells' object is missing and it is mandatory"); + } + if (!cells_key->is_array()) { + return make_unexpected("'cells' object value type should be an array"); + } + + auto cells_items = cells_key->items(); + if (cells_items.begin() == cells_items.end()) { + return make_unexpected("'cells' object does not contain any cell entries"); + } + + srs_du::du_param_config_request req; + for (const auto& cell : cells_items) { + auto plmn_key = cell.value().find("plmn"); + if (plmn_key == cell.value().end()) { + return make_unexpected("'plmn' object is missing and it is mandatory"); + } + if (!plmn_key->is_string()) { + return make_unexpected("'plmn' object value type should be a string"); + } + + auto nci_key = cell.value().find("nci"); + if (nci_key == cell.value().end()) { + return make_unexpected("'nci' object is missing and it is mandatory"); + } + if (!nci_key->is_number_unsigned()) { + return make_unexpected("'nci' object value type should be an integer"); + } + + auto plmn = plmn_identity::parse(plmn_key.value().get_ref()); + if (!plmn) { + return make_unexpected("Invalid PLMN identity value"); + } + auto nci = nr_cell_identity::create(nci_key->get()); + if (!nci) { + return make_unexpected("Invalid NR cell identity value"); + } + nr_cell_global_id_t nr_cgi; + nr_cgi.nci = nci.value(); + nr_cgi.plmn_id = plmn.value(); + + auto ssb_block_power_key = cell.value().find("ssb_block_power_dbm"); + if (ssb_block_power_key == cell.value().end()) { + return make_unexpected("'ssb_block_power_dbm' object is missing and it is mandatory"); + } + if (!ssb_block_power_key->is_number_integer()) { + return make_unexpected("'ssb_block_power_dbm' object value type should be an integer"); + } + int ssb_block_power_value = ssb_block_power_key->get(); + if (ssb_block_power_value < -60 || ssb_block_power_value > 50) { + return make_unexpected( + fmt::format("'ssb_block_power_dbm' value out of range, received '{}', valid range is from -60 to 50", + ssb_block_power_value)); + } + req.cells.emplace_back(nr_cgi, ssb_block_power_value); + } + + if (configurator.handle_operator_config_request(req).success) { + return {}; + } + + return make_unexpected("SSB modify command procedure failed to be applied by the DU"); +} diff --git a/apps/units/flexible_o_du/o_du_high/du_high/commands/du_high_remote_commands.h b/apps/units/flexible_o_du/o_du_high/du_high/commands/du_high_remote_commands.h new file mode 100644 index 0000000000..dcf97fa45f --- /dev/null +++ b/apps/units/flexible_o_du/o_du_high/du_high/commands/du_high_remote_commands.h @@ -0,0 +1,48 @@ +/* + * + * Copyright 2021-2025 Software Radio Systems Limited + * + * This file is part of srsRAN. + * + * srsRAN is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsRAN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#pragma once + +#include "apps/services/remote_control/remote_command.h" +#include "srsran/du/du_high/du_manager/du_configurator.h" + +namespace srsran { + +/// Remote command that modifies the SSB parameters. +class ssb_modify_remote_command : public app_services::remote_command +{ + srs_du::du_configurator& configurator; + +public: + explicit ssb_modify_remote_command(srs_du::du_configurator& configurator_) : configurator(configurator_) {} + + // See interface for documentation. + std::string_view get_name() const override { return "ssb_set"; } + + // See interface for documentation. + std::string_view get_description() const override { return "Modifies the SSB parameters"; } + + // See interface for documentation. + error_type execute(const nlohmann::json& json) override; +}; + +} // namespace srsran diff --git a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_cli11_schema.cpp b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_cli11_schema.cpp index da1c7e93f7..c5960388dd 100644 --- a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_cli11_schema.cpp +++ b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_cli11_schema.cpp @@ -1052,6 +1052,15 @@ static void configure_cli11_pucch_args(CLI::App& app, du_high_unit_pucch_config& pucch_params.enable_closed_loop_pw_control, "Enable closed-loop power control for PUCCH") ->capture_default_str(); + app.add_option("--target_sinr_f0", pucch_params.pucch_f0_sinr_target_dB, "Target PUCCH F0 SINR in dB") + ->capture_default_str() + ->check(CLI::Range(-10.0, 20.0)); + app.add_option("--target_sinr_f2", pucch_params.pucch_f2_sinr_target_dB, "Target PUCCH F2 SINR in dB") + ->capture_default_str() + ->check(CLI::Range(-10.0, 20.0)); + app.add_option("--target_sinr_f3", pucch_params.pucch_f3_sinr_target_dB, "Target PUCCH F3 SINR in dB") + ->capture_default_str() + ->check(CLI::Range(-15.0, 10.0)); } static void configure_cli11_srs_args(CLI::App& app, du_high_unit_srs_config& srs_params) @@ -1644,6 +1653,19 @@ static void configure_cli11_epoch_time(CLI::App& app, epoch_time_t& epoch_time) ->check(CLI::Range(0, 9)); } +static void configure_cli11_ta_info(CLI::App& app, ta_info_t& ta_info) +{ + add_option(app, "--ta_common", ta_info.ta_common, "TA common offset") + ->capture_default_str() + ->check(CLI::Range(0, 66485757)); + add_option(app, "--ta_common_drift", ta_info.ta_common_drift, "Drift rate of the common TA") + ->capture_default_str() + ->check(CLI::Range(-257303, 257303)); + add_option(app, "--ta_common_drift_variant", ta_info.ta_common_drift_variant, "Drift rate variation of the common TA") + ->capture_default_str() + ->check(CLI::Range(0, 28949)); +} + static void configure_cli11_ephemeris_info_ecef(CLI::App& app, ecef_coordinates_t& ephemeris_info) { add_option(app, "--pos_x", ephemeris_info.position_x, "X Position of the satellite") @@ -1684,6 +1706,7 @@ static void configure_cli11_ephemeris_info_orbital(CLI::App& app, orbital_coordi static void configure_cli11_ntn_args(CLI::App& app, std::optional& ntn, epoch_time_t& epoch_time, + ta_info_t& ta_info, orbital_coordinates_t& orbital_coordinates, ecef_coordinates_t& ecef_coordinates) { @@ -1693,13 +1716,18 @@ static void configure_cli11_ntn_args(CLI::App& app, ->capture_default_str() ->check(CLI::Range(0, 1023)); - ta_common_t& ta = config.ta_info.emplace(); - add_option(app, "--ta_common", ta.ta_common, "TA common offset"); + app.add_option("--ntn_ul_sync_validity_dur", ntn->ntn_ul_sync_validity_dur, "An UL sync validity duration") + ->capture_default_str() + ->check(CLI::IsMember({5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 120, 180, 240, 900})); // epoch time. CLI::App* epoch_time_subcmd = add_subcommand(app, "epoch_time", "Epoch time for the NTN assistance information"); configure_cli11_epoch_time(*epoch_time_subcmd, epoch_time); + // TA-info + CLI::App* ta_info_subcmd = add_subcommand(app, "ta_info", "TA Info for the NTN assistance information"); + configure_cli11_ta_info(*ta_info_subcmd, ta_info); + // ephemeris configuration. CLI::App* ephem_subcmd_ecef = add_subcommand(app, "ephemeris_info_ecef", "ephermeris information of the satellite in ecef coordinates"); @@ -1711,6 +1739,7 @@ static void configure_cli11_ntn_args(CLI::App& app, } static epoch_time_t epoch_time; +static ta_info_t ta_info; static ecef_coordinates_t ecef_coordinates; static orbital_coordinates_t orbital_coordinates; @@ -1812,7 +1841,8 @@ void srsran::configure_cli11_with_du_high_config_schema(CLI::App& app, du_high_p // NTN section. CLI::App* ntn_subcmd = add_subcommand(app, "ntn", "NTN parameters")->configurable(); - configure_cli11_ntn_args(*ntn_subcmd, parsed_cfg.config.ntn_cfg, epoch_time, orbital_coordinates, ecef_coordinates); + configure_cli11_ntn_args( + *ntn_subcmd, parsed_cfg.config.ntn_cfg, epoch_time, ta_info, orbital_coordinates, ecef_coordinates); // Cell section. add_option_cell( @@ -1882,6 +1912,7 @@ static void manage_ntn_optional(CLI::App& app, du_high_unit_config& gnb_cfg) { auto ntn_app = app.get_subcommand_ptr("ntn"); unsigned nof_epoch_entries = ntn_app->get_subcommand("epoch_time")->count_all(); + unsigned nof_ta_info_entries = ntn_app->get_subcommand("ta_info")->count_all(); unsigned nof_ecef_entries = ntn_app->get_subcommand("ephemeris_info_ecef")->count_all(); unsigned nof_orbital_entries = ntn_app->get_subcommand("ephemeris_orbital")->count_all(); @@ -1889,6 +1920,10 @@ static void manage_ntn_optional(CLI::App& app, du_high_unit_config& gnb_cfg) gnb_cfg.ntn_cfg.value().epoch_time = epoch_time; } + if (nof_ta_info_entries) { + gnb_cfg.ntn_cfg.value().ta_info = ta_info; + } + if (nof_ecef_entries) { gnb_cfg.ntn_cfg.value().ephemeris_info = ecef_coordinates; } else if (nof_orbital_entries) { diff --git a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_translators.cpp b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_translators.cpp index df879da257..8750d419f7 100644 --- a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_translators.cpp +++ b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_translators.cpp @@ -153,8 +153,14 @@ static sib19_info create_sib19_info(const du_high_unit_config& config) if (config.ntn_cfg.value().k_mac.has_value()) { sib19.k_mac = config.ntn_cfg.value().k_mac.value(); } + if (config.ntn_cfg.value().ntn_ul_sync_validity_dur.has_value()) { + sib19.ntn_ul_sync_validity_dur = config.ntn_cfg.value().ntn_ul_sync_validity_dur.value(); + } if (config.ntn_cfg.value().ta_info.has_value()) { sib19.ta_info = config.ntn_cfg.value().ta_info.value(); + sib19.ta_info.value().ta_common /= 0.004072; + sib19.ta_info.value().ta_common_drift /= 0.0002; + sib19.ta_info.value().ta_common_drift_variant /= 0.00002; } if (config.ntn_cfg.value().reference_location.has_value()) { sib19.ref_location = config.ntn_cfg.value().reference_location.value(); @@ -857,9 +863,10 @@ std::map srsran::generate_du_srb_config(const d // SRB1 srb_cfg.insert(std::make_pair(srb_id_t::srb1, srs_du::du_srb_config{})); if (config.srb_cfg.find(srb_id_t::srb1) != config.srb_cfg.end()) { - auto& out_rlc = srb_cfg[srb_id_t::srb1].rlc; - out_rlc.mode = rlc_mode::am; - out_rlc.am = generate_du_rlc_am_config(config.srb_cfg.at(srb_id_t::srb1).rlc); + auto& out_rlc = srb_cfg[srb_id_t::srb1].rlc; + out_rlc.mode = rlc_mode::am; + out_rlc.am = generate_du_rlc_am_config(config.srb_cfg.at(srb_id_t::srb1).rlc); + out_rlc.am.tx.pdcp_sn_len = pdcp_sn_size::size12bits; } else { srb_cfg.at(srb_id_t::srb1).rlc = make_default_srb_rlc_config(); } @@ -867,9 +874,10 @@ std::map srsran::generate_du_srb_config(const d // SRB2 srb_cfg.insert(std::make_pair(srb_id_t::srb2, srs_du::du_srb_config{})); if (config.srb_cfg.find(srb_id_t::srb2) != config.srb_cfg.end()) { - auto& out_rlc = srb_cfg[srb_id_t::srb2].rlc; - out_rlc.mode = rlc_mode::am; - out_rlc.am = generate_du_rlc_am_config(config.srb_cfg.at(srb_id_t::srb2).rlc); + auto& out_rlc = srb_cfg[srb_id_t::srb2].rlc; + out_rlc.mode = rlc_mode::am; + out_rlc.am = generate_du_rlc_am_config(config.srb_cfg.at(srb_id_t::srb2).rlc); + out_rlc.am.tx.pdcp_sn_len = pdcp_sn_size::size12bits; } else { srb_cfg.at(srb_id_t::srb2).rlc = make_default_srb_rlc_config(); } @@ -877,9 +885,10 @@ std::map srsran::generate_du_srb_config(const d // SRB3 srb_cfg.insert(std::make_pair(srb_id_t::srb3, srs_du::du_srb_config{})); if (config.srb_cfg.find(srb_id_t::srb3) != config.srb_cfg.end()) { - auto& out_rlc = srb_cfg[srb_id_t::srb3].rlc; - out_rlc.mode = rlc_mode::am; - out_rlc.am = generate_du_rlc_am_config(config.srb_cfg.at(srb_id_t::srb3).rlc); + auto& out_rlc = srb_cfg[srb_id_t::srb3].rlc; + out_rlc.mode = rlc_mode::am; + out_rlc.am = generate_du_rlc_am_config(config.srb_cfg.at(srb_id_t::srb3).rlc); + out_rlc.am.tx.pdcp_sn_len = pdcp_sn_size::size12bits; } else { srb_cfg.at(srb_id_t::srb3).rlc = make_default_srb_rlc_config(); } diff --git a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_yaml_writer.cpp b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_yaml_writer.cpp index 0104e59d31..eb36623a3d 100644 --- a/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_yaml_writer.cpp +++ b/apps/units/flexible_o_du/o_du_high/du_high/du_high_config_yaml_writer.cpp @@ -584,6 +584,22 @@ static void fill_du_high_sched_expert_section(YAML::Node& node, const du_high_un } } +static YAML::Node build_du_high_srs_section(const du_high_unit_srs_config& config) +{ + YAML::Node node; + + if (config.srs_period_ms.has_value()) { + node["srs_period_ms"] = config.srs_period_ms.value(); + } + node["srs_max_nof_sym_per_slot"] = config.max_nof_symbols_per_slot; + node["srs_nof_sym_per_resource"] = config.nof_symbols; + node["srs_tx_comb"] = config.tx_comb; + node["srs_cyclic_shift_reuse"] = config.cyclic_shift_reuse_factor; + node["srs_sequence_id_reuse"] = config.sequence_id_reuse_factor; + + return node; +} + static YAML::Node build_cell_entry(const du_high_unit_base_cell_config& config) { YAML::Node node; @@ -619,6 +635,7 @@ static YAML::Node build_cell_entry(const du_high_unit_base_cell_config& config) node["paging"] = build_du_high_paging_section(config.paging_cfg); node["csi"] = build_du_high_csi_section(config.csi_cfg); + node["srs"] = build_du_high_srs_section(config.srs_cfg); fill_du_high_sched_expert_section(node, config.sched_expert_cfg); return node; diff --git a/apps/units/flexible_o_du/o_du_high/du_high/metrics/du_high_rlc_metrics_producer.h b/apps/units/flexible_o_du/o_du_high/du_high/metrics/du_high_rlc_metrics_producer.h index ae94156400..335c39e7e9 100644 --- a/apps/units/flexible_o_du/o_du_high/du_high/metrics/du_high_rlc_metrics_producer.h +++ b/apps/units/flexible_o_du/o_du_high/du_high/metrics/du_high_rlc_metrics_producer.h @@ -37,6 +37,9 @@ class rlc_metrics_producer_impl : public rlc_metrics_notifier, public app_servic // See interface for documentation. void report_metrics(const rlc_metrics& metrics) override; + // See interface for documentation. + void on_new_report_period() override {} + private: app_services::metrics_notifier& notifier; }; diff --git a/apps/units/flexible_o_du/o_du_high/du_high/metrics/du_high_scheduler_cell_metrics_producer.cpp b/apps/units/flexible_o_du/o_du_high/du_high/metrics/du_high_scheduler_cell_metrics_producer.cpp index 4a36e33a3e..981280a1f7 100644 --- a/apps/units/flexible_o_du/o_du_high/du_high/metrics/du_high_scheduler_cell_metrics_producer.cpp +++ b/apps/units/flexible_o_du/o_du_high/du_high/metrics/du_high_scheduler_cell_metrics_producer.cpp @@ -51,4 +51,4 @@ app_services::metrics_callback scheduler_metrics_producer_impl::get_callback() logger.error("Failed to dispatch the metric '{}'", report.get_properties().name()); } }; -} \ No newline at end of file +} diff --git a/apps/units/flexible_o_du/o_du_high/du_high/metrics/du_high_scheduler_cell_metrics_producer.h b/apps/units/flexible_o_du/o_du_high/du_high/metrics/du_high_scheduler_cell_metrics_producer.h index 426eaa1f43..4956c60dc3 100644 --- a/apps/units/flexible_o_du/o_du_high/du_high/metrics/du_high_scheduler_cell_metrics_producer.h +++ b/apps/units/flexible_o_du/o_du_high/du_high/metrics/du_high_scheduler_cell_metrics_producer.h @@ -44,6 +44,9 @@ class scheduler_metrics_producer_impl : public scheduler_metrics_notifier, publi // See interface for documentation. void report_metrics(const scheduler_cell_metrics& report) override; + // See interface for documentation. + void on_new_report_period() override {} + /// Callback for the scheduler cell metrics. app_services::metrics_callback get_callback(); diff --git a/apps/units/flexible_o_du/o_du_high/o_du_high_unit_factory.cpp b/apps/units/flexible_o_du/o_du_high/o_du_high_unit_factory.cpp index 52f2386cb9..af39e1fc1c 100644 --- a/apps/units/flexible_o_du/o_du_high/o_du_high_unit_factory.cpp +++ b/apps/units/flexible_o_du/o_du_high/o_du_high_unit_factory.cpp @@ -22,7 +22,8 @@ #include "o_du_high_unit_factory.h" #include "apps/services/e2/e2_metric_connector_manager.h" -#include "du_high/du_high_commands.h" +#include "du_high/commands/du_high_cmdline_commands.h" +#include "du_high/commands/du_high_remote_commands.h" #include "du_high/du_high_config_translators.h" #include "du_high/metrics/du_high_rlc_metrics.h" #include "du_high/metrics/du_high_rlc_metrics_consumers.h" @@ -32,6 +33,7 @@ #include "du_high/metrics/du_high_scheduler_cell_metrics_producer.h" #include "e2/o_du_high_e2_config_translators.h" #include "o_du_high_unit_config.h" +#include "srsran/du/du_high/du_high.h" #include "srsran/du/du_high/du_high_configuration.h" #include "srsran/du/du_high/o_du_high_config.h" #include "srsran/du/du_high/o_du_high_factory.h" @@ -115,12 +117,12 @@ static void validates_derived_du_params(span cells } static scheduler_metrics_notifier* -build_scheduler_du_metrics(std::vector& unit_metrics, - std::vector>& unit_commands, - app_services::metrics_notifier& metrics_notifier, - const o_du_high_unit_config& o_du_high_unit_cfg, - srslog::sink& json_sink, - e2_du_metrics_notifier& e2_notifier) +build_scheduler_du_metrics(std::vector& unit_metrics, + std::vector>& unit_commands, + app_services::metrics_notifier& metrics_notifier, + const o_du_high_unit_config& o_du_high_unit_cfg, + srslog::sink& json_sink, + e2_du_metrics_notifier& e2_notifier) { // Scheduler cell metrics. auto sched_cell_metrics_gen = std::make_unique(metrics_notifier); @@ -131,7 +133,7 @@ build_scheduler_du_metrics(std::vector& sched_metrics_cfg.producers.push_back(std::move(sched_cell_metrics_gen)); const du_high_unit_config& du_hi_cfg = o_du_high_unit_cfg.du_high_cfg.config; - // Create the consumer for STDOUT. Also create the command for toogle the metrics. + // Create the consumer for STDOUT. Also create the command for toggle the metrics. auto metrics_stdout = std::make_unique(du_hi_cfg.metrics.autostart_stdout_metrics); unit_commands.push_back(std::make_unique(*metrics_stdout)); @@ -244,7 +246,7 @@ o_du_high_unit srsran::make_o_du_high_unit(const o_du_high_unit_config& o_du_hi du_hi_deps.sched_ue_metrics_notifier = build_scheduler_du_metrics(odu_unit.metrics, - odu_unit.commands, + odu_unit.commands.cmdline, dependencies.metrics_notifier, o_du_high_unit_cfg, dependencies.json_sink, @@ -281,5 +283,9 @@ o_du_high_unit srsran::make_o_du_high_unit(const o_du_high_unit_config& o_du_hi odu_unit.o_du_hi = srs_du::make_o_du_high(o_du_high_cfg, std::move(dependencies.o_du_hi_dependencies)); report_error_if_not(odu_unit.o_du_hi, "Invalid O-DU high"); + // Create remote commands. + odu_unit.commands.remote.push_back( + std::make_unique(odu_unit.o_du_hi->get_du_high().get_du_configurator())); + return odu_unit; } diff --git a/apps/units/flexible_o_du/o_du_high/o_du_high_unit_factory.h b/apps/units/flexible_o_du/o_du_high/o_du_high_unit_factory.h index 388e829b4e..7ca6985310 100644 --- a/apps/units/flexible_o_du/o_du_high/o_du_high_unit_factory.h +++ b/apps/units/flexible_o_du/o_du_high/o_du_high_unit_factory.h @@ -22,8 +22,8 @@ #pragma once -#include "apps/services/application_command.h" #include "apps/services/metrics/metrics_config.h" +#include "apps/units/application_unit_commands.h" #include "srsran/du/du_high/o_du_high.h" #include "srsran/du/du_high/o_du_high_config.h" @@ -63,9 +63,9 @@ void announce_du_high_cells(const du_high_unit_config& du_high_unit_cfg); /// O-RAN DU high unit. struct o_du_high_unit { - std::unique_ptr o_du_hi; - std::vector> commands; - std::vector metrics; + std::unique_ptr o_du_hi; + application_unit_commands commands; + std::vector metrics; }; /// O-RAN DU high unit dependencies. diff --git a/apps/units/flexible_o_du/o_du_low/du_low_config.h b/apps/units/flexible_o_du/o_du_low/du_low_config.h index a6cb22ec8b..7e39562a17 100644 --- a/apps/units/flexible_o_du/o_du_low/du_low_config.h +++ b/apps/units/flexible_o_du/o_du_low/du_low_config.h @@ -68,6 +68,10 @@ struct du_low_unit_expert_upper_phy_config { /// The request headroom size is the number of delayed slots that the upper physical layer will accept, ie, if the /// current slot is M, the upper phy will consider the slot M - nof_slots_request_headroom as valid and process it. unsigned nof_slots_request_headroom = 0U; + /// \brief Allows resource grid requests on empty uplink slots. + /// + /// An uplink slot is considered empty when it does not contain PUCCH/PUSCH/SRS PDUs. + bool allow_request_on_empty_uplink_slot = false; }; /// DU low logging functionalities. diff --git a/apps/units/flexible_o_du/o_du_low/du_low_config_cli11_schema.cpp b/apps/units/flexible_o_du/o_du_low/du_low_config_cli11_schema.cpp index 03a3f277ec..c38714209d 100644 --- a/apps/units/flexible_o_du/o_du_low/du_low_config_cli11_schema.cpp +++ b/apps/units/flexible_o_du/o_du_low/du_low_config_cli11_schema.cpp @@ -235,6 +235,12 @@ static void configure_cli11_expert_phy_args(CLI::App& app, du_low_unit_expert_up "Maximum request headroom size in slots.") ->capture_default_str() ->check(CLI::Range(0, 30)); + + add_option(app, + "--allow_request_on_empty_uplink_slot", + expert_phy_params.allow_request_on_empty_uplink_slot, + "Generates an uplink request in an uplink slot with no PUCCH/PUSCH/SRS PDUs") + ->capture_default_str(); } static void configure_cli11_hwacc_pdsch_enc_args(CLI::App& app, std::optional& config) diff --git a/apps/units/flexible_o_du/o_du_low/du_low_config_translator.cpp b/apps/units/flexible_o_du/o_du_low/du_low_config_translator.cpp index d183d1a0a0..9c1e0bd3ef 100644 --- a/apps/units/flexible_o_du/o_du_low/du_low_config_translator.cpp +++ b/apps/units/flexible_o_du/o_du_low/du_low_config_translator.cpp @@ -120,24 +120,25 @@ static void generate_du_low_config(srs_du::du_low_config& out_config max_pusch_concurrency = max_puschs_per_slot[i] * nof_ul_slots_per_frame; } - upper_phy_cell.nof_slots_request_headroom = du_low.expert_phy_cfg.nof_slots_request_headroom; - upper_phy_cell.pusch_max_nof_layers = cell.pusch_max_nof_layers; - upper_phy_cell.log_level = du_low.loggers.phy_level; - upper_phy_cell.enable_logging_broadcast = du_low.loggers.broadcast_enabled; - upper_phy_cell.rx_symbol_printer_filename = du_low.loggers.phy_rx_symbols_filename; - upper_phy_cell.rx_symbol_printer_port = du_low.loggers.phy_rx_symbols_port; - upper_phy_cell.rx_symbol_printer_prach = du_low.loggers.phy_rx_symbols_prach; - upper_phy_cell.logger_max_hex_size = du_low.loggers.hex_max_size; - upper_phy_cell.nof_tx_ports = cell.dl_carrier.nof_ant; - upper_phy_cell.nof_rx_ports = cell.ul_carrier.nof_ant; - upper_phy_cell.ldpc_decoder_iterations = du_low.expert_phy_cfg.pusch_decoder_max_iterations; - upper_phy_cell.ldpc_decoder_early_stop = du_low.expert_phy_cfg.pusch_decoder_early_stop; - upper_phy_cell.nof_dl_rg = dl_pipeline_depth + 2; - upper_phy_cell.nof_dl_processors = dl_pipeline_depth; - upper_phy_cell.nof_ul_rg = ul_pipeline_depth; - upper_phy_cell.max_ul_thread_concurrency = du_low.expert_execution_cfg.threads.nof_ul_threads + 1; - upper_phy_cell.max_pusch_concurrency = max_pusch_concurrency; - upper_phy_cell.nof_pusch_decoder_threads = du_low.expert_execution_cfg.threads.nof_pusch_decoder_threads + + upper_phy_cell.nof_slots_request_headroom = du_low.expert_phy_cfg.nof_slots_request_headroom; + upper_phy_cell.allow_request_on_empty_uplink_slot = du_low.expert_phy_cfg.allow_request_on_empty_uplink_slot; + upper_phy_cell.pusch_max_nof_layers = cell.pusch_max_nof_layers; + upper_phy_cell.log_level = du_low.loggers.phy_level; + upper_phy_cell.enable_logging_broadcast = du_low.loggers.broadcast_enabled; + upper_phy_cell.rx_symbol_printer_filename = du_low.loggers.phy_rx_symbols_filename; + upper_phy_cell.rx_symbol_printer_port = du_low.loggers.phy_rx_symbols_port; + upper_phy_cell.rx_symbol_printer_prach = du_low.loggers.phy_rx_symbols_prach; + upper_phy_cell.logger_max_hex_size = du_low.loggers.hex_max_size; + upper_phy_cell.nof_tx_ports = cell.dl_carrier.nof_ant; + upper_phy_cell.nof_rx_ports = cell.ul_carrier.nof_ant; + upper_phy_cell.ldpc_decoder_iterations = du_low.expert_phy_cfg.pusch_decoder_max_iterations; + upper_phy_cell.ldpc_decoder_early_stop = du_low.expert_phy_cfg.pusch_decoder_early_stop; + upper_phy_cell.nof_dl_rg = dl_pipeline_depth + 2; + upper_phy_cell.nof_dl_processors = dl_pipeline_depth; + upper_phy_cell.nof_ul_rg = ul_pipeline_depth; + upper_phy_cell.max_ul_thread_concurrency = du_low.expert_execution_cfg.threads.nof_ul_threads + 1; + upper_phy_cell.max_pusch_concurrency = max_pusch_concurrency; + upper_phy_cell.nof_pusch_decoder_threads = du_low.expert_execution_cfg.threads.nof_pusch_decoder_threads + du_low.expert_execution_cfg.threads.nof_ul_threads; upper_phy_cell.nof_prach_buffer = prach_pipeline_depth * nof_slots_per_subframe; upper_phy_cell.max_nof_td_prach_occasions = prach_cfg.nof_occasions_within_slot; diff --git a/apps/units/flexible_o_du/o_du_low/metrics/channel_modulation_metrics_producer.h b/apps/units/flexible_o_du/o_du_low/metrics/channel_modulation_metrics_producer.h new file mode 100644 index 0000000000..f2a7bbcdc5 --- /dev/null +++ b/apps/units/flexible_o_du/o_du_low/metrics/channel_modulation_metrics_producer.h @@ -0,0 +1,121 @@ +/* + * + * Copyright 2021-2025 Software Radio Systems Limited + * + * This file is part of srsRAN. + * + * srsRAN is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsRAN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#pragma once + +#include "srsran/phy/metrics/phy_metrics_notifiers.h" +#include "srsran/phy/metrics/phy_metrics_reports.h" +#include + +namespace srsran { + +/// Modulation mapper metric producer. +class channel_modulation_metric_producer_impl : private detail::phy_metric_notifier +{ +public: + /// Gets the modulation mapper metric interface. + detail::phy_metric_notifier& get_notifier() { return *this; } + + /// Gets the processing rate in megabits per second. + double get_avg_rate_Mbps(modulation_scheme modulation) const + { + const metrics_per_modulation& metrics = select_metrics(modulation); + return static_cast(get_bits_per_symbol(modulation) * metrics.sum_nof_symbols) / + static_cast(metrics.sum_elapsed_ns) * 1000; + } + + /// Gets the processing rate in millions of bauds per second. + double get_avg_rate_MBaudps(modulation_scheme modulation) const + { + const metrics_per_modulation& metrics = select_metrics(modulation); + return static_cast(metrics.sum_nof_symbols) / static_cast(metrics.sum_elapsed_ns) * 1000; + } + + /// Gets the total amount of time the CRC calculator spent calculating. + std::chrono::nanoseconds get_total_time() const + { + return std::chrono::nanoseconds(qpsk_metrics_collection.sum_elapsed_ns + qam16_metrics_collection.sum_elapsed_ns + + qam64_metrics_collection.sum_elapsed_ns + qam256_metrics_collection.sum_elapsed_ns + + other_metrics_collection.sum_elapsed_ns); + } + +private: + /// Groups all metrics of a single modulation. + struct metrics_per_modulation { + std::atomic sum_nof_symbols = {}; + std::atomic sum_elapsed_ns = {}; + }; + + /// Selects the CRC calculator metrics depending on the polynomial for read-write operations. + metrics_per_modulation& select_metrics(modulation_scheme modulation) + { + switch (modulation) { + case modulation_scheme::QPSK: + return qpsk_metrics_collection; + case modulation_scheme::QAM16: + return qam16_metrics_collection; + case modulation_scheme::QAM64: + return qam64_metrics_collection; + case modulation_scheme::QAM256: + return qam256_metrics_collection; + case modulation_scheme::PI_2_BPSK: + case modulation_scheme::BPSK: + default: + return other_metrics_collection; + } + } + + /// Selects the CRC calculator metrics depending on the polynomial for read-only operations. + const metrics_per_modulation& select_metrics(modulation_scheme modulation) const + { + switch (modulation) { + case modulation_scheme::QPSK: + return qpsk_metrics_collection; + case modulation_scheme::QAM16: + return qam16_metrics_collection; + case modulation_scheme::QAM64: + return qam64_metrics_collection; + case modulation_scheme::QAM256: + return qam256_metrics_collection; + case modulation_scheme::PI_2_BPSK: + case modulation_scheme::BPSK: + default: + return other_metrics_collection; + } + } + + // See interface for documentation. + void new_metric(const channel_modulation_metrics& metrics) override + { + metrics_per_modulation& metrics_modulation = select_metrics(metrics.modulation); + metrics_modulation.sum_nof_symbols += metrics.nof_symbols; + metrics_modulation.sum_elapsed_ns += metrics.elapsed.count(); + } + + metrics_per_modulation qpsk_metrics_collection; + metrics_per_modulation qam16_metrics_collection; + metrics_per_modulation qam64_metrics_collection; + metrics_per_modulation qam256_metrics_collection; + metrics_per_modulation other_metrics_collection; +}; + +} // namespace srsran diff --git a/apps/units/flexible_o_du/o_du_low/metrics/crc_calculator_metrics_producer.h b/apps/units/flexible_o_du/o_du_low/metrics/crc_calculator_metrics_producer.h index f59c3af36b..e686ab64a1 100644 --- a/apps/units/flexible_o_du/o_du_low/metrics/crc_calculator_metrics_producer.h +++ b/apps/units/flexible_o_du/o_du_low/metrics/crc_calculator_metrics_producer.h @@ -57,7 +57,7 @@ class crc_calculator_metric_producer_impl : private crc_calculator_metric_notifi } private: - /// Groups metrics a single polynomial. + /// Groups all metrics of a single polynomial. struct metrics_per_polynomial { std::atomic sum_nof_bits = {}; std::atomic sum_elapsed_ns = {}; @@ -109,7 +109,6 @@ class crc_calculator_metric_producer_impl : private crc_calculator_metric_notifi ++metrics_poly.count; } - /// Collection of metrics indexed by polynomials. metrics_per_polynomial crc16_metrics_collection; metrics_per_polynomial crc24A_metrics_collection; metrics_per_polynomial crc24B_metrics_collection; diff --git a/apps/units/flexible_o_du/o_du_low/metrics/du_low_metric_producer_impl.h b/apps/units/flexible_o_du/o_du_low/metrics/du_low_metric_producer_impl.h index 79b682c6ad..03ff2c0a8b 100644 --- a/apps/units/flexible_o_du/o_du_low/metrics/du_low_metric_producer_impl.h +++ b/apps/units/flexible_o_du/o_du_low/metrics/du_low_metric_producer_impl.h @@ -23,13 +23,23 @@ #pragma once #include "channel_equalizer_metrics_producer.h" +#include "channel_modulation_metrics_producer.h" #include "channel_precoder_metrics_producer.h" #include "crc_calculator_metrics_producer.h" #include "ldpc_decoder_metrics_producer.h" #include "ldpc_encoder_metrics_producer.h" +#include "ldpc_rate_dematcher_metrics_producer.h" +#include "ldpc_rate_matcher_metrics_producer.h" +#include "pdsch_dmrs_generator_metrics_producer.h" +#include "pdsch_processor_metrics_producer.h" +#include "port_channel_estimator_metrics_producer.h" #include "pseudo_random_sequence_metrics_producer.h" #include "pusch_channel_estimator_metrics_producer.h" +#include "pusch_demodulator_metrics_producer.h" #include "pusch_processor_metrics_producer.h" +#include "time_alignment_estimator_metrics_producer.h" +#include "transform_precoder_metrics_producer.h" +#include "ulsch_demultiplex_metrics_producer.h" #include "fmt/format.h" namespace srsran { @@ -44,11 +54,19 @@ class du_low_metric_producer_impl : public app_services::metrics_producer, priva /// Default destructor - prints current metrics. ~du_low_metric_producer_impl() override { - std::chrono::nanoseconds ldpc_decoder_total_time = ldpc_decoder_producer.get_total_time(); - std::chrono::nanoseconds pusch_channel_estimator_total_time = pusch_channel_estimator_producer.get_total_time(); - std::chrono::nanoseconds pusch_processor_total_time = pusch_processor_producer.get_total_time(); - std::chrono::nanoseconds pusch_scrambling_total_time = pusch_scrambling_producer.get_total_time(); - std::chrono::nanoseconds pusch_equalizer_total_time = pusch_channel_equalizer_producer.get_total_time(); + std::chrono::nanoseconds ldpc_decoder_total_time = ldpc_decoder_producer.get_total_time(); + std::chrono::nanoseconds pusch_channel_estimator_total_time = pusch_channel_estimator_producer.get_total_time(); + std::chrono::nanoseconds pusch_processor_total_time = pusch_processor_producer.get_total_time(); + std::chrono::nanoseconds pusch_scrambling_total_time = pusch_scrambling_producer.get_total_time(); + std::chrono::nanoseconds pusch_equalizer_total_time = pusch_channel_equalizer_producer.get_total_time(); + std::chrono::nanoseconds pusch_demodulation_total_time = pusch_demodulation_mapper_producer.get_total_time(); + std::chrono::nanoseconds pusch_evm_calc_total_time = pusch_evm_calculator_producer.get_total_time(); + std::chrono::nanoseconds pusch_waiting_time = pusch_processor_producer.get_total_wait_time(); + std::chrono::nanoseconds ulsch_demux_total_time = ulsch_demultiplex_producer.get_total_time(); + std::chrono::nanoseconds pusch_demodulator_total_time = pusch_demodulator_producer.get_total_time(); + std::chrono::nanoseconds pusch_ta_estimator_total_time = pusch_ta_estimator_producer.get_total_time(); + std::chrono::nanoseconds pusch_port_ch_estimator_total_time = pusch_port_ch_estimator_producer.get_total_time(); + std::chrono::nanoseconds pusch_transform_precoding_total_time = pusch_transform_precoder_producer.get_total_time(); double ldpc_decoder_percent = 100.0 * static_cast(ldpc_decoder_total_time.count()) / static_cast(pusch_processor_total_time.count()); @@ -58,12 +76,34 @@ class du_low_metric_producer_impl : public app_services::metrics_producer, priva static_cast(pusch_processor_total_time.count()); double pusch_equalizer_percent = 100.0 * static_cast(pusch_equalizer_total_time.count()) / static_cast(pusch_processor_total_time.count()); + double pusch_demodulation_percent = 100.0 * static_cast(pusch_demodulation_total_time.count()) / + static_cast(pusch_processor_total_time.count()); + double pusch_evm_calc_percent = 100.0 * static_cast(pusch_evm_calc_total_time.count()) / + static_cast(pusch_processor_total_time.count()); + double pusch_wait_time_percent = 100.0 * static_cast(pusch_waiting_time.count()) / + static_cast(pusch_processor_total_time.count()); + double ulsch_demux_time_percent = 100.0 * static_cast(ulsch_demux_total_time.count()) / + static_cast(pusch_processor_total_time.count()); + double pusch_demodulator_time_percent = 100.0 * static_cast(pusch_demodulator_total_time.count()) / + static_cast(pusch_processor_total_time.count()); + double pusch_ta_estimator_time_percent = 100.0 * static_cast(pusch_ta_estimator_total_time.count()) / + static_cast(pusch_processor_total_time.count()); + double pusch_port_ch_estimator_time_percent = 100.0 * + static_cast(pusch_port_ch_estimator_total_time.count()) / + static_cast(pusch_processor_total_time.count()); + double pusch_transform_precoding_time_percent = 100.0 * + static_cast(pusch_transform_precoding_total_time.count()) / + static_cast(pusch_processor_total_time.count()); fmt::print("--- LDPC Encoder metrics (per codeblock) ---\n"); fmt::print(" Avg. CB size: {:.2f} bits\n", ldpc_encoder_producer.get_avg_cb_size()); fmt::print(" Avg. latency: {:.2f} us\n", ldpc_encoder_producer.get_avg_cb_latency_us()); fmt::print(" Encode rate: {:.2f} Mbps\n", ldpc_encoder_producer.get_encode_rate_Mbps()); fmt::print("\n"); + fmt::print("--- LDPC Rate matcher (per codeblock) ---\n"); + fmt::print(" Avg. latency: {:.2f} us\n", ldpc_rate_matcher_producer.get_avg_cb_latency_us()); + fmt::print(" Processing rate: {:.2f} Mbps\n", ldpc_rate_matcher_producer.get_avg_rate_Mbps()); + fmt::print("\n"); fmt::print("--- CRC calculator ---\n"); fmt::print(" PDSCH CRC16 Avg. Latency: {:.2f} us\n", pdsch_crc_calculator_producer.get_avg_latency_us(crc_generator_poly::CRC16)); @@ -96,6 +136,10 @@ class du_low_metric_producer_impl : public app_services::metrics_producer, priva fmt::print(" Avg. iterations: {:.2f} iter\n", ldpc_decoder_producer.get_avg_nof_iterations()); fmt::print(" Decode rate: {:.2f} Mbps\n", ldpc_decoder_producer.get_decode_rate_Mbps()); fmt::print("\n"); + fmt::print("--- LDPC Rate dematcher (per codeblock) ---\n"); + fmt::print(" Avg. latency: {:.2f} us\n", ldpc_rate_dematcher_producer.get_avg_cb_latency_us()); + fmt::print(" Processing rate: {:.2f} Mbps\n", ldpc_rate_dematcher_producer.get_avg_rate_Mbps()); + fmt::print("\n"); fmt::print("--- PUSCH Channel estimator metrics ---\n"); fmt::print(" Avg. latency: {:.2f} us\n", pusch_channel_estimator_producer.get_average_latency()); fmt::print(" Avg. processing rate: {:.2f} MPRBps\n", pusch_channel_estimator_producer.get_processing_rate()); @@ -118,14 +162,59 @@ class du_low_metric_producer_impl : public app_services::metrics_producer, priva fmt::print(" Avg. PDSCH advance rate: {:.2f} Mbps\n", pdsch_scrambling_producer.get_advance_rate_Mbps()); fmt::print(" Avg. PDSCH generate rate: {:.2f} Mbps\n", pdsch_scrambling_producer.get_generate_rate_Mbps()); fmt::print("\n"); + fmt::print("--- Transform precoding ---\n"); + fmt::print(" Avg. Transform rate: {:.2f} MREps\n", pusch_transform_precoder_producer.get_avg_rate_MREps()); + fmt::print(" Avg. Transform latency: {:.2f} us/symbol\n", pusch_transform_precoder_producer.get_avg_latency_us()); + fmt::print("\n"); + fmt::print("--- Modulation, demodulation and EVM calculation ---\n"); + fmt::print(" Modulation rate QPSK: {:.2f} Mbps\n", + pdsch_modulation_mapper_producer.get_avg_rate_Mbps(modulation_scheme::QPSK)); + fmt::print(" 16-QAM: {:.2f} Mbps\n", + pdsch_modulation_mapper_producer.get_avg_rate_Mbps(modulation_scheme::QAM16)); + fmt::print(" 64-QAM: {:.2f} Mbps\n", + pdsch_modulation_mapper_producer.get_avg_rate_Mbps(modulation_scheme::QAM64)); + fmt::print(" 256-QAM: {:.2f} Mbps\n", + pdsch_modulation_mapper_producer.get_avg_rate_Mbps(modulation_scheme::QAM256)); + fmt::print(" Demodulation rate QPSK: {:.2f} Mbps\n", + pusch_demodulation_mapper_producer.get_avg_rate_Mbps(modulation_scheme::QPSK)); + fmt::print(" 16-QAM: {:.2f} Mbps\n", + pusch_demodulation_mapper_producer.get_avg_rate_Mbps(modulation_scheme::QAM16)); + fmt::print(" 64-QAM: {:.2f} Mbps\n", + pusch_demodulation_mapper_producer.get_avg_rate_Mbps(modulation_scheme::QAM64)); + fmt::print(" 256-QAM: {:.2f} Mbps\n", + pusch_demodulation_mapper_producer.get_avg_rate_Mbps(modulation_scheme::QAM256)); + fmt::print(" EVM calculator rate QPSK: {:.2f} Mbps\n", + pusch_evm_calculator_producer.get_avg_rate_Mbps(modulation_scheme::QPSK)); + fmt::print(" 16-QAM: {:.2f} Mbps\n", + pusch_evm_calculator_producer.get_avg_rate_Mbps(modulation_scheme::QAM16)); + fmt::print(" 64-QAM: {:.2f} Mbps\n", + pusch_evm_calculator_producer.get_avg_rate_Mbps(modulation_scheme::QAM64)); + fmt::print(" 256-QAM: {:.2f} Mbps\n", + pusch_evm_calculator_producer.get_avg_rate_Mbps(modulation_scheme::QAM256)); + fmt::print("\n"); + fmt::print("--- UL-SCH demux ---\n"); + fmt::print(" Avg. init time: {:.2f} us\n", ulsch_demultiplex_producer.get_average_init_time_us()); + fmt::print(" Avg. finish time: {:.2f} us\n", ulsch_demultiplex_producer.get_average_finish_time_us()); + fmt::print(" Avg. processing rate: {:.2f} Mbps\n", ulsch_demultiplex_producer.get_average_rate_Mbps()); + fmt::print("\n"); fmt::print("--- PUSCH Processor metrics ---\n"); fmt::print(" Avg. data latency: {:.2f} us\n", pusch_processor_producer.get_avg_data_latency_us()); fmt::print(" Avg. UCI latency: {:.2f} us\n", pusch_processor_producer.get_avg_uci_latency_us()); fmt::print(" Avg. processing PUSCH rate: {:.2f} Mbps\n", pusch_processor_producer.get_processing_rate_Mbps()); fmt::print(" Decoder time: {:.2f} % (asynchronous)\n", ldpc_decoder_percent); - fmt::print(" Channel estimator time: {:.2f} %\n", pusch_channel_estimator_percent); - fmt::print(" Channel equalizer time: {:.2f} %\n", pusch_equalizer_percent); - fmt::print(" Scrambling time: {:.2f} %\n", pusch_scrambling_percent); + fmt::print("\n"); + fmt::print("--- PUSCH Processor breakdown ---\n"); + fmt::print(" |-> Channel estimator: {:.2f} %\n", pusch_channel_estimator_percent); + fmt::print(" |-> Ch. estimator: {:.2f} %\n", pusch_port_ch_estimator_time_percent); + fmt::print(" |-> TA estimator: {:.2f} %\n", pusch_ta_estimator_time_percent); + fmt::print(" |-> Demodulation: {:.2f} %\n", pusch_demodulator_time_percent); + fmt::print(" |---> Channel equalizer: {:.2f} %\n", pusch_equalizer_percent); + fmt::print(" |-> Demodulation mapper: {:.2f} %\n", pusch_demodulation_percent); + fmt::print(" |-----> EVM calculation: {:.2f} %\n", pusch_evm_calc_percent); + fmt::print(" |----------> Scrambling: {:.2f} %\n", pusch_scrambling_percent); + fmt::print(" |-> Transform precoding: {:.2f} %\n", pusch_transform_precoding_time_percent); + fmt::print(" |-> UL-SCH Demux: {:.2f} %\n", ulsch_demux_time_percent); + fmt::print(" |------> Decoder: {:.2f} % (multi-threaded)\n", pusch_wait_time_percent); fmt::print("\n"); fmt::print("--- PDSCH Layer mapping and precoding metrics ---\n"); fmt::print(" Processing rate - one layer: {:.2f} MREps\n", @@ -137,8 +226,19 @@ class du_low_metric_producer_impl : public app_services::metrics_producer, priva fmt::print(" four layers: {:.2f} MREps\n", pdsch_channel_precoder_producer.get_average_rate_MRes(4)); fmt::print("\n"); + fmt::print("--- PDSCH Processor metrics ---\n"); + fmt::print(" Avg. processing latency: {:.2f} us\n", pdsch_processor_producer.get_avg_latency_us()); + fmt::print(" Avg. return latency: {:.2f} us\n", pdsch_processor_producer.get_avg_return_time_us()); + fmt::print(" Avg. processing rate: {:.2f} Mbps\n", pdsch_processor_producer.get_process_rate_Mbps()); + fmt::print("\n"); + fmt::print("--- DM-RS for PDSCH generator metrics ---\n"); + fmt::print(" Avg. generation latency: {:.2f} us\n", pdsch_dmrs_generator_producer.get_avg_latency_us()); + fmt::print("\n"); } + // See interface for documentation. + void on_new_report_period() override {} + upper_phy_metrics_notifiers& get_notifiers() { return *this; } private: @@ -196,12 +296,88 @@ class du_low_metric_producer_impl : public app_services::metrics_producer, priva return pdsch_channel_precoder_producer.get_notifier(); } + // See interface for documentation. + common_channel_modulation_metric_notifier& get_pdsch_modulation_mapper_notifier() override + { + return pdsch_modulation_mapper_producer.get_notifier(); + } + + // See interface for documentation. + common_channel_modulation_metric_notifier& get_pusch_demodulation_mapper_notifier() override + { + return pusch_demodulation_mapper_producer.get_notifier(); + } + + // See interface for documentation. + common_channel_modulation_metric_notifier& get_pusch_evm_calculator_notifier() override + { + return pusch_evm_calculator_producer.get_notifier(); + } + + // See interface for documentation. + ulsch_demultiplex_metric_notifier& get_ulsch_demultiplex_notifier() override + { + return ulsch_demultiplex_producer.get_notifier(); + } + + // See interface for documentation. + pusch_demodulator_metric_notifier& get_pusch_demodulator_notifier() override + { + return pusch_demodulator_producer.get_notifier(); + } + + // See interface for documentation. + time_alignment_estimator_metric_notifier& get_pusch_ta_estimator_notifier() override + { + return pusch_ta_estimator_producer.get_notifier(); + } + + // See interface for documentation. + port_channel_estimator_metric_notifier& get_pusch_port_channel_estimator_notifier() override + { + return pusch_port_ch_estimator_producer.get_notifier(); + } + + // See interface for documentation. + transform_precoder_metric_notifier& get_pusch_transform_precoder_notifier() override + { + return pusch_transform_precoder_producer.get_notifier(); + } + + // See interface for documentation. + ldpc_rate_matcher_metric_notifier& get_ldpc_rate_matcher_notifier() override + { + return ldpc_rate_matcher_producer.get_notifier(); + } + + // See interface for documentation. + ldpc_rate_dematcher_metric_notifier& get_ldpc_rate_dematcher_notifier() override + { + return ldpc_rate_dematcher_producer.get_notifier(); + } + + // See interface for documentation. + pdsch_processor_metric_notifier& get_pdsch_processor_notifier() override + { + return pdsch_processor_producer.get_notifier(); + } + + // See interface for documentation. + pdsch_dmrs_generator_metric_notifier& get_pdsch_dmrs_generator() override + { + return pdsch_dmrs_generator_producer.get_notifier(); + } + /// PDSCH CRC calculator metric producer implementation. crc_calculator_metric_producer_impl pdsch_crc_calculator_producer; /// PUSCH CRC calculator metric producer implementation. crc_calculator_metric_producer_impl pusch_crc_calculator_producer; /// LDPC decoder metric producer implementation. ldpc_decoder_metric_producer_impl ldpc_decoder_producer; + /// LDPC rate matcher producer implementation. + ldpc_rate_matcher_metric_producer_impl ldpc_rate_matcher_producer; + /// LDPC rate dematcher producer implementation. + ldpc_rate_dematcher_metric_producer_impl ldpc_rate_dematcher_producer; /// LDPC encoder metric producer implementation. ldpc_encoder_metric_producer_impl ldpc_encoder_producer; /// PUSCH channel estimator metric producer implementation. @@ -216,6 +392,26 @@ class du_low_metric_producer_impl : public app_services::metrics_producer, priva channel_equalizer_metric_producer_impl pusch_channel_equalizer_producer; /// PDSCH channel precoder notifier. channel_precoder_metric_producer_impl pdsch_channel_precoder_producer; + /// PDSCH modulation mapper notifier. + channel_modulation_metric_producer_impl pdsch_modulation_mapper_producer; + /// PUSCH demodulation mapper notifier. + channel_modulation_metric_producer_impl pusch_demodulation_mapper_producer; + /// PUSCH EVM calculator notifier. + channel_modulation_metric_producer_impl pusch_evm_calculator_producer; + /// UL-SCH demultiplexer producer implementation. + ulsch_demultiplex_metric_producer_impl ulsch_demultiplex_producer; + /// PUSCH demodulator metric producer implementation. + pusch_demodulator_metric_producer_impl pusch_demodulator_producer; + /// Time alignment estimator metric producer. + time_alignment_estimator_metric_producer_impl pusch_ta_estimator_producer; + /// Port channel estimator metric producer. + port_channel_estimator_metric_producer_impl pusch_port_ch_estimator_producer; + /// PUSCH transform precoder metric producer. + transform_precoder_metric_producer_impl pusch_transform_precoder_producer; + /// PDSCH processor metric producer. + pdsch_processor_metric_producer_impl pdsch_processor_producer; + /// PDSCH DM-RS metric producer. + pdsch_dmrs_generator_metric_producer_impl pdsch_dmrs_generator_producer; }; // namespace srsran } // namespace srsran diff --git a/apps/units/flexible_o_du/o_du_low/metrics/ldpc_encoder_metrics_producer.h b/apps/units/flexible_o_du/o_du_low/metrics/ldpc_encoder_metrics_producer.h index cbb5938084..3c1596695d 100644 --- a/apps/units/flexible_o_du/o_du_low/metrics/ldpc_encoder_metrics_producer.h +++ b/apps/units/flexible_o_du/o_du_low/metrics/ldpc_encoder_metrics_producer.h @@ -53,7 +53,7 @@ class ldpc_encoder_metric_producer_impl : private ldpc_encoder_metric_notifier return static_cast(sum_cb_sz) / static_cast(sum_elapsed_ns) * 1000; } - /// Gets the total amount of time the LDPC encoder spent decoding. + /// Gets the total amount of time the LDPC encoder spent encoding. std::chrono::nanoseconds get_total_time() const { return std::chrono::nanoseconds(sum_elapsed_ns); } private: diff --git a/apps/units/flexible_o_du/o_du_low/metrics/ldpc_rate_dematcher_metrics_producer.h b/apps/units/flexible_o_du/o_du_low/metrics/ldpc_rate_dematcher_metrics_producer.h new file mode 100644 index 0000000000..829beab939 --- /dev/null +++ b/apps/units/flexible_o_du/o_du_low/metrics/ldpc_rate_dematcher_metrics_producer.h @@ -0,0 +1,67 @@ +/* + * + * Copyright 2021-2025 Software Radio Systems Limited + * + * This file is part of srsRAN. + * + * srsRAN is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsRAN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#pragma once + +#include "srsran/phy/metrics/phy_metrics_notifiers.h" +#include "srsran/phy/metrics/phy_metrics_reports.h" +#include + +namespace srsran { + +/// LDPC rate dematcher metric producer. +class ldpc_rate_dematcher_metric_producer_impl : private ldpc_rate_dematcher_metric_notifier +{ +public: + /// Gets the LDPC rate dematcher metric interface. + ldpc_rate_dematcher_metric_notifier& get_notifier() { return *this; } + + /// Gets the average codeblock latency in microseconds. + double get_avg_cb_latency_us() const + { + return static_cast(sum_elapsed_ns) / static_cast(count) * 1e-3; + } + + /// Gets the average processing rate. + double get_avg_rate_Mbps() const + { + return static_cast(sum_input_size) / static_cast(sum_elapsed_ns) * 1000; + } + + /// Gets the total processing time. + std::chrono::nanoseconds get_total_time() const { return std::chrono::nanoseconds(sum_elapsed_ns); } + +private: + // See interface for documentation. + void new_metric(const ldpc_rate_dematcher_metrics& metrics) override + { + sum_input_size += metrics.input_size.value(); + sum_elapsed_ns += metrics.elapsed.count(); + ++count; + } + + std::atomic sum_input_size = {}; + std::atomic sum_elapsed_ns = {}; + std::atomic count = {}; +}; + +} // namespace srsran diff --git a/apps/units/flexible_o_du/o_du_low/metrics/ldpc_rate_matcher_metrics_producer.h b/apps/units/flexible_o_du/o_du_low/metrics/ldpc_rate_matcher_metrics_producer.h new file mode 100644 index 0000000000..2c3ffdd8be --- /dev/null +++ b/apps/units/flexible_o_du/o_du_low/metrics/ldpc_rate_matcher_metrics_producer.h @@ -0,0 +1,67 @@ +/* + * + * Copyright 2021-2025 Software Radio Systems Limited + * + * This file is part of srsRAN. + * + * srsRAN is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsRAN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#pragma once + +#include "srsran/phy/metrics/phy_metrics_notifiers.h" +#include "srsran/phy/metrics/phy_metrics_reports.h" +#include + +namespace srsran { + +/// LDPC rate matcher metric producer. +class ldpc_rate_matcher_metric_producer_impl : private ldpc_rate_matcher_metric_notifier +{ +public: + /// Gets the LDPC rate matcher metric interface. + ldpc_rate_matcher_metric_notifier& get_notifier() { return *this; } + + /// Gets the average codeblock latency in microseconds. + double get_avg_cb_latency_us() const + { + return static_cast(sum_elapsed_ns) / static_cast(count) * 1e-3; + } + + /// Gets the average processing rate. + double get_avg_rate_Mbps() const + { + return static_cast(sum_output_size) / static_cast(sum_elapsed_ns) * 1000; + } + + /// Gets the total processing time. + std::chrono::nanoseconds get_total_time() const { return std::chrono::nanoseconds(sum_elapsed_ns); } + +private: + // See interface for documentation. + void new_metric(const ldpc_rate_matcher_metrics& metrics) override + { + sum_output_size += metrics.output_size.value(); + sum_elapsed_ns += metrics.elapsed.count(); + ++count; + } + + std::atomic sum_output_size = {}; + std::atomic sum_elapsed_ns = {}; + std::atomic count = {}; +}; + +} // namespace srsran diff --git a/apps/units/flexible_o_du/o_du_low/metrics/pdsch_dmrs_generator_metrics_producer.h b/apps/units/flexible_o_du/o_du_low/metrics/pdsch_dmrs_generator_metrics_producer.h new file mode 100644 index 0000000000..044aa132cb --- /dev/null +++ b/apps/units/flexible_o_du/o_du_low/metrics/pdsch_dmrs_generator_metrics_producer.h @@ -0,0 +1,56 @@ +/* + * + * Copyright 2021-2025 Software Radio Systems Limited + * + * This file is part of srsRAN. + * + * srsRAN is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsRAN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#pragma once + +#include "srsran/phy/metrics/phy_metrics_notifiers.h" +#include "srsran/phy/metrics/phy_metrics_reports.h" +#include + +namespace srsran { + +/// PDSCH DM-RS generator metric producer. +class pdsch_dmrs_generator_metric_producer_impl : private pdsch_dmrs_generator_metric_notifier +{ +public: + /// Gets the PDSCH DM-RS metric interface. + pdsch_dmrs_generator_metric_notifier& get_notifier() { return *this; } + + /// Gets the average latency in microseconds. + double get_avg_latency_us() const { return static_cast(sum_elapsed_ns) / static_cast(count) * 1e-3; } + + /// Gets the total processing time. + std::chrono::nanoseconds get_total_time() const { return std::chrono::nanoseconds(sum_elapsed_ns); } + +private: + // See interface for documentation. + void new_metric(const pdsch_dmrs_generator_metrics& metrics) override + { + sum_elapsed_ns += metrics.elapsed.count(); + ++count; + } + + std::atomic sum_elapsed_ns = {}; + std::atomic count = {}; +}; + +} // namespace srsran diff --git a/apps/units/flexible_o_du/o_du_low/metrics/pdsch_processor_metrics_producer.h b/apps/units/flexible_o_du/o_du_low/metrics/pdsch_processor_metrics_producer.h new file mode 100644 index 0000000000..22b9bc1c9d --- /dev/null +++ b/apps/units/flexible_o_du/o_du_low/metrics/pdsch_processor_metrics_producer.h @@ -0,0 +1,80 @@ +/* + * + * Copyright 2021-2025 Software Radio Systems Limited + * + * This file is part of srsRAN. + * + * srsRAN is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsRAN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#pragma once + +#include "srsran/phy/metrics/phy_metrics_notifiers.h" +#include "srsran/phy/metrics/phy_metrics_reports.h" +#include + +namespace srsran { + +/// PDSCH processor metric producer. +class pdsch_processor_metric_producer_impl : private pdsch_processor_metric_notifier +{ +public: + /// Gets the PDSCH processor metric interface. + pdsch_processor_metric_notifier& get_notifier() { return *this; } + + /// Gets the total number of processed codeblocks. + uint64_t get_nof_processed_cb() const { return count; } + + /// Gets the average transmission latency in microseconds. + double get_avg_latency_us() const + { + return static_cast(sum_elapsed_completion_ns) / static_cast(count) * 1e-3; + } + + /// \brief Gets the average return time in microseconds. + /// + /// It is the average processing time of a single-thread PDSCH processor. + double get_avg_return_time_us() const + { + return static_cast(sum_elapsed_return_ns) / static_cast(count) * 1e-3; + } + + /// Gets the processing rate. + double get_process_rate_Mbps() const + { + return static_cast(sum_tb_sz) / static_cast(sum_elapsed_completion_ns) * 1000; + } + + /// Gets the total amount of time the PDSCH processor spent processing. + std::chrono::nanoseconds get_total_time() const { return std::chrono::nanoseconds(sum_elapsed_completion_ns); } + +private: + // See interface for documentation. + void new_metric(const pdsch_processor_metrics& metrics) override + { + sum_tb_sz += metrics.tbs.to_bits().value(); + sum_elapsed_return_ns += metrics.elapsed_return.count(); + sum_elapsed_completion_ns += metrics.elapsed_completion.count(); + ++count; + } + + std::atomic sum_tb_sz = {}; + std::atomic sum_elapsed_return_ns = {}; + std::atomic sum_elapsed_completion_ns = {}; + std::atomic count = {}; +}; + +} // namespace srsran diff --git a/apps/units/flexible_o_du/o_du_low/metrics/port_channel_estimator_metrics_producer.h b/apps/units/flexible_o_du/o_du_low/metrics/port_channel_estimator_metrics_producer.h new file mode 100644 index 0000000000..3023b5d08d --- /dev/null +++ b/apps/units/flexible_o_du/o_du_low/metrics/port_channel_estimator_metrics_producer.h @@ -0,0 +1,56 @@ +/* + * + * Copyright 2021-2025 Software Radio Systems Limited + * + * This file is part of srsRAN. + * + * srsRAN is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsRAN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#pragma once + +#include "srsran/phy/metrics/phy_metrics_notifiers.h" +#include "srsran/phy/metrics/phy_metrics_reports.h" +#include + +namespace srsran { + +/// Port channel estimator metric producer. +class port_channel_estimator_metric_producer_impl : private port_channel_estimator_metric_notifier +{ +public: + /// Gets the port channel estimator metric interface. + port_channel_estimator_metric_notifier& get_notifier() { return *this; } + + /// Gets the average processing latency in microseconds. + double get_avg_latency_us() const { return static_cast(sum_elapsed_ns) / static_cast(count) * 1e-3; } + + /// Gets the total amount of time the CRC calculator spent calculating. + std::chrono::nanoseconds get_total_time() const { return std::chrono::nanoseconds(sum_elapsed_ns); } + +private: + // See interface for documentation. + void new_metric(const port_channel_estimator_metrics& metrics) override + { + sum_elapsed_ns += metrics.elapsed.count(); + ++count; + } + + std::atomic sum_elapsed_ns = {}; + std::atomic count = {}; +}; + +} // namespace srsran diff --git a/apps/units/flexible_o_du/o_du_low/metrics/pusch_demodulator_metrics_producer.h b/apps/units/flexible_o_du/o_du_low/metrics/pusch_demodulator_metrics_producer.h new file mode 100644 index 0000000000..883b6109d5 --- /dev/null +++ b/apps/units/flexible_o_du/o_du_low/metrics/pusch_demodulator_metrics_producer.h @@ -0,0 +1,64 @@ +/* + * + * Copyright 2021-2025 Software Radio Systems Limited + * + * This file is part of srsRAN. + * + * srsRAN is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsRAN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#pragma once + +#include "srsran/phy/metrics/phy_metrics_notifiers.h" +#include "srsran/phy/metrics/phy_metrics_reports.h" +#include + +namespace srsran { + +/// PUSCH demodulator metric producer. +class pusch_demodulator_metric_producer_impl : private pusch_demodulator_metric_notifier +{ +public: + /// Gets the PUSCH demodulator metric notifier. + pusch_demodulator_metric_notifier& get_notifier() { return *this; } + + /// Gets the PUSCH demodulator average processing time in us. + double get_average_processing_time_us() const + { + return static_cast(sum_elapsed_ns) / static_cast(count) / 1000.0; + } + + /// Gets the PUSCH demodulator total processing time excluding buffer operations in us. + std::chrono::nanoseconds get_total_time() const + { + return std::chrono::nanoseconds(sum_elapsed_ns - sum_elapsed_buffer_ns); + } + +private: + // See interface for documentation. + void new_metric(const pusch_demodulator_metrics& metrics) override + { + sum_elapsed_ns += metrics.elapsed.count(); + sum_elapsed_buffer_ns += metrics.elapsed_buffer.count(); + ++count; + } + + std::atomic sum_elapsed_ns = {}; + std::atomic sum_elapsed_buffer_ns = {}; + std::atomic count = {}; +}; + +} // namespace srsran diff --git a/apps/units/flexible_o_du/o_du_low/metrics/pusch_processor_metrics_producer.h b/apps/units/flexible_o_du/o_du_low/metrics/pusch_processor_metrics_producer.h index 8b53367645..3d73b41a2d 100644 --- a/apps/units/flexible_o_du/o_du_low/metrics/pusch_processor_metrics_producer.h +++ b/apps/units/flexible_o_du/o_du_low/metrics/pusch_processor_metrics_producer.h @@ -62,6 +62,9 @@ class pusch_processor_metric_producer_impl : private pusch_processor_metric_noti /// Gets the total time spend by PUSCH processors. std::chrono::nanoseconds get_total_time() const { return std::chrono::nanoseconds(sum_data_elapsed_ns); } + /// Gets the total time spent by the PUSCH processors waiting for the asynchronous decoding to be completed. + std::chrono::nanoseconds get_total_wait_time() const { return std::chrono::nanoseconds(sum_waiting_ns); } + private: // See interface for documentation. void new_metric(const pusch_processor_metrics& metrics) override @@ -69,6 +72,9 @@ class pusch_processor_metric_producer_impl : private pusch_processor_metric_noti sum_tbs += metrics.tbs.to_bits().value(); sum_data_elapsed_ns += metrics.elapsed_data.count(); sum_return_elapsed_ns += metrics.elapsed_return.count(); + if (metrics.elapsed_data > metrics.elapsed_return) { + sum_waiting_ns += metrics.elapsed_data.count() - metrics.elapsed_return.count(); + } if (metrics.crc_ok) { ++sum_crc_ok; } @@ -85,6 +91,7 @@ class pusch_processor_metric_producer_impl : private pusch_processor_metric_noti std::atomic sum_return_elapsed_ns = {}; std::atomic sum_data_elapsed_ns = {}; std::atomic sum_uci_elapsed_ns = {}; + std::atomic sum_waiting_ns = {}; std::atomic count = {}; std::atomic uci_count = {}; }; diff --git a/apps/units/flexible_o_du/o_du_low/metrics/time_alignment_estimator_metrics_producer.h b/apps/units/flexible_o_du/o_du_low/metrics/time_alignment_estimator_metrics_producer.h new file mode 100644 index 0000000000..5587b11fc2 --- /dev/null +++ b/apps/units/flexible_o_du/o_du_low/metrics/time_alignment_estimator_metrics_producer.h @@ -0,0 +1,64 @@ +/* + * + * Copyright 2021-2025 Software Radio Systems Limited + * + * This file is part of srsRAN. + * + * srsRAN is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsRAN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#pragma once + +#include "srsran/phy/metrics/phy_metrics_notifiers.h" +#include "srsran/phy/metrics/phy_metrics_reports.h" +#include + +namespace srsran { + +/// Time alignment estimator metric producer. +class time_alignment_estimator_metric_producer_impl : private time_alignment_estimator_metric_notifier +{ +public: + /// Gets the time alignment estimator metric interface. + time_alignment_estimator_metric_notifier& get_notifier() { return *this; } + + /// Gets the average processing latency in microseconds. + double get_avg_latency_us() const { return static_cast(sum_elapsed_ns) / static_cast(count) * 1e-3; } + + /// Gets the average processing rate in MREps (millions of resource elements per second). + double get_avg_rate_MREps() const + { + return static_cast(sum_nof_re) / static_cast(sum_elapsed_ns) * 1000; + } + + /// Gets the total amount of time the TA estimator spent calculating. + std::chrono::nanoseconds get_total_time() const { return std::chrono::nanoseconds(sum_elapsed_ns); } + +private: + // See interface for documentation. + void new_metric(const time_alignment_estimator_metrics& metrics) override + { + sum_nof_re += metrics.nof_re; + sum_elapsed_ns += metrics.elapsed.count(); + ++count; + } + + std::atomic sum_nof_re = {}; + std::atomic sum_elapsed_ns = {}; + std::atomic count = {}; +}; + +} // namespace srsran diff --git a/apps/units/flexible_o_du/o_du_low/metrics/transform_precoder_metrics_producer.h b/apps/units/flexible_o_du/o_du_low/metrics/transform_precoder_metrics_producer.h new file mode 100644 index 0000000000..6332abb9a2 --- /dev/null +++ b/apps/units/flexible_o_du/o_du_low/metrics/transform_precoder_metrics_producer.h @@ -0,0 +1,64 @@ +/* + * + * Copyright 2021-2025 Software Radio Systems Limited + * + * This file is part of srsRAN. + * + * srsRAN is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsRAN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#pragma once + +#include "srsran/phy/metrics/phy_metrics_notifiers.h" +#include "srsran/phy/metrics/phy_metrics_reports.h" +#include + +namespace srsran { + +/// Transform precoder metric producer. +class transform_precoder_metric_producer_impl : private transform_precoder_metric_notifier +{ +public: + /// Gets the transform precoder metric interface. + transform_precoder_metric_notifier& get_notifier() { return *this; } + + /// Gets the average processing latency in microseconds. + double get_avg_latency_us() const { return static_cast(sum_elapsed_ns) / static_cast(count) * 1e-3; } + + /// Gets the average processing rate in MREps (millions of resource elements per second). + double get_avg_rate_MREps() const + { + return static_cast(sum_nof_re) / static_cast(sum_elapsed_ns) * 1000; + } + + /// Gets the total amount of time the transform precoding spent calculating. + std::chrono::nanoseconds get_total_time() const { return std::chrono::nanoseconds(sum_elapsed_ns); } + +private: + // See interface for documentation. + void new_metric(const transform_precoder_metrics& metrics) override + { + sum_nof_re += metrics.nof_re; + sum_elapsed_ns += metrics.elapsed.count(); + ++count; + } + + std::atomic sum_nof_re = {}; + std::atomic sum_elapsed_ns = {}; + std::atomic count = {}; +}; + +} // namespace srsran diff --git a/apps/units/flexible_o_du/o_du_low/metrics/ulsch_demultiplex_metrics_producer.h b/apps/units/flexible_o_du/o_du_low/metrics/ulsch_demultiplex_metrics_producer.h new file mode 100644 index 0000000000..0a793beaa3 --- /dev/null +++ b/apps/units/flexible_o_du/o_du_low/metrics/ulsch_demultiplex_metrics_producer.h @@ -0,0 +1,80 @@ +/* + * + * Copyright 2021-2025 Software Radio Systems Limited + * + * This file is part of srsRAN. + * + * srsRAN is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * srsRAN is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * A copy of the GNU Affero General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#pragma once + +#include "srsran/phy/metrics/phy_metrics_notifiers.h" +#include "srsran/phy/metrics/phy_metrics_reports.h" +#include + +namespace srsran { + +/// UL-SCH demultiplexer metric producer. +class ulsch_demultiplex_metric_producer_impl : private ulsch_demultiplex_metric_notifier +{ +public: + /// Gets the UL-SCH demultiplexer metric notifier. + ulsch_demultiplex_metric_notifier& get_notifier() { return *this; } + + /// Gets the UL-SCH demultiplexer average initialization time in us. + double get_average_init_time_us() const + { + return static_cast(sum_elapsed_init_ns) / static_cast(count) / 1000.0; + } + + /// Gets the UL-SCH demultiplexer average finalization time in us. + double get_average_finish_time_us() const + { + return static_cast(sum_elapsed_on_end_codeword_ns) / static_cast(count) / 1000.0; + } + + /// Gets the UL-SCH demultiplexer average processing rate in Mbps. + double get_average_rate_Mbps() const + { + return static_cast(sum_nof_bits) / static_cast(sum_elapsed_on_new_block_ns) * 1000.0; + } + + /// Gets the total time spent by the UL-SCH demultiplexer. + std::chrono::nanoseconds get_total_time() const + { + return std::chrono::nanoseconds(sum_elapsed_init_ns + sum_elapsed_on_new_block_ns + sum_elapsed_on_end_codeword_ns); + } + +private: + // See interface for documentation. + void new_metric(const ulsch_demultiplex_metrics& metrics) override + { + sum_elapsed_init_ns += metrics.elapsed_init.count(); + sum_elapsed_on_new_block_ns += metrics.elapsed_on_new_block.count(); + sum_elapsed_on_end_codeword_ns += metrics.elapsed_on_end_codeword.count(); + sum_nof_bits += metrics.sum_nof_bits; + ++count; + } + + std::atomic sum_elapsed_init_ns = {}; + std::atomic sum_elapsed_on_new_block_ns = {}; + std::atomic sum_elapsed_on_end_codeword_ns = {}; + std::atomic sum_nof_bits = {}; + std::atomic count = {}; +}; + +} // namespace srsran diff --git a/apps/units/flexible_o_du/o_du_unit.h b/apps/units/flexible_o_du/o_du_unit.h index cc9055132a..7be4b30e7a 100644 --- a/apps/units/flexible_o_du/o_du_unit.h +++ b/apps/units/flexible_o_du/o_du_unit.h @@ -22,9 +22,9 @@ #pragma once -#include "apps/services/application_command.h" #include "apps/services/e2/e2_metric_connector_manager.h" #include "apps/services/metrics/metrics_config.h" +#include "apps/units/application_unit_commands.h" #include "srsran/du/du.h" #include #include @@ -51,9 +51,9 @@ struct worker_manager; /// O-DU unit. struct o_du_unit { - std::unique_ptr unit; - std::vector> commands; - std::vector metrics; + std::unique_ptr unit; + std::vector metrics; + application_unit_commands commands; std::unique_ptr> e2_metric_connectors; }; diff --git a/apps/units/flexible_o_du/split_7_2/helpers/ru_ofh_config_validator.cpp b/apps/units/flexible_o_du/split_7_2/helpers/ru_ofh_config_validator.cpp index 8a4555b1e1..3c53f37895 100644 --- a/apps/units/flexible_o_du/split_7_2/helpers/ru_ofh_config_validator.cpp +++ b/apps/units/flexible_o_du/split_7_2/helpers/ru_ofh_config_validator.cpp @@ -139,6 +139,14 @@ static bool validate_ru_ofh_unit_config(span return false; } + if (cell_cfg.nof_antennas_ul > ofh_cell.ru_prach_port_id.size()) { + fmt::print("RU number of PRACH ports={} must be equal or greater than the number of reception antennas={}\n", + ofh_cell.ru_prach_port_id.size(), + cell_cfg.nof_antennas_ul); + + return false; + } + if (cell_cfg.nof_prach_ports > ofh_cell.ru_prach_port_id.size()) { fmt::print("RU number of PRACH ports={} must be equal or greater than the cell number of PRACH ports={}\n", ofh_cell.ru_prach_port_id.size(), diff --git a/apps/units/flexible_o_du/split_helpers/flexible_o_du_factory.cpp b/apps/units/flexible_o_du/split_helpers/flexible_o_du_factory.cpp index e2cacaebc6..6a55df30b7 100644 --- a/apps/units/flexible_o_du/split_helpers/flexible_o_du_factory.cpp +++ b/apps/units/flexible_o_du/split_helpers/flexible_o_du_factory.cpp @@ -108,6 +108,7 @@ o_du_unit flexible_o_du_factory::create_flexible_o_du(const o_du_unit_dependenci std::for_each(odu_hi_unit.metrics.begin(), odu_hi_unit.metrics.end(), [&](auto& e) { o_du.metrics.emplace_back(std::move(e)); }); + o_du.commands = std::move(odu_hi_unit.commands); auto odu_instance = make_o_du(std::move(odu_hi_unit.o_du_hi), std::move(odu_lo_unit.o_du_lo)); @@ -125,19 +126,19 @@ o_du_unit flexible_o_du_factory::create_flexible_o_du(const o_du_unit_dependenci srsran_assert(ru, "Invalid Radio Unit"); - // Add RU commands. - o_du.commands.push_back(std::make_unique()); - o_du.commands.push_back(std::make_unique(ru->get_controller())); + // Add RU command-line commands. + o_du.commands.cmdline.push_back(std::make_unique()); + o_du.commands.cmdline.push_back(std::make_unique(ru->get_controller())); // Create the RU gain commands. if (auto* controller = ru->get_controller().get_gain_controller()) { - o_du.commands.push_back(std::make_unique(*controller)); - o_du.commands.push_back(std::make_unique(*controller)); + o_du.commands.cmdline.push_back(std::make_unique(*controller)); + o_du.commands.cmdline.push_back(std::make_unique(*controller)); } // Create the RU CFO command. if (auto* controller = ru->get_controller().get_cfo_controller()) { - o_du.commands.push_back(std::make_unique(*controller)); + o_du.commands.cmdline.push_back(std::make_unique(*controller)); } // Configure the RU and DU in the dynamic DU. diff --git a/apps/units/o_cu_cp/cu_cp/cu_cp_commands.h b/apps/units/o_cu_cp/cu_cp/cu_cp_cmdline_commands.h similarity index 90% rename from apps/units/o_cu_cp/cu_cp/cu_cp_commands.h rename to apps/units/o_cu_cp/cu_cp/cu_cp_cmdline_commands.h index 7fd51198bc..ecac023505 100644 --- a/apps/units/o_cu_cp/cu_cp/cu_cp_commands.h +++ b/apps/units/o_cu_cp/cu_cp/cu_cp_cmdline_commands.h @@ -22,8 +22,8 @@ #pragma once -#include "apps/services/application_command.h" -#include "apps/services/stdin_command_dispatcher_utils.h" +#include "apps/services/cmdline/cmdline_command.h" +#include "apps/services/cmdline/cmdline_command_dispatcher_utils.h" #include "srsran/adt/expected.h" #include "srsran/cu_cp/cu_cp_command_handler.h" #include "srsran/ran/pci.h" @@ -32,7 +32,7 @@ namespace srsran { /// Application command to trigger a handover. -class handover_app_command : public app_services::application_command +class handover_app_command : public app_services::cmdline_command { srs_cu_cp::cu_cp_command_handler& cu_cp; @@ -53,19 +53,19 @@ class handover_app_command : public app_services::application_command return; } - auto arg = args.begin(); + const auto* arg = args.begin(); expected serving_pci = app_services::parse_int(*arg); if (not serving_pci.has_value()) { fmt::print("Invalid serving PCI.\n"); return; } - arg++; + ++arg; expected rnti = app_services::parse_unsigned_hex(*arg); if (not rnti.has_value()) { fmt::print("Invalid UE RNTI.\n"); return; } - arg++; + ++arg; expected target_pci = app_services::parse_int(*arg); if (not target_pci.has_value()) { fmt::print("Invalid target PCI.\n"); diff --git a/apps/units/o_cu_cp/o_cu_cp_builder.cpp b/apps/units/o_cu_cp/o_cu_cp_builder.cpp index dd33cc0d56..78ff38926f 100644 --- a/apps/units/o_cu_cp/o_cu_cp_builder.cpp +++ b/apps/units/o_cu_cp/o_cu_cp_builder.cpp @@ -22,7 +22,7 @@ #include "o_cu_cp_builder.h" #include "apps/services/metrics/metrics_config.h" -#include "cu_cp/cu_cp_commands.h" +#include "cu_cp/cu_cp_cmdline_commands.h" #include "cu_cp/cu_cp_config_translators.h" #include "e2/o_cu_cp_e2_config_translators.h" #include "o_cu_cp_unit_config.h" @@ -86,7 +86,8 @@ o_cu_cp_unit srsran::build_o_cu_cp(const o_cu_cp_unit_config& unit_cfg, o_cu_cp_ std::move(n2_clients), std::move(e2_metric_connectors), srs_cu_cp::create_o_cu_cp(o_cu_cp_cfg, ocu_dependencies)); // Add the commands; - ocucp.commands.push_back(std::make_unique(ocucp.unit->get_cu_cp().get_command_handler())); + ocucp.commands.cmdline.push_back( + std::make_unique(ocucp.unit->get_cu_cp().get_command_handler())); return ocucp; } diff --git a/apps/units/o_cu_cp/o_cu_cp_builder.h b/apps/units/o_cu_cp/o_cu_cp_builder.h index 25c685b86a..805bc8e9c4 100644 --- a/apps/units/o_cu_cp/o_cu_cp_builder.h +++ b/apps/units/o_cu_cp/o_cu_cp_builder.h @@ -22,9 +22,9 @@ #pragma once -#include "apps/services/application_command.h" #include "apps/services/e2/e2_metric_connector_manager.h" #include "apps/services/metrics/metrics_config.h" +#include "apps/units/application_unit_commands.h" #include "o_cu_cp_unit_impl.h" #include "srsran/cu_cp/cu_cp.h" #include "srsran/e2/e2_cu_metrics_connector.h" @@ -62,9 +62,9 @@ struct o_cu_cp_unit_dependencies { /// O-RAN CU-CP unit. struct o_cu_cp_unit { - std::unique_ptr unit; - std::vector> commands; - std::vector metrics; + std::unique_ptr unit; + application_unit_commands commands; + std::vector metrics; }; /// Builds an O-RAN CU-CP unit with the given configuration and dependencies. diff --git a/apps/units/o_cu_up/cu_up/metrics/cu_up_pdcp_metrics_producer.h b/apps/units/o_cu_up/cu_up/metrics/cu_up_pdcp_metrics_producer.h index 3c8aafe17e..a86b36d142 100644 --- a/apps/units/o_cu_up/cu_up/metrics/cu_up_pdcp_metrics_producer.h +++ b/apps/units/o_cu_up/cu_up/metrics/cu_up_pdcp_metrics_producer.h @@ -37,6 +37,9 @@ class pdcp_metrics_producer_impl : public pdcp_metrics_notifier, public app_serv // See interface for documentation. void report_metrics(const pdcp_metrics_container& metrics) override; + // See interface for documentation. + void on_new_report_period() override {} + private: app_services::metrics_notifier& notifier; }; diff --git a/configs/qos.yml b/configs/qos.yml index 8a9ee030fc..90f95fa010 100644 --- a/configs/qos.yml +++ b/configs/qos.yml @@ -457,3 +457,249 @@ qos: sn: 18 t-reassembly: 20 t-status-prohibit: 10 + # + # Delay-critical Guaranteed Bitrate 5QIs + # + - + # 5QI = 82 e.g Discrete Automation + # PDB = 10ms PER = 10^-4 + five_qi: 82 + pdcp: + tx: + sn: 12 + discard_timer: 10 + status_report_required: false + rx: + sn: 12 + t_reordering: 0 + out_of_order_delivery: false + f1u_cu_up: + backoff_timer: 10 + f1u_du: + backoff_timer: 10 + rlc: + mode: um-bidir + um-bidir: + tx: + sn: 12 + queue-size: 16384 + queue-bytes: 6172672 + rx: + sn: 12 + t-reassembly: 10 + - + # 5QI = 83 e.g Discrete Automation + # PDB = 10ms PER = 10^-4 + five_qi: 83 + pdcp: + tx: + sn: 12 + discard_timer: 10 + status_report_required: false + rx: + sn: 12 + t_reordering: 0 + out_of_order_delivery: false + f1u_cu_up: + backoff_timer: 10 + f1u_du: + backoff_timer: 10 + rlc: + mode: um-bidir + um-bidir: + tx: + sn: 12 + queue-size: 16384 + queue-bytes: 6172672 + rx: + sn: 12 + t-reassembly: 10 + - + # 5QI = 84 e.g Intelligent transport systems + # PDB = 30ms PER = 10^-5 + five_qi: 84 + pdcp: + tx: + sn: 12 + discard_timer: 30 + status_report_required: false + rx: + sn: 12 + t_reordering: 0 + out_of_order_delivery: false + f1u_cu_up: + backoff_timer: 10 + f1u_du: + backoff_timer: 10 + rlc: + mode: um-bidir + um-bidir: + tx: + sn: 12 + queue-size: 16384 + queue-bytes: 6172672 + rx: + sn: 12 + t-reassembly: 10 + - + # 5QI = 85 e.g Electricity Distribution-high voltage + # PDB = 5ms PER = 10^-5 + five_qi: 85 + pdcp: + tx: + sn: 12 + discard_timer: 10 + status_report_required: false + rx: + sn: 12 + t_reordering: 0 + out_of_order_delivery: false + f1u_cu_up: + backoff_timer: 10 + f1u_du: + backoff_timer: 10 + rlc: + mode: um-bidir + um-bidir: + tx: + sn: 12 + queue-size: 16384 + queue-bytes: 6172672 + rx: + sn: 12 + t-reassembly: 10 + - + # 5QI = 86 e.g V2X messages + # PDB = 5ms PER = 10^-4 + five_qi: 86 + pdcp: + tx: + sn: 12 + discard_timer: 10 + status_report_required: false + rx: + sn: 12 + t_reordering: 0 + out_of_order_delivery: false + f1u_cu_up: + backoff_timer: 10 + f1u_du: + backoff_timer: 10 + rlc: + mode: um-bidir + um-bidir: + tx: + sn: 12 + queue-size: 16384 + queue-bytes: 6172672 + rx: + sn: 12 + t-reassembly: 10 + - + # 5QI = 87 e.g Interactive Service-Motion tracking data + # PDB = 5ms PER = 10^-3 + five_qi: 87 + pdcp: + tx: + sn: 12 + discard_timer: 10 + status_report_required: false + rx: + sn: 12 + t_reordering: 0 + out_of_order_delivery: false + f1u_cu_up: + backoff_timer: 10 + f1u_du: + backoff_timer: 10 + rlc: + mode: um-bidir + um-bidir: + tx: + sn: 12 + queue-size: 16384 + queue-bytes: 6172672 + rx: + sn: 12 + t-reassembly: 10 + - + # 5QI = 88 e.g Interactive Service-Motion tracking data + # PDB = 10ms PER = 10^-3 + five_qi: 88 + pdcp: + tx: + sn: 12 + discard_timer: 10 + status_report_required: false + rx: + sn: 12 + t_reordering: 0 + out_of_order_delivery: false + f1u_cu_up: + backoff_timer: 10 + f1u_du: + backoff_timer: 10 + rlc: + mode: um-bidir + um-bidir: + tx: + sn: 12 + queue-size: 16384 + queue-bytes: 6172672 + rx: + sn: 12 + t-reassembly: 10 + - + # 5QI = 89 e.g Visual content for cloud/edge/split rendering + # PDB = 15ms PER = 10^-4 + five_qi: 89 + pdcp: + tx: + sn: 12 + discard_timer: 20 + status_report_required: false + rx: + sn: 12 + t_reordering: 0 + out_of_order_delivery: false + f1u_cu_up: + backoff_timer: 10 + f1u_du: + backoff_timer: 10 + rlc: + mode: um-bidir + um-bidir: + tx: + sn: 12 + queue-size: 16384 + queue-bytes: 6172672 + rx: + sn: 12 + t-reassembly: 10 + - + # 5QI = 90 e.g Visual content for cloud/edge/split rendering + # PDB = 20ms PER = 10^-4 + five_qi: 90 + pdcp: + tx: + sn: 12 + discard_timer: 20 + status_report_required: false + rx: + sn: 12 + t_reordering: 0 + out_of_order_delivery: false + f1u_cu_up: + backoff_timer: 10 + f1u_du: + backoff_timer: 10 + rlc: + mode: um-bidir + um-bidir: + tx: + sn: 12 + queue-size: 16384 + queue-bytes: 6172672 + rx: + sn: 12 + t-reassembly: 10 diff --git a/docker/Dockerfile b/docker/Dockerfile index 25c68cb134..d7bbe62d24 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -21,15 +21,15 @@ # Build args ################ # OS_VERSION Ubuntu OS version -# LIB uhd or dpdk (lowercase) -# LIB_VERSION UHD or DPDK version number +# UHD_VERSION UHD version number +# DPDK_VERSION DPDK version number # MARCH gcc/clang compatible arch -# NUM_JOBS Number or empty for all +# NUM_JOBS Number or empty for all # EXTRA_CMAKE_ARGS Extra flags for srsRAN Project ARG OS_VERSION=24.04 -ARG LIB=uhd -ARG LIB_VERSION=4.7.0.0 +ARG UHD_VERSION=4.7.0.0 +ARG DPDK_VERSION=23.11.1 ARG MARCH=native ARG NUM_JOBS="" @@ -45,36 +45,41 @@ ADD . /src # RUN git clone https://github.com/srsran/srsRAN_Project.git /src # Install srsRAN build dependencies -ARG LIB RUN /src/docker/scripts/install_dependencies.sh build && \ - /src/docker/scripts/install_${LIB}_dependencies.sh build && \ + /src/docker/scripts/install_uhd_dependencies.sh build && \ + /src/docker/scripts/install_dpdk_dependencies.sh build && \ DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends git clang -ARG COMPILER=gcc -ARG LIB_VERSION +ARG UHD_VERSION +ARG DPDK_VERSION ARG MARCH ARG NUM_JOBS # Compile UHD/DPDK -RUN /src/docker/scripts/build_${LIB}.sh ${LIB_VERSION} ${MARCH} ${NUM_JOBS} +RUN /src/docker/scripts/build_uhd.sh "${UHD_VERSION}" ${MARCH} ${NUM_JOBS} && \ + /src/docker/scripts/build_dpdk.sh "${DPDK_VERSION}" ${MARCH} ${NUM_JOBS} # Compile srsRAN Project and install it in the OS +ARG COMPILER=gcc ARG EXTRA_CMAKE_ARGS="" -RUN if [ -z "$NUM_JOBS" ]; then NUM_JOBS=$(nproc); fi && \ - LIB_UPPER=$(echo $LIB | tr '[:lower:]' '[:upper:]') && \ - export ${LIB_UPPER}_DIR="/opt/${LIB}/${LIB_VERSION}" && \ - if [ "$LIB_UPPER" = "UHD" ]; then TARGETS="srsdu_split_8 gnb_split_8"; else TARGETS="srsdu_split_7_2 gnb_split_7_2"; fi \ +ENV UHD_DIR=/opt/uhd/${UHD_VERSION} +ENV DPDK_DIR=/opt/dpdk/${DPDK_VERSION} +RUN if [ -z "$NUM_JOBS" ]; then NUM_JOBS=$(nproc); fi \ && \ - /src/docker/scripts/builder.sh -c ${COMPILER} -m "-j${NUM_JOBS} srscu $TARGETS ru_emulator" \ - -DBUILD_TESTS=False -DENABLE_${LIB_UPPER}=On -DMARCH=${MARCH} -DCMAKE_INSTALL_PREFIX=/opt/srs \ + /src/docker/scripts/builder.sh -c ${COMPILER} -m "-j${NUM_JOBS} srscu srsdu srsdu_split_8 srsdu_split_7_2 gnb gnb_split_8 gnb_split_7_2 ru_emulator" \ + -DBUILD_TESTS=False -DENABLE_UHD=On -DENABLE_DPDK=On -DMARCH=${MARCH} -DCMAKE_INSTALL_PREFIX=/opt/srs \ ${EXTRA_CMAKE_ARGS} /src \ && \ mkdir -p /opt/srs/bin /opt/srs/share/srsran && \ - cp /src/build/apps/cu/srscu /opt/srs/bin/srscu && \ - cp /src/build/apps/du_split_*/srsdu /opt/srs/bin/srsdu && \ - cp /src/build/apps/gnb_split_*/gnb /opt/srs/bin/gnb && \ - cp /src/build/apps/examples/ofh/ru_emulator /opt/srs/bin/ru_emulator && \ - cp /src/configs/*.yml /opt/srs/share/srsran/ + cp /src/build/apps/cu/srscu /opt/srs/bin/srscu && \ + cp /src/build/apps/du/srsdu /opt/srs/bin/srsdu && \ + cp /src/build/apps/du_split_8/srsdu /opt/srs/bin/srsdu_split_8 && \ + cp /src/build/apps/du_split_7_2/srsdu /opt/srs/bin/srsdu_split_7_2 && \ + cp /src/build/apps/gnb/gnb /opt/srs/bin/gnb && \ + cp /src/build/apps/gnb_split_8/gnb /opt/srs/bin/gnb_split_8 && \ + cp /src/build/apps/gnb_split_7_2/gnb /opt/srs/bin/gnb_split_7_2 && \ + cp /src/build/apps/examples/ofh/ru_emulator /opt/srs/bin/ru_emulator && \ + cp /src/configs/*.yml /opt/srs/share/srsran/ ################ # Stage 2: Run # @@ -82,20 +87,24 @@ RUN if [ -z "$NUM_JOBS" ]; then NUM_JOBS=$(nproc); fi && \ FROM ubuntu:$OS_VERSION -ARG LIB -ARG LIB_VERSION +ARG UHD_VERSION +ARG DPDK_VERSION # Copy srsRAN binaries and libraries installed in previous stage -COPY --from=builder /opt/${LIB}/${LIB_VERSION} /opt/${LIB}/${LIB_VERSION} -COPY --from=builder /opt/srs /usr/local +COPY --from=builder /opt/uhd/${UHD_VERSION} /opt/uhd/${UHD_VERSION} +COPY --from=builder /opt/dpdk/${DPDK_VERSION} /opt/dpdk/${DPDK_VERSION} +COPY --from=builder /opt/srs /usr/local # Copy the install dependencies scripts -ADD docker/scripts/install_${LIB}_dependencies.sh /usr/local/etc/install_lib_dependencies.sh -ADD docker/scripts/install_dependencies.sh /usr/local/etc/install_srsran_dependencies.sh -ENV LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/${LIB}/${LIB_VERSION}/lib/:/opt/${LIB}/${LIB_VERSION}/lib/x86_64-linux-gnu/:/opt/${LIB}/${LIB_VERSION}/lib/aarch64-linux-gnu/ -ENV PATH=$PATH:/opt/${LIB}/${LIB_VERSION}/bin/ +ADD docker/scripts/install_uhd_dependencies.sh /usr/local/etc/install_uhd_dependencies.sh +ADD docker/scripts/install_dpdk_dependencies.sh /usr/local/etc/install_dpdk_dependencies.sh +ADD docker/scripts/install_dependencies.sh /usr/local/etc/install_srsran_dependencies.sh +ENV LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/uhd/${UHD_VERSION}/lib/:/opt/uhd/${UHD_VERSION}/lib/x86_64-linux-gnu/:/opt/uhd/${UHD_VERSION}/lib/aarch64-linux-gnu/ +ENV LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/dpdk/${DPDK_VERSION}/lib/:/opt/dpdk/${DPDK_VERSION}/lib/x86_64-linux-gnu/:/opt/dpdk/${DPDK_VERSION}/lib/aarch64-linux-gnu/ +ENV PATH=$PATH:/opt/uhd/${UHD_VERSION}/bin/:/opt/dpdk/${DPDK_VERSION}/bin/ # Install srsran and lib runtime dependencies RUN /usr/local/etc/install_srsran_dependencies.sh run && \ - /usr/local/etc/install_lib_dependencies.sh run && \ + /usr/local/etc/install_uhd_dependencies.sh run && \ + /usr/local/etc/install_dpdk_dependencies.sh run && \ apt-get autoremove && apt-get clean && rm -rf /var/lib/apt/lists/* diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt index d8a88fa1e1..bc1a2388c8 100644 --- a/external/CMakeLists.txt +++ b/external/CMakeLists.txt @@ -19,3 +19,4 @@ # add_subdirectory(fmt) +add_subdirectory(uWebSockets) diff --git a/external/nlohmann/json.hpp b/external/nlohmann/json.hpp new file mode 100644 index 0000000000..8b72ea6539 --- /dev/null +++ b/external/nlohmann/json.hpp @@ -0,0 +1,24765 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +/****************************************************************************\ + * Note on documentation: The source files contain links to the online * + * documentation of the public API at https://json.nlohmann.me. This URL * + * contains the most recent documentation and should also be applicable to * + * previous versions; documentation for deprecated functions is not * + * removed, but marked deprecated. See "Generate documentation" section in * + * file docs/README.md. * +\****************************************************************************/ + +#ifndef INCLUDE_NLOHMANN_JSON_HPP_ +#define INCLUDE_NLOHMANN_JSON_HPP_ + +#include // all_of, find, for_each +#include // nullptr_t, ptrdiff_t, size_t +#include // hash, less +#include // initializer_list +#ifndef JSON_NO_IO + #include // istream, ostream +#endif // JSON_NO_IO +#include // random_access_iterator_tag +#include // unique_ptr +#include // string, stoi, to_string +#include // declval, forward, move, pair, swap +#include // vector + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +// This file contains all macro definitions affecting or depending on the ABI + +#ifndef JSON_SKIP_LIBRARY_VERSION_CHECK + #if defined(NLOHMANN_JSON_VERSION_MAJOR) && defined(NLOHMANN_JSON_VERSION_MINOR) && defined(NLOHMANN_JSON_VERSION_PATCH) + #if NLOHMANN_JSON_VERSION_MAJOR != 3 || NLOHMANN_JSON_VERSION_MINOR != 11 || NLOHMANN_JSON_VERSION_PATCH != 3 + #warning "Already included a different version of the library!" + #endif + #endif +#endif + +#define NLOHMANN_JSON_VERSION_MAJOR 3 // NOLINT(modernize-macro-to-enum) +#define NLOHMANN_JSON_VERSION_MINOR 11 // NOLINT(modernize-macro-to-enum) +#define NLOHMANN_JSON_VERSION_PATCH 3 // NOLINT(modernize-macro-to-enum) + +#ifndef JSON_DIAGNOSTICS + #define JSON_DIAGNOSTICS 0 +#endif + +#ifndef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON + #define JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON 0 +#endif + +#if JSON_DIAGNOSTICS + #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS _diag +#else + #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS +#endif + +#if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON + #define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON _ldvcmp +#else + #define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON +#endif + +#ifndef NLOHMANN_JSON_NAMESPACE_NO_VERSION + #define NLOHMANN_JSON_NAMESPACE_NO_VERSION 0 +#endif + +// Construct the namespace ABI tags component +#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b) json_abi ## a ## b +#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b) \ + NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b) + +#define NLOHMANN_JSON_ABI_TAGS \ + NLOHMANN_JSON_ABI_TAGS_CONCAT( \ + NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS, \ + NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON) + +// Construct the namespace version component +#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) \ + _v ## major ## _ ## minor ## _ ## patch +#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(major, minor, patch) \ + NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) + +#if NLOHMANN_JSON_NAMESPACE_NO_VERSION +#define NLOHMANN_JSON_NAMESPACE_VERSION +#else +#define NLOHMANN_JSON_NAMESPACE_VERSION \ + NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(NLOHMANN_JSON_VERSION_MAJOR, \ + NLOHMANN_JSON_VERSION_MINOR, \ + NLOHMANN_JSON_VERSION_PATCH) +#endif + +// Combine namespace components +#define NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b) a ## b +#define NLOHMANN_JSON_NAMESPACE_CONCAT(a, b) \ + NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b) + +#ifndef NLOHMANN_JSON_NAMESPACE +#define NLOHMANN_JSON_NAMESPACE \ + nlohmann::NLOHMANN_JSON_NAMESPACE_CONCAT( \ + NLOHMANN_JSON_ABI_TAGS, \ + NLOHMANN_JSON_NAMESPACE_VERSION) +#endif + +#ifndef NLOHMANN_JSON_NAMESPACE_BEGIN +#define NLOHMANN_JSON_NAMESPACE_BEGIN \ + namespace nlohmann \ + { \ + inline namespace NLOHMANN_JSON_NAMESPACE_CONCAT( \ + NLOHMANN_JSON_ABI_TAGS, \ + NLOHMANN_JSON_NAMESPACE_VERSION) \ + { +#endif + +#ifndef NLOHMANN_JSON_NAMESPACE_END +#define NLOHMANN_JSON_NAMESPACE_END \ + } /* namespace (inline namespace) NOLINT(readability/namespace) */ \ + } // namespace nlohmann +#endif + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // transform +#include // array +#include // forward_list +#include // inserter, front_inserter, end +#include // map +#include // string +#include // tuple, make_tuple +#include // is_arithmetic, is_same, is_enum, underlying_type, is_convertible +#include // unordered_map +#include // pair, declval +#include // valarray + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // nullptr_t +#include // exception +#if JSON_DIAGNOSTICS + #include // accumulate +#endif +#include // runtime_error +#include // to_string +#include // vector + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // array +#include // size_t +#include // uint8_t +#include // string + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // declval, pair +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +template struct make_void +{ + using type = void; +}; +template using void_t = typename make_void::type; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +// https://en.cppreference.com/w/cpp/experimental/is_detected +struct nonesuch +{ + nonesuch() = delete; + ~nonesuch() = delete; + nonesuch(nonesuch const&) = delete; + nonesuch(nonesuch const&&) = delete; + void operator=(nonesuch const&) = delete; + void operator=(nonesuch&&) = delete; +}; + +template class Op, + class... Args> +struct detector +{ + using value_t = std::false_type; + using type = Default; +}; + +template class Op, class... Args> +struct detector>, Op, Args...> +{ + using value_t = std::true_type; + using type = Op; +}; + +template class Op, class... Args> +using is_detected = typename detector::value_t; + +template class Op, class... Args> +struct is_detected_lazy : is_detected { }; + +template class Op, class... Args> +using detected_t = typename detector::type; + +template class Op, class... Args> +using detected_or = detector; + +template class Op, class... Args> +using detected_or_t = typename detected_or::type; + +template class Op, class... Args> +using is_detected_exact = std::is_same>; + +template class Op, class... Args> +using is_detected_convertible = + std::is_convertible, To>; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + +// #include + + +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2016-2021 Evan Nemerson +// SPDX-License-Identifier: MIT + +/* Hedley - https://nemequ.github.io/hedley + * Created by Evan Nemerson + */ + +#if !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < 15) +#if defined(JSON_HEDLEY_VERSION) + #undef JSON_HEDLEY_VERSION +#endif +#define JSON_HEDLEY_VERSION 15 + +#if defined(JSON_HEDLEY_STRINGIFY_EX) + #undef JSON_HEDLEY_STRINGIFY_EX +#endif +#define JSON_HEDLEY_STRINGIFY_EX(x) #x + +#if defined(JSON_HEDLEY_STRINGIFY) + #undef JSON_HEDLEY_STRINGIFY +#endif +#define JSON_HEDLEY_STRINGIFY(x) JSON_HEDLEY_STRINGIFY_EX(x) + +#if defined(JSON_HEDLEY_CONCAT_EX) + #undef JSON_HEDLEY_CONCAT_EX +#endif +#define JSON_HEDLEY_CONCAT_EX(a,b) a##b + +#if defined(JSON_HEDLEY_CONCAT) + #undef JSON_HEDLEY_CONCAT +#endif +#define JSON_HEDLEY_CONCAT(a,b) JSON_HEDLEY_CONCAT_EX(a,b) + +#if defined(JSON_HEDLEY_CONCAT3_EX) + #undef JSON_HEDLEY_CONCAT3_EX +#endif +#define JSON_HEDLEY_CONCAT3_EX(a,b,c) a##b##c + +#if defined(JSON_HEDLEY_CONCAT3) + #undef JSON_HEDLEY_CONCAT3 +#endif +#define JSON_HEDLEY_CONCAT3(a,b,c) JSON_HEDLEY_CONCAT3_EX(a,b,c) + +#if defined(JSON_HEDLEY_VERSION_ENCODE) + #undef JSON_HEDLEY_VERSION_ENCODE +#endif +#define JSON_HEDLEY_VERSION_ENCODE(major,minor,revision) (((major) * 1000000) + ((minor) * 1000) + (revision)) + +#if defined(JSON_HEDLEY_VERSION_DECODE_MAJOR) + #undef JSON_HEDLEY_VERSION_DECODE_MAJOR +#endif +#define JSON_HEDLEY_VERSION_DECODE_MAJOR(version) ((version) / 1000000) + +#if defined(JSON_HEDLEY_VERSION_DECODE_MINOR) + #undef JSON_HEDLEY_VERSION_DECODE_MINOR +#endif +#define JSON_HEDLEY_VERSION_DECODE_MINOR(version) (((version) % 1000000) / 1000) + +#if defined(JSON_HEDLEY_VERSION_DECODE_REVISION) + #undef JSON_HEDLEY_VERSION_DECODE_REVISION +#endif +#define JSON_HEDLEY_VERSION_DECODE_REVISION(version) ((version) % 1000) + +#if defined(JSON_HEDLEY_GNUC_VERSION) + #undef JSON_HEDLEY_GNUC_VERSION +#endif +#if defined(__GNUC__) && defined(__GNUC_PATCHLEVEL__) + #define JSON_HEDLEY_GNUC_VERSION JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) +#elif defined(__GNUC__) + #define JSON_HEDLEY_GNUC_VERSION JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, 0) +#endif + +#if defined(JSON_HEDLEY_GNUC_VERSION_CHECK) + #undef JSON_HEDLEY_GNUC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_GNUC_VERSION) + #define JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_GNUC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_MSVC_VERSION) + #undef JSON_HEDLEY_MSVC_VERSION +#endif +#if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 140000000) && !defined(__ICL) + #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 10000000, (_MSC_FULL_VER % 10000000) / 100000, (_MSC_FULL_VER % 100000) / 100) +#elif defined(_MSC_FULL_VER) && !defined(__ICL) + #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 1000000, (_MSC_FULL_VER % 1000000) / 10000, (_MSC_FULL_VER % 10000) / 10) +#elif defined(_MSC_VER) && !defined(__ICL) + #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_VER / 100, _MSC_VER % 100, 0) +#endif + +#if defined(JSON_HEDLEY_MSVC_VERSION_CHECK) + #undef JSON_HEDLEY_MSVC_VERSION_CHECK +#endif +#if !defined(JSON_HEDLEY_MSVC_VERSION) + #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (0) +#elif defined(_MSC_VER) && (_MSC_VER >= 1400) + #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 10000000) + (minor * 100000) + (patch))) +#elif defined(_MSC_VER) && (_MSC_VER >= 1200) + #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 1000000) + (minor * 10000) + (patch))) +#else + #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_VER >= ((major * 100) + (minor))) +#endif + +#if defined(JSON_HEDLEY_INTEL_VERSION) + #undef JSON_HEDLEY_INTEL_VERSION +#endif +#if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) && !defined(__ICL) + #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, __INTEL_COMPILER_UPDATE) +#elif defined(__INTEL_COMPILER) && !defined(__ICL) + #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, 0) +#endif + +#if defined(JSON_HEDLEY_INTEL_VERSION_CHECK) + #undef JSON_HEDLEY_INTEL_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_INTEL_VERSION) + #define JSON_HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_INTEL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_INTEL_CL_VERSION) + #undef JSON_HEDLEY_INTEL_CL_VERSION +#endif +#if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) && defined(__ICL) + #define JSON_HEDLEY_INTEL_CL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER, __INTEL_COMPILER_UPDATE, 0) +#endif + +#if defined(JSON_HEDLEY_INTEL_CL_VERSION_CHECK) + #undef JSON_HEDLEY_INTEL_CL_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_INTEL_CL_VERSION) + #define JSON_HEDLEY_INTEL_CL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_INTEL_CL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_INTEL_CL_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_PGI_VERSION) + #undef JSON_HEDLEY_PGI_VERSION +#endif +#if defined(__PGI) && defined(__PGIC__) && defined(__PGIC_MINOR__) && defined(__PGIC_PATCHLEVEL__) + #define JSON_HEDLEY_PGI_VERSION JSON_HEDLEY_VERSION_ENCODE(__PGIC__, __PGIC_MINOR__, __PGIC_PATCHLEVEL__) +#endif + +#if defined(JSON_HEDLEY_PGI_VERSION_CHECK) + #undef JSON_HEDLEY_PGI_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_PGI_VERSION) + #define JSON_HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_PGI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_SUNPRO_VERSION) + #undef JSON_HEDLEY_SUNPRO_VERSION +#endif +#if defined(__SUNPRO_C) && (__SUNPRO_C > 0x1000) + #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((((__SUNPRO_C >> 16) & 0xf) * 10) + ((__SUNPRO_C >> 12) & 0xf), (((__SUNPRO_C >> 8) & 0xf) * 10) + ((__SUNPRO_C >> 4) & 0xf), (__SUNPRO_C & 0xf) * 10) +#elif defined(__SUNPRO_C) + #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_C >> 8) & 0xf, (__SUNPRO_C >> 4) & 0xf, (__SUNPRO_C) & 0xf) +#elif defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x1000) + #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((((__SUNPRO_CC >> 16) & 0xf) * 10) + ((__SUNPRO_CC >> 12) & 0xf), (((__SUNPRO_CC >> 8) & 0xf) * 10) + ((__SUNPRO_CC >> 4) & 0xf), (__SUNPRO_CC & 0xf) * 10) +#elif defined(__SUNPRO_CC) + #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_CC >> 8) & 0xf, (__SUNPRO_CC >> 4) & 0xf, (__SUNPRO_CC) & 0xf) +#endif + +#if defined(JSON_HEDLEY_SUNPRO_VERSION_CHECK) + #undef JSON_HEDLEY_SUNPRO_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_SUNPRO_VERSION) + #define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_SUNPRO_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION) + #undef JSON_HEDLEY_EMSCRIPTEN_VERSION +#endif +#if defined(__EMSCRIPTEN__) + #define JSON_HEDLEY_EMSCRIPTEN_VERSION JSON_HEDLEY_VERSION_ENCODE(__EMSCRIPTEN_major__, __EMSCRIPTEN_minor__, __EMSCRIPTEN_tiny__) +#endif + +#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK) + #undef JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION) + #define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_EMSCRIPTEN_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_ARM_VERSION) + #undef JSON_HEDLEY_ARM_VERSION +#endif +#if defined(__CC_ARM) && defined(__ARMCOMPILER_VERSION) + #define JSON_HEDLEY_ARM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ARMCOMPILER_VERSION / 1000000, (__ARMCOMPILER_VERSION % 1000000) / 10000, (__ARMCOMPILER_VERSION % 10000) / 100) +#elif defined(__CC_ARM) && defined(__ARMCC_VERSION) + #define JSON_HEDLEY_ARM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ARMCC_VERSION / 1000000, (__ARMCC_VERSION % 1000000) / 10000, (__ARMCC_VERSION % 10000) / 100) +#endif + +#if defined(JSON_HEDLEY_ARM_VERSION_CHECK) + #undef JSON_HEDLEY_ARM_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_ARM_VERSION) + #define JSON_HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_ARM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_IBM_VERSION) + #undef JSON_HEDLEY_IBM_VERSION +#endif +#if defined(__ibmxl__) + #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ibmxl_version__, __ibmxl_release__, __ibmxl_modification__) +#elif defined(__xlC__) && defined(__xlC_ver__) + #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, (__xlC_ver__ >> 8) & 0xff) +#elif defined(__xlC__) + #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, 0) +#endif + +#if defined(JSON_HEDLEY_IBM_VERSION_CHECK) + #undef JSON_HEDLEY_IBM_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_IBM_VERSION) + #define JSON_HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_IBM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_VERSION) + #undef JSON_HEDLEY_TI_VERSION +#endif +#if \ + defined(__TI_COMPILER_VERSION__) && \ + ( \ + defined(__TMS470__) || defined(__TI_ARM__) || \ + defined(__MSP430__) || \ + defined(__TMS320C2000__) \ + ) +#if (__TI_COMPILER_VERSION__ >= 16000000) + #define JSON_HEDLEY_TI_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif +#endif + +#if defined(JSON_HEDLEY_TI_VERSION_CHECK) + #undef JSON_HEDLEY_TI_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_VERSION) + #define JSON_HEDLEY_TI_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CL2000_VERSION) + #undef JSON_HEDLEY_TI_CL2000_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C2000__) + #define JSON_HEDLEY_TI_CL2000_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CL2000_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CL2000_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CL2000_VERSION) + #define JSON_HEDLEY_TI_CL2000_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL2000_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CL2000_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CL430_VERSION) + #undef JSON_HEDLEY_TI_CL430_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__MSP430__) + #define JSON_HEDLEY_TI_CL430_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CL430_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CL430_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CL430_VERSION) + #define JSON_HEDLEY_TI_CL430_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL430_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CL430_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_ARMCL_VERSION) + #undef JSON_HEDLEY_TI_ARMCL_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && (defined(__TMS470__) || defined(__TI_ARM__)) + #define JSON_HEDLEY_TI_ARMCL_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_ARMCL_VERSION_CHECK) + #undef JSON_HEDLEY_TI_ARMCL_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_ARMCL_VERSION) + #define JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_ARMCL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CL6X_VERSION) + #undef JSON_HEDLEY_TI_CL6X_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C6X__) + #define JSON_HEDLEY_TI_CL6X_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CL6X_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CL6X_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CL6X_VERSION) + #define JSON_HEDLEY_TI_CL6X_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL6X_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CL6X_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CL7X_VERSION) + #undef JSON_HEDLEY_TI_CL7X_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__C7000__) + #define JSON_HEDLEY_TI_CL7X_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CL7X_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CL7X_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CL7X_VERSION) + #define JSON_HEDLEY_TI_CL7X_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL7X_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CL7X_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TI_CLPRU_VERSION) + #undef JSON_HEDLEY_TI_CLPRU_VERSION +#endif +#if defined(__TI_COMPILER_VERSION__) && defined(__PRU__) + #define JSON_HEDLEY_TI_CLPRU_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(JSON_HEDLEY_TI_CLPRU_VERSION_CHECK) + #undef JSON_HEDLEY_TI_CLPRU_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TI_CLPRU_VERSION) + #define JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CLPRU_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_CRAY_VERSION) + #undef JSON_HEDLEY_CRAY_VERSION +#endif +#if defined(_CRAYC) + #if defined(_RELEASE_PATCHLEVEL) + #define JSON_HEDLEY_CRAY_VERSION JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, _RELEASE_PATCHLEVEL) + #else + #define JSON_HEDLEY_CRAY_VERSION JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, 0) + #endif +#endif + +#if defined(JSON_HEDLEY_CRAY_VERSION_CHECK) + #undef JSON_HEDLEY_CRAY_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_CRAY_VERSION) + #define JSON_HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_CRAY_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_IAR_VERSION) + #undef JSON_HEDLEY_IAR_VERSION +#endif +#if defined(__IAR_SYSTEMS_ICC__) + #if __VER__ > 1000 + #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE((__VER__ / 1000000), ((__VER__ / 1000) % 1000), (__VER__ % 1000)) + #else + #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE(__VER__ / 100, __VER__ % 100, 0) + #endif +#endif + +#if defined(JSON_HEDLEY_IAR_VERSION_CHECK) + #undef JSON_HEDLEY_IAR_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_IAR_VERSION) + #define JSON_HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_IAR_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_TINYC_VERSION) + #undef JSON_HEDLEY_TINYC_VERSION +#endif +#if defined(__TINYC__) + #define JSON_HEDLEY_TINYC_VERSION JSON_HEDLEY_VERSION_ENCODE(__TINYC__ / 1000, (__TINYC__ / 100) % 10, __TINYC__ % 100) +#endif + +#if defined(JSON_HEDLEY_TINYC_VERSION_CHECK) + #undef JSON_HEDLEY_TINYC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_TINYC_VERSION) + #define JSON_HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TINYC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_DMC_VERSION) + #undef JSON_HEDLEY_DMC_VERSION +#endif +#if defined(__DMC__) + #define JSON_HEDLEY_DMC_VERSION JSON_HEDLEY_VERSION_ENCODE(__DMC__ >> 8, (__DMC__ >> 4) & 0xf, __DMC__ & 0xf) +#endif + +#if defined(JSON_HEDLEY_DMC_VERSION_CHECK) + #undef JSON_HEDLEY_DMC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_DMC_VERSION) + #define JSON_HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_DMC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_COMPCERT_VERSION) + #undef JSON_HEDLEY_COMPCERT_VERSION +#endif +#if defined(__COMPCERT_VERSION__) + #define JSON_HEDLEY_COMPCERT_VERSION JSON_HEDLEY_VERSION_ENCODE(__COMPCERT_VERSION__ / 10000, (__COMPCERT_VERSION__ / 100) % 100, __COMPCERT_VERSION__ % 100) +#endif + +#if defined(JSON_HEDLEY_COMPCERT_VERSION_CHECK) + #undef JSON_HEDLEY_COMPCERT_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_COMPCERT_VERSION) + #define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_COMPCERT_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_PELLES_VERSION) + #undef JSON_HEDLEY_PELLES_VERSION +#endif +#if defined(__POCC__) + #define JSON_HEDLEY_PELLES_VERSION JSON_HEDLEY_VERSION_ENCODE(__POCC__ / 100, __POCC__ % 100, 0) +#endif + +#if defined(JSON_HEDLEY_PELLES_VERSION_CHECK) + #undef JSON_HEDLEY_PELLES_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_PELLES_VERSION) + #define JSON_HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_PELLES_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_MCST_LCC_VERSION) + #undef JSON_HEDLEY_MCST_LCC_VERSION +#endif +#if defined(__LCC__) && defined(__LCC_MINOR__) + #define JSON_HEDLEY_MCST_LCC_VERSION JSON_HEDLEY_VERSION_ENCODE(__LCC__ / 100, __LCC__ % 100, __LCC_MINOR__) +#endif + +#if defined(JSON_HEDLEY_MCST_LCC_VERSION_CHECK) + #undef JSON_HEDLEY_MCST_LCC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_MCST_LCC_VERSION) + #define JSON_HEDLEY_MCST_LCC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_MCST_LCC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_MCST_LCC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_GCC_VERSION) + #undef JSON_HEDLEY_GCC_VERSION +#endif +#if \ + defined(JSON_HEDLEY_GNUC_VERSION) && \ + !defined(__clang__) && \ + !defined(JSON_HEDLEY_INTEL_VERSION) && \ + !defined(JSON_HEDLEY_PGI_VERSION) && \ + !defined(JSON_HEDLEY_ARM_VERSION) && \ + !defined(JSON_HEDLEY_CRAY_VERSION) && \ + !defined(JSON_HEDLEY_TI_VERSION) && \ + !defined(JSON_HEDLEY_TI_ARMCL_VERSION) && \ + !defined(JSON_HEDLEY_TI_CL430_VERSION) && \ + !defined(JSON_HEDLEY_TI_CL2000_VERSION) && \ + !defined(JSON_HEDLEY_TI_CL6X_VERSION) && \ + !defined(JSON_HEDLEY_TI_CL7X_VERSION) && \ + !defined(JSON_HEDLEY_TI_CLPRU_VERSION) && \ + !defined(__COMPCERT__) && \ + !defined(JSON_HEDLEY_MCST_LCC_VERSION) + #define JSON_HEDLEY_GCC_VERSION JSON_HEDLEY_GNUC_VERSION +#endif + +#if defined(JSON_HEDLEY_GCC_VERSION_CHECK) + #undef JSON_HEDLEY_GCC_VERSION_CHECK +#endif +#if defined(JSON_HEDLEY_GCC_VERSION) + #define JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_GCC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch)) +#else + #define JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (0) +#endif + +#if defined(JSON_HEDLEY_HAS_ATTRIBUTE) + #undef JSON_HEDLEY_HAS_ATTRIBUTE +#endif +#if \ + defined(__has_attribute) && \ + ( \ + (!defined(JSON_HEDLEY_IAR_VERSION) || JSON_HEDLEY_IAR_VERSION_CHECK(8,5,9)) \ + ) +# define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) __has_attribute(attribute) +#else +# define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_ATTRIBUTE) + #undef JSON_HEDLEY_GNUC_HAS_ATTRIBUTE +#endif +#if defined(__has_attribute) + #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_HAS_ATTRIBUTE(attribute) +#else + #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_ATTRIBUTE) + #undef JSON_HEDLEY_GCC_HAS_ATTRIBUTE +#endif +#if defined(__has_attribute) + #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_HAS_ATTRIBUTE(attribute) +#else + #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE) + #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE +#endif +#if \ + defined(__has_cpp_attribute) && \ + defined(__cplusplus) && \ + (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) __has_cpp_attribute(attribute) +#else + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) (0) +#endif + +#if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS) + #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS +#endif +#if !defined(__cplusplus) || !defined(__has_cpp_attribute) + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0) +#elif \ + !defined(JSON_HEDLEY_PGI_VERSION) && \ + !defined(JSON_HEDLEY_IAR_VERSION) && \ + (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) && \ + (!defined(JSON_HEDLEY_MSVC_VERSION) || JSON_HEDLEY_MSVC_VERSION_CHECK(19,20,0)) + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) JSON_HEDLEY_HAS_CPP_ATTRIBUTE(ns::attribute) +#else + #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE) + #undef JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE +#endif +#if defined(__has_cpp_attribute) && defined(__cplusplus) + #define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute) +#else + #define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE) + #undef JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE +#endif +#if defined(__has_cpp_attribute) && defined(__cplusplus) + #define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute) +#else + #define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_BUILTIN) + #undef JSON_HEDLEY_HAS_BUILTIN +#endif +#if defined(__has_builtin) + #define JSON_HEDLEY_HAS_BUILTIN(builtin) __has_builtin(builtin) +#else + #define JSON_HEDLEY_HAS_BUILTIN(builtin) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_BUILTIN) + #undef JSON_HEDLEY_GNUC_HAS_BUILTIN +#endif +#if defined(__has_builtin) + #define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin) +#else + #define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_BUILTIN) + #undef JSON_HEDLEY_GCC_HAS_BUILTIN +#endif +#if defined(__has_builtin) + #define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin) +#else + #define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_FEATURE) + #undef JSON_HEDLEY_HAS_FEATURE +#endif +#if defined(__has_feature) + #define JSON_HEDLEY_HAS_FEATURE(feature) __has_feature(feature) +#else + #define JSON_HEDLEY_HAS_FEATURE(feature) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_FEATURE) + #undef JSON_HEDLEY_GNUC_HAS_FEATURE +#endif +#if defined(__has_feature) + #define JSON_HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature) +#else + #define JSON_HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_FEATURE) + #undef JSON_HEDLEY_GCC_HAS_FEATURE +#endif +#if defined(__has_feature) + #define JSON_HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature) +#else + #define JSON_HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_EXTENSION) + #undef JSON_HEDLEY_HAS_EXTENSION +#endif +#if defined(__has_extension) + #define JSON_HEDLEY_HAS_EXTENSION(extension) __has_extension(extension) +#else + #define JSON_HEDLEY_HAS_EXTENSION(extension) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_EXTENSION) + #undef JSON_HEDLEY_GNUC_HAS_EXTENSION +#endif +#if defined(__has_extension) + #define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension) +#else + #define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_EXTENSION) + #undef JSON_HEDLEY_GCC_HAS_EXTENSION +#endif +#if defined(__has_extension) + #define JSON_HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension) +#else + #define JSON_HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE) + #undef JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE +#endif +#if defined(__has_declspec_attribute) + #define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) __has_declspec_attribute(attribute) +#else + #define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE) + #undef JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE +#endif +#if defined(__has_declspec_attribute) + #define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute) +#else + #define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE) + #undef JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE +#endif +#if defined(__has_declspec_attribute) + #define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute) +#else + #define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_HAS_WARNING) + #undef JSON_HEDLEY_HAS_WARNING +#endif +#if defined(__has_warning) + #define JSON_HEDLEY_HAS_WARNING(warning) __has_warning(warning) +#else + #define JSON_HEDLEY_HAS_WARNING(warning) (0) +#endif + +#if defined(JSON_HEDLEY_GNUC_HAS_WARNING) + #undef JSON_HEDLEY_GNUC_HAS_WARNING +#endif +#if defined(__has_warning) + #define JSON_HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning) +#else + #define JSON_HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_GCC_HAS_WARNING) + #undef JSON_HEDLEY_GCC_HAS_WARNING +#endif +#if defined(__has_warning) + #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning) +#else + #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if \ + (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ + defined(__clang__) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,7,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(2,0,1) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,1,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,0,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,17) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(8,0,0) || \ + (JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) && defined(__C99_PRAGMA_OPERATOR)) + #define JSON_HEDLEY_PRAGMA(value) _Pragma(#value) +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) + #define JSON_HEDLEY_PRAGMA(value) __pragma(value) +#else + #define JSON_HEDLEY_PRAGMA(value) +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_PUSH) + #undef JSON_HEDLEY_DIAGNOSTIC_PUSH +#endif +#if defined(JSON_HEDLEY_DIAGNOSTIC_POP) + #undef JSON_HEDLEY_DIAGNOSTIC_POP +#endif +#if defined(__clang__) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("clang diagnostic push") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("clang diagnostic pop") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("GCC diagnostic pop") +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH __pragma(warning(push)) + #define JSON_HEDLEY_DIAGNOSTIC_POP __pragma(warning(pop)) +#elif JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("push") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("pop") +#elif \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,4,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,1,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("diag_push") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("diag_pop") +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0) + #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma("warning(push)") + #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma("warning(pop)") +#else + #define JSON_HEDLEY_DIAGNOSTIC_PUSH + #define JSON_HEDLEY_DIAGNOSTIC_POP +#endif + +/* JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ is for + HEDLEY INTERNAL USE ONLY. API subject to change without notice. */ +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ +#endif +#if defined(__cplusplus) +# if JSON_HEDLEY_HAS_WARNING("-Wc++98-compat") +# if JSON_HEDLEY_HAS_WARNING("-Wc++17-extensions") +# if JSON_HEDLEY_HAS_WARNING("-Wc++1z-extensions") +# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ + _Pragma("clang diagnostic ignored \"-Wc++17-extensions\"") \ + _Pragma("clang diagnostic ignored \"-Wc++1z-extensions\"") \ + xpr \ + JSON_HEDLEY_DIAGNOSTIC_POP +# else +# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ + _Pragma("clang diagnostic ignored \"-Wc++17-extensions\"") \ + xpr \ + JSON_HEDLEY_DIAGNOSTIC_POP +# endif +# else +# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ + xpr \ + JSON_HEDLEY_DIAGNOSTIC_POP +# endif +# endif +#endif +#if !defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(x) x +#endif + +#if defined(JSON_HEDLEY_CONST_CAST) + #undef JSON_HEDLEY_CONST_CAST +#endif +#if defined(__cplusplus) +# define JSON_HEDLEY_CONST_CAST(T, expr) (const_cast(expr)) +#elif \ + JSON_HEDLEY_HAS_WARNING("-Wcast-qual") || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) +# define JSON_HEDLEY_CONST_CAST(T, expr) (__extension__ ({ \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL \ + ((T) (expr)); \ + JSON_HEDLEY_DIAGNOSTIC_POP \ + })) +#else +# define JSON_HEDLEY_CONST_CAST(T, expr) ((T) (expr)) +#endif + +#if defined(JSON_HEDLEY_REINTERPRET_CAST) + #undef JSON_HEDLEY_REINTERPRET_CAST +#endif +#if defined(__cplusplus) + #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) (reinterpret_cast(expr)) +#else + #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) ((T) (expr)) +#endif + +#if defined(JSON_HEDLEY_STATIC_CAST) + #undef JSON_HEDLEY_STATIC_CAST +#endif +#if defined(__cplusplus) + #define JSON_HEDLEY_STATIC_CAST(T, expr) (static_cast(expr)) +#else + #define JSON_HEDLEY_STATIC_CAST(T, expr) ((T) (expr)) +#endif + +#if defined(JSON_HEDLEY_CPP_CAST) + #undef JSON_HEDLEY_CPP_CAST +#endif +#if defined(__cplusplus) +# if JSON_HEDLEY_HAS_WARNING("-Wold-style-cast") +# define JSON_HEDLEY_CPP_CAST(T, expr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wold-style-cast\"") \ + ((T) (expr)) \ + JSON_HEDLEY_DIAGNOSTIC_POP +# elif JSON_HEDLEY_IAR_VERSION_CHECK(8,3,0) +# define JSON_HEDLEY_CPP_CAST(T, expr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("diag_suppress=Pe137") \ + JSON_HEDLEY_DIAGNOSTIC_POP +# else +# define JSON_HEDLEY_CPP_CAST(T, expr) ((T) (expr)) +# endif +#else +# define JSON_HEDLEY_CPP_CAST(T, expr) (expr) +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wdeprecated-declarations") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warning(disable:1478 1786)") +#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:1478 1786)) +#elif JSON_HEDLEY_PGI_VERSION_CHECK(20,7,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1216,1444,1445") +#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:4996)) +#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1215,1444") +#elif \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress 1291,1718") +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && !defined(__cplusplus) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,E_DEPRECATED_ATT,E_DEPRECATED_ATT_MESS)") +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && defined(__cplusplus) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("error_messages(off,symdeprecated,symdeprecated2)") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("diag_suppress=Pe1444,Pe1215") +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma("warn(disable:2241)") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("clang diagnostic ignored \"-Wunknown-pragmas\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("warning(disable:161)") +#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:161)) +#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 1675") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("GCC diagnostic ignored \"-Wunknown-pragmas\"") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:4068)) +#elif \ + JSON_HEDLEY_TI_VERSION_CHECK(16,9,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,3,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163") +#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 163") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress=Pe161") +#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma("diag_suppress 161") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunknown-attributes") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("clang diagnostic ignored \"-Wunknown-attributes\"") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("warning(disable:1292)") +#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:1292)) +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:5030)) +#elif JSON_HEDLEY_PGI_VERSION_CHECK(20,7,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097,1098") +#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097") +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("error_messages(off,attrskipunsup)") +#elif \ + JSON_HEDLEY_TI_VERSION_CHECK(18,1,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,3,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1173") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress=Pe1097") +#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wcast-qual") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("clang diagnostic ignored \"-Wcast-qual\"") +#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("warning(disable:2203 2331)") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma("GCC diagnostic ignored \"-Wcast-qual\"") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL +#endif + +#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION) + #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunused-function") + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("clang diagnostic ignored \"-Wunused-function\"") +#elif JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("GCC diagnostic ignored \"-Wunused-function\"") +#elif JSON_HEDLEY_MSVC_VERSION_CHECK(1,0,0) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION __pragma(warning(disable:4505)) +#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma("diag_suppress 3142") +#else + #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION +#endif + +#if defined(JSON_HEDLEY_DEPRECATED) + #undef JSON_HEDLEY_DEPRECATED +#endif +#if defined(JSON_HEDLEY_DEPRECATED_FOR) + #undef JSON_HEDLEY_DEPRECATED_FOR +#endif +#if \ + JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated("Since " # since)) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated("Since " #since "; use " #replacement)) +#elif \ + (JSON_HEDLEY_HAS_EXTENSION(attribute_deprecated_with_message) && !defined(JSON_HEDLEY_IAR_VERSION)) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(18,1,0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(18,1,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,3,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,3,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__("Since " #since))) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__("Since " #since "; use " #replacement))) +#elif defined(__cplusplus) && (__cplusplus >= 201402L) + #define JSON_HEDLEY_DEPRECATED(since) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since)]]) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since "; use " #replacement)]]) +#elif \ + JSON_HEDLEY_HAS_ATTRIBUTE(deprecated) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0) + #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__)) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__)) +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ + JSON_HEDLEY_PELLES_VERSION_CHECK(6,50,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated) +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_DEPRECATED(since) _Pragma("deprecated") + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) _Pragma("deprecated") +#else + #define JSON_HEDLEY_DEPRECATED(since) + #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) +#endif + +#if defined(JSON_HEDLEY_UNAVAILABLE) + #undef JSON_HEDLEY_UNAVAILABLE +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(warning) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_UNAVAILABLE(available_since) __attribute__((__warning__("Not available until " #available_since))) +#else + #define JSON_HEDLEY_UNAVAILABLE(available_since) +#endif + +#if defined(JSON_HEDLEY_WARN_UNUSED_RESULT) + #undef JSON_HEDLEY_WARN_UNUSED_RESULT +#endif +#if defined(JSON_HEDLEY_WARN_UNUSED_RESULT_MSG) + #undef JSON_HEDLEY_WARN_UNUSED_RESULT_MSG +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(warn_unused_result) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__)) + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) __attribute__((__warn_unused_result__)) +#elif (JSON_HEDLEY_HAS_CPP_ATTRIBUTE(nodiscard) >= 201907L) + #define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard(msg)]]) +#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE(nodiscard) + #define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) +#elif defined(_Check_return_) /* SAL */ + #define JSON_HEDLEY_WARN_UNUSED_RESULT _Check_return_ + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) _Check_return_ +#else + #define JSON_HEDLEY_WARN_UNUSED_RESULT + #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) +#endif + +#if defined(JSON_HEDLEY_SENTINEL) + #undef JSON_HEDLEY_SENTINEL +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(sentinel) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_SENTINEL(position) __attribute__((__sentinel__(position))) +#else + #define JSON_HEDLEY_SENTINEL(position) +#endif + +#if defined(JSON_HEDLEY_NO_RETURN) + #undef JSON_HEDLEY_NO_RETURN +#endif +#if JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_NO_RETURN __noreturn +#elif \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__)) +#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L + #define JSON_HEDLEY_NO_RETURN _Noreturn +#elif defined(__cplusplus) && (__cplusplus >= 201103L) + #define JSON_HEDLEY_NO_RETURN JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[noreturn]]) +#elif \ + JSON_HEDLEY_HAS_ATTRIBUTE(noreturn) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,2,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0) + #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__)) +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) + #define JSON_HEDLEY_NO_RETURN _Pragma("does_not_return") +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_NO_RETURN __declspec(noreturn) +#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus) + #define JSON_HEDLEY_NO_RETURN _Pragma("FUNC_NEVER_RETURNS;") +#elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0) + #define JSON_HEDLEY_NO_RETURN __attribute((noreturn)) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(9,0,0) + #define JSON_HEDLEY_NO_RETURN __declspec(noreturn) +#else + #define JSON_HEDLEY_NO_RETURN +#endif + +#if defined(JSON_HEDLEY_NO_ESCAPE) + #undef JSON_HEDLEY_NO_ESCAPE +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(noescape) + #define JSON_HEDLEY_NO_ESCAPE __attribute__((__noescape__)) +#else + #define JSON_HEDLEY_NO_ESCAPE +#endif + +#if defined(JSON_HEDLEY_UNREACHABLE) + #undef JSON_HEDLEY_UNREACHABLE +#endif +#if defined(JSON_HEDLEY_UNREACHABLE_RETURN) + #undef JSON_HEDLEY_UNREACHABLE_RETURN +#endif +#if defined(JSON_HEDLEY_ASSUME) + #undef JSON_HEDLEY_ASSUME +#endif +#if \ + JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_ASSUME(expr) __assume(expr) +#elif JSON_HEDLEY_HAS_BUILTIN(__builtin_assume) + #define JSON_HEDLEY_ASSUME(expr) __builtin_assume(expr) +#elif \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) + #if defined(__cplusplus) + #define JSON_HEDLEY_ASSUME(expr) std::_nassert(expr) + #else + #define JSON_HEDLEY_ASSUME(expr) _nassert(expr) + #endif +#endif +#if \ + (JSON_HEDLEY_HAS_BUILTIN(__builtin_unreachable) && (!defined(JSON_HEDLEY_ARM_VERSION))) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(18,10,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13,1,5) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(10,0,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_UNREACHABLE() __builtin_unreachable() +#elif defined(JSON_HEDLEY_ASSUME) + #define JSON_HEDLEY_UNREACHABLE() JSON_HEDLEY_ASSUME(0) +#endif +#if !defined(JSON_HEDLEY_ASSUME) + #if defined(JSON_HEDLEY_UNREACHABLE) + #define JSON_HEDLEY_ASSUME(expr) JSON_HEDLEY_STATIC_CAST(void, ((expr) ? 1 : (JSON_HEDLEY_UNREACHABLE(), 1))) + #else + #define JSON_HEDLEY_ASSUME(expr) JSON_HEDLEY_STATIC_CAST(void, expr) + #endif +#endif +#if defined(JSON_HEDLEY_UNREACHABLE) + #if \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) + #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return (JSON_HEDLEY_STATIC_CAST(void, JSON_HEDLEY_ASSUME(0)), (value)) + #else + #define JSON_HEDLEY_UNREACHABLE_RETURN(value) JSON_HEDLEY_UNREACHABLE() + #endif +#else + #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return (value) +#endif +#if !defined(JSON_HEDLEY_UNREACHABLE) + #define JSON_HEDLEY_UNREACHABLE() JSON_HEDLEY_ASSUME(0) +#endif + +JSON_HEDLEY_DIAGNOSTIC_PUSH +#if JSON_HEDLEY_HAS_WARNING("-Wpedantic") + #pragma clang diagnostic ignored "-Wpedantic" +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wc++98-compat-pedantic") && defined(__cplusplus) + #pragma clang diagnostic ignored "-Wc++98-compat-pedantic" +#endif +#if JSON_HEDLEY_GCC_HAS_WARNING("-Wvariadic-macros",4,0,0) + #if defined(__clang__) + #pragma clang diagnostic ignored "-Wvariadic-macros" + #elif defined(JSON_HEDLEY_GCC_VERSION) + #pragma GCC diagnostic ignored "-Wvariadic-macros" + #endif +#endif +#if defined(JSON_HEDLEY_NON_NULL) + #undef JSON_HEDLEY_NON_NULL +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(nonnull) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) + #define JSON_HEDLEY_NON_NULL(...) __attribute__((__nonnull__(__VA_ARGS__))) +#else + #define JSON_HEDLEY_NON_NULL(...) +#endif +JSON_HEDLEY_DIAGNOSTIC_POP + +#if defined(JSON_HEDLEY_PRINTF_FORMAT) + #undef JSON_HEDLEY_PRINTF_FORMAT +#endif +#if defined(__MINGW32__) && JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && !defined(__USE_MINGW_ANSI_STDIO) + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(ms_printf, string_idx, first_to_check))) +#elif defined(__MINGW32__) && JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && defined(__USE_MINGW_ANSI_STDIO) + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(gnu_printf, string_idx, first_to_check))) +#elif \ + JSON_HEDLEY_HAS_ATTRIBUTE(format) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(__printf__, string_idx, first_to_check))) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(6,0,0) + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __declspec(vaformat(printf,string_idx,first_to_check)) +#else + #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) +#endif + +#if defined(JSON_HEDLEY_CONSTEXPR) + #undef JSON_HEDLEY_CONSTEXPR +#endif +#if defined(__cplusplus) + #if __cplusplus >= 201103L + #define JSON_HEDLEY_CONSTEXPR JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(constexpr) + #endif +#endif +#if !defined(JSON_HEDLEY_CONSTEXPR) + #define JSON_HEDLEY_CONSTEXPR +#endif + +#if defined(JSON_HEDLEY_PREDICT) + #undef JSON_HEDLEY_PREDICT +#endif +#if defined(JSON_HEDLEY_LIKELY) + #undef JSON_HEDLEY_LIKELY +#endif +#if defined(JSON_HEDLEY_UNLIKELY) + #undef JSON_HEDLEY_UNLIKELY +#endif +#if defined(JSON_HEDLEY_UNPREDICTABLE) + #undef JSON_HEDLEY_UNPREDICTABLE +#endif +#if JSON_HEDLEY_HAS_BUILTIN(__builtin_unpredictable) + #define JSON_HEDLEY_UNPREDICTABLE(expr) __builtin_unpredictable((expr)) +#endif +#if \ + (JSON_HEDLEY_HAS_BUILTIN(__builtin_expect_with_probability) && !defined(JSON_HEDLEY_PGI_VERSION)) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(9,0,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) +# define JSON_HEDLEY_PREDICT(expr, value, probability) __builtin_expect_with_probability( (expr), (value), (probability)) +# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) __builtin_expect_with_probability(!!(expr), 1 , (probability)) +# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) __builtin_expect_with_probability(!!(expr), 0 , (probability)) +# define JSON_HEDLEY_LIKELY(expr) __builtin_expect (!!(expr), 1 ) +# define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect (!!(expr), 0 ) +#elif \ + (JSON_HEDLEY_HAS_BUILTIN(__builtin_expect) && !defined(JSON_HEDLEY_INTEL_CL_VERSION)) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,7,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,1,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,27) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) +# define JSON_HEDLEY_PREDICT(expr, expected, probability) \ + (((probability) >= 0.9) ? __builtin_expect((expr), (expected)) : (JSON_HEDLEY_STATIC_CAST(void, expected), (expr))) +# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) \ + (__extension__ ({ \ + double hedley_probability_ = (probability); \ + ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 1) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 0) : !!(expr))); \ + })) +# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) \ + (__extension__ ({ \ + double hedley_probability_ = (probability); \ + ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 0) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 1) : !!(expr))); \ + })) +# define JSON_HEDLEY_LIKELY(expr) __builtin_expect(!!(expr), 1) +# define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect(!!(expr), 0) +#else +# define JSON_HEDLEY_PREDICT(expr, expected, probability) (JSON_HEDLEY_STATIC_CAST(void, expected), (expr)) +# define JSON_HEDLEY_PREDICT_TRUE(expr, probability) (!!(expr)) +# define JSON_HEDLEY_PREDICT_FALSE(expr, probability) (!!(expr)) +# define JSON_HEDLEY_LIKELY(expr) (!!(expr)) +# define JSON_HEDLEY_UNLIKELY(expr) (!!(expr)) +#endif +#if !defined(JSON_HEDLEY_UNPREDICTABLE) + #define JSON_HEDLEY_UNPREDICTABLE(expr) JSON_HEDLEY_PREDICT(expr, 1, 0.5) +#endif + +#if defined(JSON_HEDLEY_MALLOC) + #undef JSON_HEDLEY_MALLOC +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(malloc) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_MALLOC __attribute__((__malloc__)) +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) + #define JSON_HEDLEY_MALLOC _Pragma("returns_new_memory") +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_MALLOC __declspec(restrict) +#else + #define JSON_HEDLEY_MALLOC +#endif + +#if defined(JSON_HEDLEY_PURE) + #undef JSON_HEDLEY_PURE +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(pure) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(2,96,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) +# define JSON_HEDLEY_PURE __attribute__((__pure__)) +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) +# define JSON_HEDLEY_PURE _Pragma("does_not_write_global_data") +#elif defined(__cplusplus) && \ + ( \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(2,0,1) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) \ + ) +# define JSON_HEDLEY_PURE _Pragma("FUNC_IS_PURE;") +#else +# define JSON_HEDLEY_PURE +#endif + +#if defined(JSON_HEDLEY_CONST) + #undef JSON_HEDLEY_CONST +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(const) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(2,5,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_CONST __attribute__((__const__)) +#elif \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) + #define JSON_HEDLEY_CONST _Pragma("no_side_effect") +#else + #define JSON_HEDLEY_CONST JSON_HEDLEY_PURE +#endif + +#if defined(JSON_HEDLEY_RESTRICT) + #undef JSON_HEDLEY_RESTRICT +#endif +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && !defined(__cplusplus) + #define JSON_HEDLEY_RESTRICT restrict +#elif \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,4) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,1,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus)) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \ + defined(__clang__) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_RESTRICT __restrict +#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,3,0) && !defined(__cplusplus) + #define JSON_HEDLEY_RESTRICT _Restrict +#else + #define JSON_HEDLEY_RESTRICT +#endif + +#if defined(JSON_HEDLEY_INLINE) + #undef JSON_HEDLEY_INLINE +#endif +#if \ + (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ + (defined(__cplusplus) && (__cplusplus >= 199711L)) + #define JSON_HEDLEY_INLINE inline +#elif \ + defined(JSON_HEDLEY_GCC_VERSION) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(6,2,0) + #define JSON_HEDLEY_INLINE __inline__ +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,1,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(3,1,0) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_INLINE __inline +#else + #define JSON_HEDLEY_INLINE +#endif + +#if defined(JSON_HEDLEY_ALWAYS_INLINE) + #undef JSON_HEDLEY_ALWAYS_INLINE +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(always_inline) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0) +# define JSON_HEDLEY_ALWAYS_INLINE __attribute__((__always_inline__)) JSON_HEDLEY_INLINE +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) +# define JSON_HEDLEY_ALWAYS_INLINE __forceinline +#elif defined(__cplusplus) && \ + ( \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) \ + ) +# define JSON_HEDLEY_ALWAYS_INLINE _Pragma("FUNC_ALWAYS_INLINE;") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) +# define JSON_HEDLEY_ALWAYS_INLINE _Pragma("inline=forced") +#else +# define JSON_HEDLEY_ALWAYS_INLINE JSON_HEDLEY_INLINE +#endif + +#if defined(JSON_HEDLEY_NEVER_INLINE) + #undef JSON_HEDLEY_NEVER_INLINE +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(noinline) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \ + JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \ + (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \ + (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \ + (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \ + JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \ + JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \ + JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0) + #define JSON_HEDLEY_NEVER_INLINE __attribute__((__noinline__)) +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline) +#elif JSON_HEDLEY_PGI_VERSION_CHECK(10,2,0) + #define JSON_HEDLEY_NEVER_INLINE _Pragma("noinline") +#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus) + #define JSON_HEDLEY_NEVER_INLINE _Pragma("FUNC_CANNOT_INLINE;") +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) + #define JSON_HEDLEY_NEVER_INLINE _Pragma("inline=never") +#elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0) + #define JSON_HEDLEY_NEVER_INLINE __attribute((noinline)) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(9,0,0) + #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline) +#else + #define JSON_HEDLEY_NEVER_INLINE +#endif + +#if defined(JSON_HEDLEY_PRIVATE) + #undef JSON_HEDLEY_PRIVATE +#endif +#if defined(JSON_HEDLEY_PUBLIC) + #undef JSON_HEDLEY_PUBLIC +#endif +#if defined(JSON_HEDLEY_IMPORT) + #undef JSON_HEDLEY_IMPORT +#endif +#if defined(_WIN32) || defined(__CYGWIN__) +# define JSON_HEDLEY_PRIVATE +# define JSON_HEDLEY_PUBLIC __declspec(dllexport) +# define JSON_HEDLEY_IMPORT __declspec(dllimport) +#else +# if \ + JSON_HEDLEY_HAS_ATTRIBUTE(visibility) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ + JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ + ( \ + defined(__TI_EABI__) && \ + ( \ + (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) \ + ) \ + ) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) +# define JSON_HEDLEY_PRIVATE __attribute__((__visibility__("hidden"))) +# define JSON_HEDLEY_PUBLIC __attribute__((__visibility__("default"))) +# else +# define JSON_HEDLEY_PRIVATE +# define JSON_HEDLEY_PUBLIC +# endif +# define JSON_HEDLEY_IMPORT extern +#endif + +#if defined(JSON_HEDLEY_NO_THROW) + #undef JSON_HEDLEY_NO_THROW +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(nothrow) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_NO_THROW __attribute__((__nothrow__)) +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(13,1,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) + #define JSON_HEDLEY_NO_THROW __declspec(nothrow) +#else + #define JSON_HEDLEY_NO_THROW +#endif + +#if defined(JSON_HEDLEY_FALL_THROUGH) + #undef JSON_HEDLEY_FALL_THROUGH +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(fallthrough) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(7,0,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_FALL_THROUGH __attribute__((__fallthrough__)) +#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(clang,fallthrough) + #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[clang::fallthrough]]) +#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE(fallthrough) + #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[fallthrough]]) +#elif defined(__fallthrough) /* SAL */ + #define JSON_HEDLEY_FALL_THROUGH __fallthrough +#else + #define JSON_HEDLEY_FALL_THROUGH +#endif + +#if defined(JSON_HEDLEY_RETURNS_NON_NULL) + #undef JSON_HEDLEY_RETURNS_NON_NULL +#endif +#if \ + JSON_HEDLEY_HAS_ATTRIBUTE(returns_nonnull) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_RETURNS_NON_NULL __attribute__((__returns_nonnull__)) +#elif defined(_Ret_notnull_) /* SAL */ + #define JSON_HEDLEY_RETURNS_NON_NULL _Ret_notnull_ +#else + #define JSON_HEDLEY_RETURNS_NON_NULL +#endif + +#if defined(JSON_HEDLEY_ARRAY_PARAM) + #undef JSON_HEDLEY_ARRAY_PARAM +#endif +#if \ + defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \ + !defined(__STDC_NO_VLA__) && \ + !defined(__cplusplus) && \ + !defined(JSON_HEDLEY_PGI_VERSION) && \ + !defined(JSON_HEDLEY_TINYC_VERSION) + #define JSON_HEDLEY_ARRAY_PARAM(name) (name) +#else + #define JSON_HEDLEY_ARRAY_PARAM(name) +#endif + +#if defined(JSON_HEDLEY_IS_CONSTANT) + #undef JSON_HEDLEY_IS_CONSTANT +#endif +#if defined(JSON_HEDLEY_REQUIRE_CONSTEXPR) + #undef JSON_HEDLEY_REQUIRE_CONSTEXPR +#endif +/* JSON_HEDLEY_IS_CONSTEXPR_ is for + HEDLEY INTERNAL USE ONLY. API subject to change without notice. */ +#if defined(JSON_HEDLEY_IS_CONSTEXPR_) + #undef JSON_HEDLEY_IS_CONSTEXPR_ +#endif +#if \ + JSON_HEDLEY_HAS_BUILTIN(__builtin_constant_p) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,19) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ + JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \ + (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) && !defined(__cplusplus)) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \ + JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) + #define JSON_HEDLEY_IS_CONSTANT(expr) __builtin_constant_p(expr) +#endif +#if !defined(__cplusplus) +# if \ + JSON_HEDLEY_HAS_BUILTIN(__builtin_types_compatible_p) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ + JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) || \ + JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,24) +#if defined(__INTPTR_TYPE__) + #define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0)), int*) +#else + #include + #define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((intptr_t) ((expr) * 0)) : (int*) 0)), int*) +#endif +# elif \ + ( \ + defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && \ + !defined(JSON_HEDLEY_SUNPRO_VERSION) && \ + !defined(JSON_HEDLEY_PGI_VERSION) && \ + !defined(JSON_HEDLEY_IAR_VERSION)) || \ + (JSON_HEDLEY_HAS_EXTENSION(c_generic_selections) && !defined(JSON_HEDLEY_IAR_VERSION)) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0) || \ + JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \ + JSON_HEDLEY_ARM_VERSION_CHECK(5,3,0) +#if defined(__INTPTR_TYPE__) + #define JSON_HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0), int*: 1, void*: 0) +#else + #include + #define JSON_HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((intptr_t) * 0) : (int*) 0), int*: 1, void*: 0) +#endif +# elif \ + defined(JSON_HEDLEY_GCC_VERSION) || \ + defined(JSON_HEDLEY_INTEL_VERSION) || \ + defined(JSON_HEDLEY_TINYC_VERSION) || \ + defined(JSON_HEDLEY_TI_ARMCL_VERSION) || \ + JSON_HEDLEY_TI_CL430_VERSION_CHECK(18,12,0) || \ + defined(JSON_HEDLEY_TI_CL2000_VERSION) || \ + defined(JSON_HEDLEY_TI_CL6X_VERSION) || \ + defined(JSON_HEDLEY_TI_CL7X_VERSION) || \ + defined(JSON_HEDLEY_TI_CLPRU_VERSION) || \ + defined(__clang__) +# define JSON_HEDLEY_IS_CONSTEXPR_(expr) ( \ + sizeof(void) != \ + sizeof(*( \ + 1 ? \ + ((void*) ((expr) * 0L) ) : \ +((struct { char v[sizeof(void) * 2]; } *) 1) \ + ) \ + ) \ + ) +# endif +#endif +#if defined(JSON_HEDLEY_IS_CONSTEXPR_) + #if !defined(JSON_HEDLEY_IS_CONSTANT) + #define JSON_HEDLEY_IS_CONSTANT(expr) JSON_HEDLEY_IS_CONSTEXPR_(expr) + #endif + #define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (JSON_HEDLEY_IS_CONSTEXPR_(expr) ? (expr) : (-1)) +#else + #if !defined(JSON_HEDLEY_IS_CONSTANT) + #define JSON_HEDLEY_IS_CONSTANT(expr) (0) + #endif + #define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (expr) +#endif + +#if defined(JSON_HEDLEY_BEGIN_C_DECLS) + #undef JSON_HEDLEY_BEGIN_C_DECLS +#endif +#if defined(JSON_HEDLEY_END_C_DECLS) + #undef JSON_HEDLEY_END_C_DECLS +#endif +#if defined(JSON_HEDLEY_C_DECL) + #undef JSON_HEDLEY_C_DECL +#endif +#if defined(__cplusplus) + #define JSON_HEDLEY_BEGIN_C_DECLS extern "C" { + #define JSON_HEDLEY_END_C_DECLS } + #define JSON_HEDLEY_C_DECL extern "C" +#else + #define JSON_HEDLEY_BEGIN_C_DECLS + #define JSON_HEDLEY_END_C_DECLS + #define JSON_HEDLEY_C_DECL +#endif + +#if defined(JSON_HEDLEY_STATIC_ASSERT) + #undef JSON_HEDLEY_STATIC_ASSERT +#endif +#if \ + !defined(__cplusplus) && ( \ + (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) || \ + (JSON_HEDLEY_HAS_FEATURE(c_static_assert) && !defined(JSON_HEDLEY_INTEL_CL_VERSION)) || \ + JSON_HEDLEY_GCC_VERSION_CHECK(6,0,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \ + defined(_Static_assert) \ + ) +# define JSON_HEDLEY_STATIC_ASSERT(expr, message) _Static_assert(expr, message) +#elif \ + (defined(__cplusplus) && (__cplusplus >= 201103L)) || \ + JSON_HEDLEY_MSVC_VERSION_CHECK(16,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) +# define JSON_HEDLEY_STATIC_ASSERT(expr, message) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(static_assert(expr, message)) +#else +# define JSON_HEDLEY_STATIC_ASSERT(expr, message) +#endif + +#if defined(JSON_HEDLEY_NULL) + #undef JSON_HEDLEY_NULL +#endif +#if defined(__cplusplus) + #if __cplusplus >= 201103L + #define JSON_HEDLEY_NULL JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(nullptr) + #elif defined(NULL) + #define JSON_HEDLEY_NULL NULL + #else + #define JSON_HEDLEY_NULL JSON_HEDLEY_STATIC_CAST(void*, 0) + #endif +#elif defined(NULL) + #define JSON_HEDLEY_NULL NULL +#else + #define JSON_HEDLEY_NULL ((void*) 0) +#endif + +#if defined(JSON_HEDLEY_MESSAGE) + #undef JSON_HEDLEY_MESSAGE +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") +# define JSON_HEDLEY_MESSAGE(msg) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ + JSON_HEDLEY_PRAGMA(message msg) \ + JSON_HEDLEY_DIAGNOSTIC_POP +#elif \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) +# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message msg) +#elif JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0) +# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(_CRI message msg) +#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) +# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg)) +#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,0,0) +# define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg)) +#else +# define JSON_HEDLEY_MESSAGE(msg) +#endif + +#if defined(JSON_HEDLEY_WARNING) + #undef JSON_HEDLEY_WARNING +#endif +#if JSON_HEDLEY_HAS_WARNING("-Wunknown-pragmas") +# define JSON_HEDLEY_WARNING(msg) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \ + JSON_HEDLEY_PRAGMA(clang warning msg) \ + JSON_HEDLEY_DIAGNOSTIC_POP +#elif \ + JSON_HEDLEY_GCC_VERSION_CHECK(4,8,0) || \ + JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) || \ + JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) +# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(GCC warning msg) +#elif \ + JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) +# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(message(msg)) +#else +# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_MESSAGE(msg) +#endif + +#if defined(JSON_HEDLEY_REQUIRE) + #undef JSON_HEDLEY_REQUIRE +#endif +#if defined(JSON_HEDLEY_REQUIRE_MSG) + #undef JSON_HEDLEY_REQUIRE_MSG +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(diagnose_if) +# if JSON_HEDLEY_HAS_WARNING("-Wgcc-compat") +# define JSON_HEDLEY_REQUIRE(expr) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ + __attribute__((diagnose_if(!(expr), #expr, "error"))) \ + JSON_HEDLEY_DIAGNOSTIC_POP +# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ + __attribute__((diagnose_if(!(expr), msg, "error"))) \ + JSON_HEDLEY_DIAGNOSTIC_POP +# else +# define JSON_HEDLEY_REQUIRE(expr) __attribute__((diagnose_if(!(expr), #expr, "error"))) +# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) __attribute__((diagnose_if(!(expr), msg, "error"))) +# endif +#else +# define JSON_HEDLEY_REQUIRE(expr) +# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) +#endif + +#if defined(JSON_HEDLEY_FLAGS) + #undef JSON_HEDLEY_FLAGS +#endif +#if JSON_HEDLEY_HAS_ATTRIBUTE(flag_enum) && (!defined(__cplusplus) || JSON_HEDLEY_HAS_WARNING("-Wbitfield-enum-conversion")) + #define JSON_HEDLEY_FLAGS __attribute__((__flag_enum__)) +#else + #define JSON_HEDLEY_FLAGS +#endif + +#if defined(JSON_HEDLEY_FLAGS_CAST) + #undef JSON_HEDLEY_FLAGS_CAST +#endif +#if JSON_HEDLEY_INTEL_VERSION_CHECK(19,0,0) +# define JSON_HEDLEY_FLAGS_CAST(T, expr) (__extension__ ({ \ + JSON_HEDLEY_DIAGNOSTIC_PUSH \ + _Pragma("warning(disable:188)") \ + ((T) (expr)); \ + JSON_HEDLEY_DIAGNOSTIC_POP \ + })) +#else +# define JSON_HEDLEY_FLAGS_CAST(T, expr) JSON_HEDLEY_STATIC_CAST(T, expr) +#endif + +#if defined(JSON_HEDLEY_EMPTY_BASES) + #undef JSON_HEDLEY_EMPTY_BASES +#endif +#if \ + (JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,23918) && !JSON_HEDLEY_MSVC_VERSION_CHECK(20,0,0)) || \ + JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) + #define JSON_HEDLEY_EMPTY_BASES __declspec(empty_bases) +#else + #define JSON_HEDLEY_EMPTY_BASES +#endif + +/* Remaining macros are deprecated. */ + +#if defined(JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK) + #undef JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK +#endif +#if defined(__clang__) + #define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) (0) +#else + #define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) +#endif + +#if defined(JSON_HEDLEY_CLANG_HAS_ATTRIBUTE) + #undef JSON_HEDLEY_CLANG_HAS_ATTRIBUTE +#endif +#define JSON_HEDLEY_CLANG_HAS_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_ATTRIBUTE(attribute) + +#if defined(JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE) + #undef JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE +#endif +#define JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) + +#if defined(JSON_HEDLEY_CLANG_HAS_BUILTIN) + #undef JSON_HEDLEY_CLANG_HAS_BUILTIN +#endif +#define JSON_HEDLEY_CLANG_HAS_BUILTIN(builtin) JSON_HEDLEY_HAS_BUILTIN(builtin) + +#if defined(JSON_HEDLEY_CLANG_HAS_FEATURE) + #undef JSON_HEDLEY_CLANG_HAS_FEATURE +#endif +#define JSON_HEDLEY_CLANG_HAS_FEATURE(feature) JSON_HEDLEY_HAS_FEATURE(feature) + +#if defined(JSON_HEDLEY_CLANG_HAS_EXTENSION) + #undef JSON_HEDLEY_CLANG_HAS_EXTENSION +#endif +#define JSON_HEDLEY_CLANG_HAS_EXTENSION(extension) JSON_HEDLEY_HAS_EXTENSION(extension) + +#if defined(JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE) + #undef JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE +#endif +#define JSON_HEDLEY_CLANG_HAS_DECLSPEC_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) + +#if defined(JSON_HEDLEY_CLANG_HAS_WARNING) + #undef JSON_HEDLEY_CLANG_HAS_WARNING +#endif +#define JSON_HEDLEY_CLANG_HAS_WARNING(warning) JSON_HEDLEY_HAS_WARNING(warning) + +#endif /* !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < X) */ + + +// This file contains all internal macro definitions (except those affecting ABI) +// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them + +// #include + + +// exclude unsupported compilers +#if !defined(JSON_SKIP_UNSUPPORTED_COMPILER_CHECK) + #if defined(__clang__) + #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400 + #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" + #endif + #elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER)) + #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40800 + #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" + #endif + #endif +#endif + +// C++ language standard detection +// if the user manually specified the used c++ version this is skipped +#if !defined(JSON_HAS_CPP_20) && !defined(JSON_HAS_CPP_17) && !defined(JSON_HAS_CPP_14) && !defined(JSON_HAS_CPP_11) + #if (defined(__cplusplus) && __cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L) + #define JSON_HAS_CPP_20 + #define JSON_HAS_CPP_17 + #define JSON_HAS_CPP_14 + #elif (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 + #define JSON_HAS_CPP_17 + #define JSON_HAS_CPP_14 + #elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) + #define JSON_HAS_CPP_14 + #endif + // the cpp 11 flag is always specified because it is the minimal required version + #define JSON_HAS_CPP_11 +#endif + +#ifdef __has_include + #if __has_include() + #include + #endif +#endif + +#if !defined(JSON_HAS_FILESYSTEM) && !defined(JSON_HAS_EXPERIMENTAL_FILESYSTEM) + #ifdef JSON_HAS_CPP_17 + #if defined(__cpp_lib_filesystem) + #define JSON_HAS_FILESYSTEM 1 + #elif defined(__cpp_lib_experimental_filesystem) + #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1 + #elif !defined(__has_include) + #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1 + #elif __has_include() + #define JSON_HAS_FILESYSTEM 1 + #elif __has_include() + #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1 + #endif + + // std::filesystem does not work on MinGW GCC 8: https://sourceforge.net/p/mingw-w64/bugs/737/ + #if defined(__MINGW32__) && defined(__GNUC__) && __GNUC__ == 8 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before GCC 8: https://en.cppreference.com/w/cpp/compiler_support + #if defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 8 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before Clang 7: https://en.cppreference.com/w/cpp/compiler_support + #if defined(__clang_major__) && __clang_major__ < 7 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before MSVC 19.14: https://en.cppreference.com/w/cpp/compiler_support + #if defined(_MSC_VER) && _MSC_VER < 1914 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before iOS 13 + #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED < 130000 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + + // no filesystem support before macOS Catalina + #if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101500 + #undef JSON_HAS_FILESYSTEM + #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #endif + #endif +#endif + +#ifndef JSON_HAS_EXPERIMENTAL_FILESYSTEM + #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 0 +#endif + +#ifndef JSON_HAS_FILESYSTEM + #define JSON_HAS_FILESYSTEM 0 +#endif + +#ifndef JSON_HAS_THREE_WAY_COMPARISON + #if defined(__cpp_impl_three_way_comparison) && __cpp_impl_three_way_comparison >= 201907L \ + && defined(__cpp_lib_three_way_comparison) && __cpp_lib_three_way_comparison >= 201907L + #define JSON_HAS_THREE_WAY_COMPARISON 1 + #else + #define JSON_HAS_THREE_WAY_COMPARISON 0 + #endif +#endif + +#ifndef JSON_HAS_RANGES + // ranges header shipping in GCC 11.1.0 (released 2021-04-27) has syntax error + #if defined(__GLIBCXX__) && __GLIBCXX__ == 20210427 + #define JSON_HAS_RANGES 0 + #elif defined(__cpp_lib_ranges) + #define JSON_HAS_RANGES 1 + #else + #define JSON_HAS_RANGES 0 + #endif +#endif + +#ifndef JSON_HAS_STATIC_RTTI + #if !defined(_HAS_STATIC_RTTI) || _HAS_STATIC_RTTI != 0 + #define JSON_HAS_STATIC_RTTI 1 + #else + #define JSON_HAS_STATIC_RTTI 0 + #endif +#endif + +#ifdef JSON_HAS_CPP_17 + #define JSON_INLINE_VARIABLE inline +#else + #define JSON_INLINE_VARIABLE +#endif + +#if JSON_HEDLEY_HAS_ATTRIBUTE(no_unique_address) + #define JSON_NO_UNIQUE_ADDRESS [[no_unique_address]] +#else + #define JSON_NO_UNIQUE_ADDRESS +#endif + +// disable documentation warnings on clang +#if defined(__clang__) + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wdocumentation" + #pragma clang diagnostic ignored "-Wdocumentation-unknown-command" +#endif + +// allow disabling exceptions +#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION) + #define JSON_THROW(exception) throw exception + #define JSON_TRY try + #define JSON_CATCH(exception) catch(exception) + #define JSON_INTERNAL_CATCH(exception) catch(exception) +#else + #include + #define JSON_THROW(exception) std::abort() + #define JSON_TRY if(true) + #define JSON_CATCH(exception) if(false) + #define JSON_INTERNAL_CATCH(exception) if(false) +#endif + +// override exception macros +#if defined(JSON_THROW_USER) + #undef JSON_THROW + #define JSON_THROW JSON_THROW_USER +#endif +#if defined(JSON_TRY_USER) + #undef JSON_TRY + #define JSON_TRY JSON_TRY_USER +#endif +#if defined(JSON_CATCH_USER) + #undef JSON_CATCH + #define JSON_CATCH JSON_CATCH_USER + #undef JSON_INTERNAL_CATCH + #define JSON_INTERNAL_CATCH JSON_CATCH_USER +#endif +#if defined(JSON_INTERNAL_CATCH_USER) + #undef JSON_INTERNAL_CATCH + #define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER +#endif + +// allow overriding assert +#if !defined(JSON_ASSERT) + #include // assert + #define JSON_ASSERT(x) assert(x) +#endif + +// allow to access some private functions (needed by the test suite) +#if defined(JSON_TESTS_PRIVATE) + #define JSON_PRIVATE_UNLESS_TESTED public +#else + #define JSON_PRIVATE_UNLESS_TESTED private +#endif + +/*! +@brief macro to briefly define a mapping between an enum and JSON +@def NLOHMANN_JSON_SERIALIZE_ENUM +@since version 3.4.0 +*/ +#define NLOHMANN_JSON_SERIALIZE_ENUM(ENUM_TYPE, ...) \ + template \ + inline void to_json(BasicJsonType& j, const ENUM_TYPE& e) \ + { \ + static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ + static const std::pair m[] = __VA_ARGS__; \ + auto it = std::find_if(std::begin(m), std::end(m), \ + [e](const std::pair& ej_pair) -> bool \ + { \ + return ej_pair.first == e; \ + }); \ + j = ((it != std::end(m)) ? it : std::begin(m))->second; \ + } \ + template \ + inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \ + { \ + static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ + static const std::pair m[] = __VA_ARGS__; \ + auto it = std::find_if(std::begin(m), std::end(m), \ + [&j](const std::pair& ej_pair) -> bool \ + { \ + return ej_pair.second == j; \ + }); \ + e = ((it != std::end(m)) ? it : std::begin(m))->first; \ + } + +// Ugly macros to avoid uglier copy-paste when specializing basic_json. They +// may be removed in the future once the class is split. + +#define NLOHMANN_BASIC_JSON_TPL_DECLARATION \ + template class ObjectType, \ + template class ArrayType, \ + class StringType, class BooleanType, class NumberIntegerType, \ + class NumberUnsignedType, class NumberFloatType, \ + template class AllocatorType, \ + template class JSONSerializer, \ + class BinaryType, \ + class CustomBaseClass> + +#define NLOHMANN_BASIC_JSON_TPL \ + basic_json + +// Macros to simplify conversion from/to types + +#define NLOHMANN_JSON_EXPAND( x ) x +#define NLOHMANN_JSON_GET_MACRO(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, NAME,...) NAME +#define NLOHMANN_JSON_PASTE(...) NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_GET_MACRO(__VA_ARGS__, \ + NLOHMANN_JSON_PASTE64, \ + NLOHMANN_JSON_PASTE63, \ + NLOHMANN_JSON_PASTE62, \ + NLOHMANN_JSON_PASTE61, \ + NLOHMANN_JSON_PASTE60, \ + NLOHMANN_JSON_PASTE59, \ + NLOHMANN_JSON_PASTE58, \ + NLOHMANN_JSON_PASTE57, \ + NLOHMANN_JSON_PASTE56, \ + NLOHMANN_JSON_PASTE55, \ + NLOHMANN_JSON_PASTE54, \ + NLOHMANN_JSON_PASTE53, \ + NLOHMANN_JSON_PASTE52, \ + NLOHMANN_JSON_PASTE51, \ + NLOHMANN_JSON_PASTE50, \ + NLOHMANN_JSON_PASTE49, \ + NLOHMANN_JSON_PASTE48, \ + NLOHMANN_JSON_PASTE47, \ + NLOHMANN_JSON_PASTE46, \ + NLOHMANN_JSON_PASTE45, \ + NLOHMANN_JSON_PASTE44, \ + NLOHMANN_JSON_PASTE43, \ + NLOHMANN_JSON_PASTE42, \ + NLOHMANN_JSON_PASTE41, \ + NLOHMANN_JSON_PASTE40, \ + NLOHMANN_JSON_PASTE39, \ + NLOHMANN_JSON_PASTE38, \ + NLOHMANN_JSON_PASTE37, \ + NLOHMANN_JSON_PASTE36, \ + NLOHMANN_JSON_PASTE35, \ + NLOHMANN_JSON_PASTE34, \ + NLOHMANN_JSON_PASTE33, \ + NLOHMANN_JSON_PASTE32, \ + NLOHMANN_JSON_PASTE31, \ + NLOHMANN_JSON_PASTE30, \ + NLOHMANN_JSON_PASTE29, \ + NLOHMANN_JSON_PASTE28, \ + NLOHMANN_JSON_PASTE27, \ + NLOHMANN_JSON_PASTE26, \ + NLOHMANN_JSON_PASTE25, \ + NLOHMANN_JSON_PASTE24, \ + NLOHMANN_JSON_PASTE23, \ + NLOHMANN_JSON_PASTE22, \ + NLOHMANN_JSON_PASTE21, \ + NLOHMANN_JSON_PASTE20, \ + NLOHMANN_JSON_PASTE19, \ + NLOHMANN_JSON_PASTE18, \ + NLOHMANN_JSON_PASTE17, \ + NLOHMANN_JSON_PASTE16, \ + NLOHMANN_JSON_PASTE15, \ + NLOHMANN_JSON_PASTE14, \ + NLOHMANN_JSON_PASTE13, \ + NLOHMANN_JSON_PASTE12, \ + NLOHMANN_JSON_PASTE11, \ + NLOHMANN_JSON_PASTE10, \ + NLOHMANN_JSON_PASTE9, \ + NLOHMANN_JSON_PASTE8, \ + NLOHMANN_JSON_PASTE7, \ + NLOHMANN_JSON_PASTE6, \ + NLOHMANN_JSON_PASTE5, \ + NLOHMANN_JSON_PASTE4, \ + NLOHMANN_JSON_PASTE3, \ + NLOHMANN_JSON_PASTE2, \ + NLOHMANN_JSON_PASTE1)(__VA_ARGS__)) +#define NLOHMANN_JSON_PASTE2(func, v1) func(v1) +#define NLOHMANN_JSON_PASTE3(func, v1, v2) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE2(func, v2) +#define NLOHMANN_JSON_PASTE4(func, v1, v2, v3) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE3(func, v2, v3) +#define NLOHMANN_JSON_PASTE5(func, v1, v2, v3, v4) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE4(func, v2, v3, v4) +#define NLOHMANN_JSON_PASTE6(func, v1, v2, v3, v4, v5) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE5(func, v2, v3, v4, v5) +#define NLOHMANN_JSON_PASTE7(func, v1, v2, v3, v4, v5, v6) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE6(func, v2, v3, v4, v5, v6) +#define NLOHMANN_JSON_PASTE8(func, v1, v2, v3, v4, v5, v6, v7) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE7(func, v2, v3, v4, v5, v6, v7) +#define NLOHMANN_JSON_PASTE9(func, v1, v2, v3, v4, v5, v6, v7, v8) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE8(func, v2, v3, v4, v5, v6, v7, v8) +#define NLOHMANN_JSON_PASTE10(func, v1, v2, v3, v4, v5, v6, v7, v8, v9) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE9(func, v2, v3, v4, v5, v6, v7, v8, v9) +#define NLOHMANN_JSON_PASTE11(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE10(func, v2, v3, v4, v5, v6, v7, v8, v9, v10) +#define NLOHMANN_JSON_PASTE12(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE11(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) +#define NLOHMANN_JSON_PASTE13(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE12(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) +#define NLOHMANN_JSON_PASTE14(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE13(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) +#define NLOHMANN_JSON_PASTE15(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE14(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) +#define NLOHMANN_JSON_PASTE16(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE15(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) +#define NLOHMANN_JSON_PASTE17(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE16(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) +#define NLOHMANN_JSON_PASTE18(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE17(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17) +#define NLOHMANN_JSON_PASTE19(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE18(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18) +#define NLOHMANN_JSON_PASTE20(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE19(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19) +#define NLOHMANN_JSON_PASTE21(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE20(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20) +#define NLOHMANN_JSON_PASTE22(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE21(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21) +#define NLOHMANN_JSON_PASTE23(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE22(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22) +#define NLOHMANN_JSON_PASTE24(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE23(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23) +#define NLOHMANN_JSON_PASTE25(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE24(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24) +#define NLOHMANN_JSON_PASTE26(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE25(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25) +#define NLOHMANN_JSON_PASTE27(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE26(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26) +#define NLOHMANN_JSON_PASTE28(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE27(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27) +#define NLOHMANN_JSON_PASTE29(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE28(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28) +#define NLOHMANN_JSON_PASTE30(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE29(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29) +#define NLOHMANN_JSON_PASTE31(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE30(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30) +#define NLOHMANN_JSON_PASTE32(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE31(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31) +#define NLOHMANN_JSON_PASTE33(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE32(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32) +#define NLOHMANN_JSON_PASTE34(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE33(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33) +#define NLOHMANN_JSON_PASTE35(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE34(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34) +#define NLOHMANN_JSON_PASTE36(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE35(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35) +#define NLOHMANN_JSON_PASTE37(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE36(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36) +#define NLOHMANN_JSON_PASTE38(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE37(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37) +#define NLOHMANN_JSON_PASTE39(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE38(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38) +#define NLOHMANN_JSON_PASTE40(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE39(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39) +#define NLOHMANN_JSON_PASTE41(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE40(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40) +#define NLOHMANN_JSON_PASTE42(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE41(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41) +#define NLOHMANN_JSON_PASTE43(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE42(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42) +#define NLOHMANN_JSON_PASTE44(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE43(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43) +#define NLOHMANN_JSON_PASTE45(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE44(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44) +#define NLOHMANN_JSON_PASTE46(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE45(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45) +#define NLOHMANN_JSON_PASTE47(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE46(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46) +#define NLOHMANN_JSON_PASTE48(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE47(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47) +#define NLOHMANN_JSON_PASTE49(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE48(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48) +#define NLOHMANN_JSON_PASTE50(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE49(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49) +#define NLOHMANN_JSON_PASTE51(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE50(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50) +#define NLOHMANN_JSON_PASTE52(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE51(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51) +#define NLOHMANN_JSON_PASTE53(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE52(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52) +#define NLOHMANN_JSON_PASTE54(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE53(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53) +#define NLOHMANN_JSON_PASTE55(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE54(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54) +#define NLOHMANN_JSON_PASTE56(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE55(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55) +#define NLOHMANN_JSON_PASTE57(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE56(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56) +#define NLOHMANN_JSON_PASTE58(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE57(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57) +#define NLOHMANN_JSON_PASTE59(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE58(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58) +#define NLOHMANN_JSON_PASTE60(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE59(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59) +#define NLOHMANN_JSON_PASTE61(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE60(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60) +#define NLOHMANN_JSON_PASTE62(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE61(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61) +#define NLOHMANN_JSON_PASTE63(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE62(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62) +#define NLOHMANN_JSON_PASTE64(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE63(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63) + +#define NLOHMANN_JSON_TO(v1) nlohmann_json_j[#v1] = nlohmann_json_t.v1; +#define NLOHMANN_JSON_FROM(v1) nlohmann_json_j.at(#v1).get_to(nlohmann_json_t.v1); +#define NLOHMANN_JSON_FROM_WITH_DEFAULT(v1) nlohmann_json_t.v1 = nlohmann_json_j.value(#v1, nlohmann_json_default_obj.v1); + +/*! +@brief macro +@def NLOHMANN_DEFINE_TYPE_INTRUSIVE +@since version 3.9.0 +*/ +#define NLOHMANN_DEFINE_TYPE_INTRUSIVE(Type, ...) \ + friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } + +#define NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(Type, ...) \ + friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) } + +#define NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE(Type, ...) \ + friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } + +/*! +@brief macro +@def NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE +@since version 3.9.0 +*/ +#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Type, ...) \ + inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } + +#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE(Type, ...) \ + inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } + +#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(Type, ...) \ + inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ + inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) } + +// inspired from https://stackoverflow.com/a/26745591 +// allows to call any std function as if (e.g. with begin): +// using std::begin; begin(x); +// +// it allows using the detected idiom to retrieve the return type +// of such an expression +#define NLOHMANN_CAN_CALL_STD_FUNC_IMPL(std_name) \ + namespace detail { \ + using std::std_name; \ + \ + template \ + using result_of_##std_name = decltype(std_name(std::declval()...)); \ + } \ + \ + namespace detail2 { \ + struct std_name##_tag \ + { \ + }; \ + \ + template \ + std_name##_tag std_name(T&&...); \ + \ + template \ + using result_of_##std_name = decltype(std_name(std::declval()...)); \ + \ + template \ + struct would_call_std_##std_name \ + { \ + static constexpr auto const value = ::nlohmann::detail:: \ + is_detected_exact::value; \ + }; \ + } /* namespace detail2 */ \ + \ + template \ + struct would_call_std_##std_name : detail2::would_call_std_##std_name \ + { \ + } + +#ifndef JSON_USE_IMPLICIT_CONVERSIONS + #define JSON_USE_IMPLICIT_CONVERSIONS 1 +#endif + +#if JSON_USE_IMPLICIT_CONVERSIONS + #define JSON_EXPLICIT +#else + #define JSON_EXPLICIT explicit +#endif + +#ifndef JSON_DISABLE_ENUM_SERIALIZATION + #define JSON_DISABLE_ENUM_SERIALIZATION 0 +#endif + +#ifndef JSON_USE_GLOBAL_UDLS + #define JSON_USE_GLOBAL_UDLS 1 +#endif + +#if JSON_HAS_THREE_WAY_COMPARISON + #include // partial_ordering +#endif + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +/////////////////////////// +// JSON type enumeration // +/////////////////////////// + +/*! +@brief the JSON type enumeration + +This enumeration collects the different JSON types. It is internally used to +distinguish the stored values, and the functions @ref basic_json::is_null(), +@ref basic_json::is_object(), @ref basic_json::is_array(), +@ref basic_json::is_string(), @ref basic_json::is_boolean(), +@ref basic_json::is_number() (with @ref basic_json::is_number_integer(), +@ref basic_json::is_number_unsigned(), and @ref basic_json::is_number_float()), +@ref basic_json::is_discarded(), @ref basic_json::is_primitive(), and +@ref basic_json::is_structured() rely on it. + +@note There are three enumeration entries (number_integer, number_unsigned, and +number_float), because the library distinguishes these three types for numbers: +@ref basic_json::number_unsigned_t is used for unsigned integers, +@ref basic_json::number_integer_t is used for signed integers, and +@ref basic_json::number_float_t is used for floating-point numbers or to +approximate integers which do not fit in the limits of their respective type. + +@sa see @ref basic_json::basic_json(const value_t value_type) -- create a JSON +value with the default value for a given type + +@since version 1.0.0 +*/ +enum class value_t : std::uint8_t +{ + null, ///< null value + object, ///< object (unordered set of name/value pairs) + array, ///< array (ordered collection of values) + string, ///< string value + boolean, ///< boolean value + number_integer, ///< number value (signed integer) + number_unsigned, ///< number value (unsigned integer) + number_float, ///< number value (floating-point) + binary, ///< binary array (ordered collection of bytes) + discarded ///< discarded by the parser callback function +}; + +/*! +@brief comparison operator for JSON types + +Returns an ordering that is similar to Python: +- order: null < boolean < number < object < array < string < binary +- furthermore, each type is not smaller than itself +- discarded values are not comparable +- binary is represented as a b"" string in python and directly comparable to a + string; however, making a binary array directly comparable with a string would + be surprising behavior in a JSON file. + +@since version 1.0.0 +*/ +#if JSON_HAS_THREE_WAY_COMPARISON + inline std::partial_ordering operator<=>(const value_t lhs, const value_t rhs) noexcept // *NOPAD* +#else + inline bool operator<(const value_t lhs, const value_t rhs) noexcept +#endif +{ + static constexpr std::array order = {{ + 0 /* null */, 3 /* object */, 4 /* array */, 5 /* string */, + 1 /* boolean */, 2 /* integer */, 2 /* unsigned */, 2 /* float */, + 6 /* binary */ + } + }; + + const auto l_index = static_cast(lhs); + const auto r_index = static_cast(rhs); +#if JSON_HAS_THREE_WAY_COMPARISON + if (l_index < order.size() && r_index < order.size()) + { + return order[l_index] <=> order[r_index]; // *NOPAD* + } + return std::partial_ordering::unordered; +#else + return l_index < order.size() && r_index < order.size() && order[l_index] < order[r_index]; +#endif +} + +// GCC selects the built-in operator< over an operator rewritten from +// a user-defined spaceship operator +// Clang, MSVC, and ICC select the rewritten candidate +// (see GCC bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105200) +#if JSON_HAS_THREE_WAY_COMPARISON && defined(__GNUC__) +inline bool operator<(const value_t lhs, const value_t rhs) noexcept +{ + return std::is_lt(lhs <=> rhs); // *NOPAD* +} +#endif + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +/*! +@brief replace all occurrences of a substring by another string + +@param[in,out] s the string to manipulate; changed so that all + occurrences of @a f are replaced with @a t +@param[in] f the substring to replace with @a t +@param[in] t the string to replace @a f + +@pre The search string @a f must not be empty. **This precondition is +enforced with an assertion.** + +@since version 2.0.0 +*/ +template +inline void replace_substring(StringType& s, const StringType& f, + const StringType& t) +{ + JSON_ASSERT(!f.empty()); + for (auto pos = s.find(f); // find first occurrence of f + pos != StringType::npos; // make sure f was found + s.replace(pos, f.size(), t), // replace with t, and + pos = s.find(f, pos + t.size())) // find next occurrence of f + {} +} + +/*! + * @brief string escaping as described in RFC 6901 (Sect. 4) + * @param[in] s string to escape + * @return escaped string + * + * Note the order of escaping "~" to "~0" and "/" to "~1" is important. + */ +template +inline StringType escape(StringType s) +{ + replace_substring(s, StringType{"~"}, StringType{"~0"}); + replace_substring(s, StringType{"/"}, StringType{"~1"}); + return s; +} + +/*! + * @brief string unescaping as described in RFC 6901 (Sect. 4) + * @param[in] s string to unescape + * @return unescaped string + * + * Note the order of escaping "~1" to "/" and "~0" to "~" is important. + */ +template +static void unescape(StringType& s) +{ + replace_substring(s, StringType{"~1"}, StringType{"/"}); + replace_substring(s, StringType{"~0"}, StringType{"~"}); +} + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // size_t + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +/// struct to capture the start position of the current token +struct position_t +{ + /// the total number of characters read + std::size_t chars_read_total = 0; + /// the number of characters read in the current line + std::size_t chars_read_current_line = 0; + /// the number of lines read + std::size_t lines_read = 0; + + /// conversion to size_t to preserve SAX interface + constexpr operator size_t() const + { + return chars_read_total; + } +}; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + +// #include + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-FileCopyrightText: 2018 The Abseil Authors +// SPDX-License-Identifier: MIT + + + +#include // array +#include // size_t +#include // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type +#include // index_sequence, make_index_sequence, index_sequence_for + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +template +using uncvref_t = typename std::remove_cv::type>::type; + +#ifdef JSON_HAS_CPP_14 + +// the following utilities are natively available in C++14 +using std::enable_if_t; +using std::index_sequence; +using std::make_index_sequence; +using std::index_sequence_for; + +#else + +// alias templates to reduce boilerplate +template +using enable_if_t = typename std::enable_if::type; + +// The following code is taken from https://github.com/abseil/abseil-cpp/blob/10cb35e459f5ecca5b2ff107635da0bfa41011b4/absl/utility/utility.h +// which is part of Google Abseil (https://github.com/abseil/abseil-cpp), licensed under the Apache License 2.0. + +//// START OF CODE FROM GOOGLE ABSEIL + +// integer_sequence +// +// Class template representing a compile-time integer sequence. An instantiation +// of `integer_sequence` has a sequence of integers encoded in its +// type through its template arguments (which is a common need when +// working with C++11 variadic templates). `absl::integer_sequence` is designed +// to be a drop-in replacement for C++14's `std::integer_sequence`. +// +// Example: +// +// template< class T, T... Ints > +// void user_function(integer_sequence); +// +// int main() +// { +// // user_function's `T` will be deduced to `int` and `Ints...` +// // will be deduced to `0, 1, 2, 3, 4`. +// user_function(make_integer_sequence()); +// } +template +struct integer_sequence +{ + using value_type = T; + static constexpr std::size_t size() noexcept + { + return sizeof...(Ints); + } +}; + +// index_sequence +// +// A helper template for an `integer_sequence` of `size_t`, +// `absl::index_sequence` is designed to be a drop-in replacement for C++14's +// `std::index_sequence`. +template +using index_sequence = integer_sequence; + +namespace utility_internal +{ + +template +struct Extend; + +// Note that SeqSize == sizeof...(Ints). It's passed explicitly for efficiency. +template +struct Extend, SeqSize, 0> +{ + using type = integer_sequence < T, Ints..., (Ints + SeqSize)... >; +}; + +template +struct Extend, SeqSize, 1> +{ + using type = integer_sequence < T, Ints..., (Ints + SeqSize)..., 2 * SeqSize >; +}; + +// Recursion helper for 'make_integer_sequence'. +// 'Gen::type' is an alias for 'integer_sequence'. +template +struct Gen +{ + using type = + typename Extend < typename Gen < T, N / 2 >::type, N / 2, N % 2 >::type; +}; + +template +struct Gen +{ + using type = integer_sequence; +}; + +} // namespace utility_internal + +// Compile-time sequences of integers + +// make_integer_sequence +// +// This template alias is equivalent to +// `integer_sequence`, and is designed to be a drop-in +// replacement for C++14's `std::make_integer_sequence`. +template +using make_integer_sequence = typename utility_internal::Gen::type; + +// make_index_sequence +// +// This template alias is equivalent to `index_sequence<0, 1, ..., N-1>`, +// and is designed to be a drop-in replacement for C++14's +// `std::make_index_sequence`. +template +using make_index_sequence = make_integer_sequence; + +// index_sequence_for +// +// Converts a typename pack into an index sequence of the same length, and +// is designed to be a drop-in replacement for C++14's +// `std::index_sequence_for()` +template +using index_sequence_for = make_index_sequence; + +//// END OF CODE FROM GOOGLE ABSEIL + +#endif + +// dispatch utility (taken from ranges-v3) +template struct priority_tag : priority_tag < N - 1 > {}; +template<> struct priority_tag<0> {}; + +// taken from ranges-v3 +template +struct static_const +{ + static JSON_INLINE_VARIABLE constexpr T value{}; +}; + +#ifndef JSON_HAS_CPP_17 + template + constexpr T static_const::value; +#endif + +template +inline constexpr std::array make_array(Args&& ... args) +{ + return std::array {{static_cast(std::forward(args))...}}; +} + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // numeric_limits +#include // false_type, is_constructible, is_integral, is_same, true_type +#include // declval +#include // tuple +#include // char_traits + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +#include // random_access_iterator_tag + +// #include + +// #include + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN +namespace detail +{ + +template +struct iterator_types {}; + +template +struct iterator_types < + It, + void_t> +{ + using difference_type = typename It::difference_type; + using value_type = typename It::value_type; + using pointer = typename It::pointer; + using reference = typename It::reference; + using iterator_category = typename It::iterator_category; +}; + +// This is required as some compilers implement std::iterator_traits in a way that +// doesn't work with SFINAE. See https://github.com/nlohmann/json/issues/1341. +template +struct iterator_traits +{ +}; + +template +struct iterator_traits < T, enable_if_t < !std::is_pointer::value >> + : iterator_types +{ +}; + +template +struct iterator_traits::value>> +{ + using iterator_category = std::random_access_iterator_tag; + using value_type = T; + using difference_type = ptrdiff_t; + using pointer = T*; + using reference = T&; +}; + +} // namespace detail +NLOHMANN_JSON_NAMESPACE_END + +// #include + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN + +NLOHMANN_CAN_CALL_STD_FUNC_IMPL(begin); + +NLOHMANN_JSON_NAMESPACE_END + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + + + +// #include + + +NLOHMANN_JSON_NAMESPACE_BEGIN + +NLOHMANN_CAN_CALL_STD_FUNC_IMPL(end); + +NLOHMANN_JSON_NAMESPACE_END + +// #include + +// #include + +// #include +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ +// | | |__ | | | | | | version 3.11.3 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann +// SPDX-License-Identifier: MIT + +#ifndef INCLUDE_NLOHMANN_JSON_FWD_HPP_ + #define INCLUDE_NLOHMANN_JSON_FWD_HPP_ + + #include // int64_t, uint64_t + #include // map + #include // allocator + #include // string + #include // vector + + // #include + + + /*! + @brief namespace for Niels Lohmann + @see https://github.com/nlohmann + @since version 1.0.0 + */ + NLOHMANN_JSON_NAMESPACE_BEGIN + + /*! + @brief default JSONSerializer template argument + + This serializer ignores the template arguments and uses ADL + ([argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl)) + for serialization. + */ + template + struct adl_serializer; + + /// a class to store JSON values + /// @sa https://json.nlohmann.me/api/basic_json/ + template class ObjectType = + std::map, + template class ArrayType = std::vector, + class StringType = std::string, class BooleanType = bool, + class NumberIntegerType = std::int64_t, + class NumberUnsignedType = std::uint64_t, + class NumberFloatType = double, + template class AllocatorType = std::allocator, + template class JSONSerializer = + adl_serializer, + class BinaryType = std::vector, // cppcheck-suppress syntaxError + class CustomBaseClass = void> + class basic_json; + + /// @brief JSON Pointer defines a string syntax for identifying a specific value within a JSON document + /// @sa https://json.nlohmann.me/api/json_pointer/ + template + class json_pointer; + + /*! + @brief default specialization + @sa https://json.nlohmann.me/api/json/ + */ + using json = basic_json<>; + + /// @brief a minimal map-like container that preserves insertion order + /// @sa https://json.nlohmann.me/api/ordered_map/ + template + struct ordered_map; + + /// @brief specialization that maintains the insertion order of object keys + /// @sa https://json.nlohmann.me/api/ordered_json/ + using ordered_json = basic_json; + + NLOHMANN_JSON_NAMESPACE_END + +#endif // INCLUDE_NLOHMANN_JSON_FWD_HPP_ + + +NLOHMANN_JSON_NAMESPACE_BEGIN +/*! +@brief detail namespace with internal helper functions + +This namespace collects functions that should not be exposed, +implementations of some @ref basic_json methods, and meta-programming helpers. + +@since version 2.1.0 +*/ +namespace detail +{ + +///////////// +// helpers // +///////////// + +// Note to maintainers: +// +// Every trait in this file expects a non CV-qualified type. +// The only exceptions are in the 'aliases for detected' section +// (i.e. those of the form: decltype(T::member_function(std::declval()))) +// +// In this case, T has to be properly CV-qualified to constraint the function arguments +// (e.g. to_json(BasicJsonType&, const T&)) + +template struct is_basic_json : std::false_type {}; + +NLOHMANN_BASIC_JSON_TPL_DECLARATION +struct is_basic_json : std::true_type {}; + +// used by exceptions create() member functions +// true_type for pointer to possibly cv-qualified basic_json or std::nullptr_t +// false_type otherwise +template +struct is_basic_json_context : + std::integral_constant < bool, + is_basic_json::type>::type>::value + || std::is_same::value > +{}; + +////////////////////// +// json_ref helpers // +////////////////////// + +template +class json_ref; + +template +struct is_json_ref : std::false_type {}; + +template +struct is_json_ref> : std::true_type {}; + +////////////////////////// +// aliases for detected // +////////////////////////// + +template +using mapped_type_t = typename T::mapped_type; + +template +using key_type_t = typename T::key_type; + +template +using value_type_t = typename T::value_type; + +template +using difference_type_t = typename T::difference_type; + +template +using pointer_t = typename T::pointer; + +template +using reference_t = typename T::reference; + +template +using iterator_category_t = typename T::iterator_category; + +template +using to_json_function = decltype(T::to_json(std::declval()...)); + +template +using from_json_function = decltype(T::from_json(std::declval()...)); + +template +using get_template_function = decltype(std::declval().template get()); + +// trait checking if JSONSerializer::from_json(json const&, udt&) exists +template +struct has_from_json : std::false_type {}; + +// trait checking if j.get is valid +// use this trait instead of std::is_constructible or std::is_convertible, +// both rely on, or make use of implicit conversions, and thus fail when T +// has several constructors/operator= (see https://github.com/nlohmann/json/issues/958) +template +struct is_getable +{ + static constexpr bool value = is_detected::value; +}; + +template +struct has_from_json < BasicJsonType, T, enable_if_t < !is_basic_json::value >> +{ + using serializer = typename BasicJsonType::template json_serializer; + + static constexpr bool value = + is_detected_exact::value; +}; + +// This trait checks if JSONSerializer::from_json(json const&) exists +// this overload is used for non-default-constructible user-defined-types +template +struct has_non_default_from_json : std::false_type {}; + +template +struct has_non_default_from_json < BasicJsonType, T, enable_if_t < !is_basic_json::value >> +{ + using serializer = typename BasicJsonType::template json_serializer; + + static constexpr bool value = + is_detected_exact::value; +}; + +// This trait checks if BasicJsonType::json_serializer::to_json exists +// Do not evaluate the trait when T is a basic_json type, to avoid template instantiation infinite recursion. +template +struct has_to_json : std::false_type {}; + +template +struct has_to_json < BasicJsonType, T, enable_if_t < !is_basic_json::value >> +{ + using serializer = typename BasicJsonType::template json_serializer; + + static constexpr bool value = + is_detected_exact::value; +}; + +template +using detect_key_compare = typename T::key_compare; + +template +struct has_key_compare : std::integral_constant::value> {}; + +// obtains the actual object key comparator +template +struct actual_object_comparator +{ + using object_t = typename BasicJsonType::object_t; + using object_comparator_t = typename BasicJsonType::default_object_comparator_t; + using type = typename std::conditional < has_key_compare::value, + typename object_t::key_compare, object_comparator_t>::type; +}; + +template +using actual_object_comparator_t = typename actual_object_comparator::type; + +///////////////// +// char_traits // +///////////////// + +// Primary template of char_traits calls std char_traits +template +struct char_traits : std::char_traits +{}; + +// Explicitly define char traits for unsigned char since it is not standard +template<> +struct char_traits : std::char_traits +{ + using char_type = unsigned char; + using int_type = uint64_t; + + // Redefine to_int_type function + static int_type to_int_type(char_type c) noexcept + { + return static_cast(c); + } + + static char_type to_char_type(int_type i) noexcept + { + return static_cast(i); + } + + static constexpr int_type eof() noexcept + { + return static_cast(EOF); + } +}; + +// Explicitly define char traits for signed char since it is not standard +template<> +struct char_traits : std::char_traits +{ + using char_type = signed char; + using int_type = uint64_t; + + // Redefine to_int_type function + static int_type to_int_type(char_type c) noexcept + { + return static_cast(c); + } + + static char_type to_char_type(int_type i) noexcept + { + return static_cast(i); + } + + static constexpr int_type eof() noexcept + { + return static_cast(EOF); + } +}; + +/////////////////// +// is_ functions // +/////////////////// + +// https://en.cppreference.com/w/cpp/types/conjunction +template struct conjunction : std::true_type { }; +template struct conjunction : B { }; +template +struct conjunction +: std::conditional(B::value), conjunction, B>::type {}; + +// https://en.cppreference.com/w/cpp/types/negation +template struct negation : std::integral_constant < bool, !B::value > { }; + +// Reimplementation of is_constructible and is_default_constructible, due to them being broken for +// std::pair and std::tuple until LWG 2367 fix (see https://cplusplus.github.io/LWG/lwg-defects.html#2367). +// This causes compile errors in e.g. clang 3.5 or gcc 4.9. +template +struct is_default_constructible : std::is_default_constructible {}; + +template +struct is_default_constructible> + : conjunction, is_default_constructible> {}; + +template +struct is_default_constructible> + : conjunction, is_default_constructible> {}; + +template +struct is_default_constructible> + : conjunction...> {}; + +template +struct is_default_constructible> + : conjunction...> {}; + +template +struct is_constructible : std::is_constructible {}; + +template +struct is_constructible> : is_default_constructible> {}; + +template +struct is_constructible> : is_default_constructible> {}; + +template +struct is_constructible> : is_default_constructible> {}; + +template +struct is_constructible> : is_default_constructible> {}; + +template +struct is_iterator_traits : std::false_type {}; + +template +struct is_iterator_traits> +{ + private: + using traits = iterator_traits; + + public: + static constexpr auto value = + is_detected::value && + is_detected::value && + is_detected::value && + is_detected::value && + is_detected::value; +}; + +template +struct is_range +{ + private: + using t_ref = typename std::add_lvalue_reference::type; + + using iterator = detected_t; + using sentinel = detected_t; + + // to be 100% correct, it should use https://en.cppreference.com/w/cpp/iterator/input_or_output_iterator + // and https://en.cppreference.com/w/cpp/iterator/sentinel_for + // but reimplementing these would be too much work, as a lot of other concepts are used underneath + static constexpr auto is_iterator_begin = + is_iterator_traits>::value; + + public: + static constexpr bool value = !std::is_same::value && !std::is_same::value && is_iterator_begin; +}; + +template +using iterator_t = enable_if_t::value, result_of_begin())>>; + +template +using range_value_t = value_type_t>>; + +// The following implementation of is_complete_type is taken from +// https://blogs.msdn.microsoft.com/vcblog/2015/12/02/partial-support-for-expression-sfinae-in-vs-2015-update-1/ +// and is written by Xiang Fan who agreed to using it in this library. + +template +struct is_complete_type : std::false_type {}; + +template +struct is_complete_type : std::true_type {}; + +template +struct is_compatible_object_type_impl : std::false_type {}; + +template +struct is_compatible_object_type_impl < + BasicJsonType, CompatibleObjectType, + enable_if_t < is_detected::value&& + is_detected::value >> +{ + using object_t = typename BasicJsonType::object_t; + + // macOS's is_constructible does not play well with nonesuch... + static constexpr bool value = + is_constructible::value && + is_constructible::value; +}; + +template +struct is_compatible_object_type + : is_compatible_object_type_impl {}; + +template +struct is_constructible_object_type_impl : std::false_type {}; + +template +struct is_constructible_object_type_impl < + BasicJsonType, ConstructibleObjectType, + enable_if_t < is_detected::value&& + is_detected::value >> +{ + using object_t = typename BasicJsonType::object_t; + + static constexpr bool value = + (is_default_constructible::value && + (std::is_move_assignable::value || + std::is_copy_assignable::value) && + (is_constructible::value && + std::is_same < + typename object_t::mapped_type, + typename ConstructibleObjectType::mapped_type >::value)) || + (has_from_json::value || + has_non_default_from_json < + BasicJsonType, + typename ConstructibleObjectType::mapped_type >::value); +}; + +template +struct is_constructible_object_type + : is_constructible_object_type_impl {}; + +template +struct is_compatible_string_type +{ + static constexpr auto value = + is_constructible::value; +}; + +template +struct is_constructible_string_type +{ + // launder type through decltype() to fix compilation failure on ICPC +#ifdef __INTEL_COMPILER + using laundered_type = decltype(std::declval()); +#else + using laundered_type = ConstructibleStringType; +#endif + + static constexpr auto value = + conjunction < + is_constructible, + is_detected_exact>::value; +}; + +template +struct is_compatible_array_type_impl : std::false_type {}; + +template +struct is_compatible_array_type_impl < + BasicJsonType, CompatibleArrayType, + enable_if_t < + is_detected::value&& + is_iterator_traits>>::value&& +// special case for types like std::filesystem::path whose iterator's value_type are themselves +// c.f. https://github.com/nlohmann/json/pull/3073 + !std::is_same>::value >> +{ + static constexpr bool value = + is_constructible>::value; +}; + +template +struct is_compatible_array_type + : is_compatible_array_type_impl {}; + +template +struct is_constructible_array_type_impl : std::false_type {}; + +template +struct is_constructible_array_type_impl < + BasicJsonType, ConstructibleArrayType, + enable_if_t::value >> + : std::true_type {}; + +template +struct is_constructible_array_type_impl < + BasicJsonType, ConstructibleArrayType, + enable_if_t < !std::is_same::value&& + !is_compatible_string_type::value&& + is_default_constructible::value&& +(std::is_move_assignable::value || + std::is_copy_assignable::value)&& +is_detected::value&& +is_iterator_traits>>::value&& +is_detected::value&& +// special case for types like std::filesystem::path whose iterator's value_type are themselves +// c.f. https://github.com/nlohmann/json/pull/3073 +!std::is_same>::value&& + is_complete_type < + detected_t>::value >> +{ + using value_type = range_value_t; + + static constexpr bool value = + std::is_same::value || + has_from_json::value || + has_non_default_from_json < + BasicJsonType, + value_type >::value; +}; + +template +struct is_constructible_array_type + : is_constructible_array_type_impl {}; + +template +struct is_compatible_integer_type_impl : std::false_type {}; + +template +struct is_compatible_integer_type_impl < + RealIntegerType, CompatibleNumberIntegerType, + enable_if_t < std::is_integral::value&& + std::is_integral::value&& + !std::is_same::value >> +{ + // is there an assert somewhere on overflows? + using RealLimits = std::numeric_limits; + using CompatibleLimits = std::numeric_limits; + + static constexpr auto value = + is_constructible::value && + CompatibleLimits::is_integer && + RealLimits::is_signed == CompatibleLimits::is_signed; +}; + +template +struct is_compatible_integer_type + : is_compatible_integer_type_impl {}; + +template +struct is_compatible_type_impl: std::false_type {}; + +template +struct is_compatible_type_impl < + BasicJsonType, CompatibleType, + enable_if_t::value >> +{ + static constexpr bool value = + has_to_json::value; +}; + +template +struct is_compatible_type + : is_compatible_type_impl {}; + +template +struct is_constructible_tuple : std::false_type {}; + +template +struct is_constructible_tuple> : conjunction...> {}; + +template +struct is_json_iterator_of : std::false_type {}; + +template +struct is_json_iterator_of : std::true_type {}; + +template +struct is_json_iterator_of : std::true_type +{}; + +// checks if a given type T is a template specialization of Primary +template