[
  {
    "path": ".gitignore",
    "content": "# Prerequisites\n*.d\n\n# Compiled Object files\n*.slo\n*.lo\n*.o\n*.obj\n\n# Precompiled Headers\n*.gch\n*.pch\n\n# Compiled Dynamic libraries\n*.so\n*.dylib\n*.dll\n\n# Fortran module files\n*.mod\n*.smod\n\n# Compiled Static libraries\n*.lai\n*.la\n*.a\n*.lib\n\n# Executables\n*.exe\n*.out\n*.app\n\n# CMakeUserfile\n*.user\n*.user.*\n\n"
  },
  {
    "path": "CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.9)\n\nproject(da4qi4)\n\n#set(_DAQI_TARGET_TYPE_ \"DEMO_SERVER\")\n#set(_DAQI_TARGET_TYPE_ \"STATIC_LIB\")\n#set(_DAQI_TARGET_TYPE_ \"SHARED_LIB\")\n\ninclude_directories(.)\ninclude_directories(include/)\ninclude_directories(nlohmann_json/include/)\n\nset(USE_LOCAL_BOOST_VERSION OFF)\n\nif (USE_LOCAL_BOOST_VERSION)\n    SET(BOOST_INCLUDEDIR /usr/local/include)\n    SET(BOOST_LIBRARYDIR /usr/local/lib)\n    find_package(Boost 1.67.0 REQUIRED COMPONENTS filesystem system)\nelse()\n    SET(BOOST_INCLUDEDIR /usr/include)\n    SET(BOOST_LIBRARYDIR /usr/lib)\n    find_package(Boost 1.65.0 REQUIRED COMPONENTS filesystem system)\nendif()\n\nif (Boost_FOUND)\n    message(STATUS ${Boost_VERSION})\n    message(STATUS ${Boost_INCLUDE_DIRS})\n    message(STATUS ${Boost_LIBRARY_DIRS})\n    \n    if ((Boost_VERSION EQUAL 106600) OR (Boost_VERSION GREATER 106600))\n        add_definitions(-D_USE_BOOST_VERSION_GE_1_66_=1)\n    endif()\n\n    add_definitions(-D_USE_BOOST_VERSION_=${Boost_VERSION})        \n    include_directories(${Boost_INCLUDE_DIRS})\nendif()\n\nfind_library(LIBICONV iconv /usr/local/lib)\n\nlink_libraries(${LIBICONV} pthread)\n\nset(JSON_MultipleHeaders ON  CACHE INTERNAL \"\")\nset(JSON_BuildTests OFF CACHE INTERNAL \"\")\nadd_subdirectory(nlohmann_json)\n\nadd_subdirectory(llhttp)\nadd_subdirectory(multipart-parser)\n\naux_source_directory(./src/redis-client DAQI_SRC_FILES)\naux_source_directory(./src/utilities DAQI_SRC_FILES)\naux_source_directory(./src/def DAQI_SRC_FILES)\naux_source_directory(./src/intercepters DAQI_SRC_FILES)\naux_source_directory(./src/client DAQI_SRC_FILES)\naux_source_directory(./src/net-detail DAQI_SRC_FILES)\naux_source_directory(./src/websocket DAQI_SRC_FILES)\naux_source_directory(./src DAQI_SRC_FILES)\n\naux_source_directory(./ DAQI_SRC_FILES)\n\nset(CMAKE_CXX_STANDARD 17)\nset(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -g -Wall\")\n\nlink_libraries(multipart_parser)\nlink_libraries(llhttp)    \nlink_libraries(nlohmann_json)\n\nif(_DAQI_TARGET_TYPE_ STREQUAL \"DEMO_SERVER\")\n    message(STATUS \"~BUILD DAQI AS DEMO SERVER~\")    \n    link_libraries(ssl)\n    link_libraries(crypto)\n    add_definitions(-D_BUILD_DAQI_DEMO_SERVER_=1)\n    add_executable(${PROJECT_NAME} ${DAQI_SRC_FILES})  \n    target_link_libraries (${PROJECT_NAME} ${Boost_LIBRARIES})\nelseif(_DAQI_TARGET_TYPE_ STREQUAL \"STATIC_LIB\")    \n    message(STATUS \"~BUILD DAQI AS STATIC LIB~\")    \n    add_library(${PROJECT_NAME} STATIC ${DAQI_SRC_FILES})  \n    set_target_properties (${PROJECT_NAME} PROPERTIES DEBUG_POSTFIX _d)\n    target_link_libraries (${PROJECT_NAME} ${Boost_LIBRARIES})\nelseif(_DAQI_TARGET_TYPE_ STREQUAL \"SHARED_LIB\")    \n    message(STATUS \"~BUILD DAQI AS SHARED LIB~\")    \n    add_library(${PROJECT_NAME} SHARED ${DAQI_SRC_FILES})        \n    set_target_properties (${PROJECT_NAME} PROPERTIES DEBUG_POSTFIX _d)\nendif()\n\nfunction(echo_all_cmake_variable_values)\n  get_cmake_property(vs VARIABLES)\n  foreach(v ${vs})\n    message(STATUS “${v}=’${${v}}'”)\n  endforeach(v)\n  message(STATUS “”)\nendfunction()\n\n#echo_all_cmake_variable_values()\n"
  },
  {
    "path": "LICENSE",
    "content": "Apache License\nVersion 2.0, January 2004\nhttp://www.apache.org/licenses/\n\nTERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n1. Definitions.\n\n\"License\" shall mean the terms and conditions for use, reproduction, and\ndistribution as defined by Sections 1 through 9 of this document.\n\n\"Licensor\" shall mean the copyright owner or entity authorized by the copyright\nowner that is granting the License.\n\n\"Legal Entity\" shall mean the union of the acting entity and all other entities\nthat control, are controlled by, or are under common control with that entity.\nFor the purposes of this definition, \"control\" means (i) the power, direct or\nindirect, to cause the direction or management of such entity, whether by\ncontract or otherwise, or (ii) ownership of fifty percent (50%) or more of the\noutstanding shares, or (iii) beneficial ownership of such entity.\n\n\"You\" (or \"Your\") shall mean an individual or Legal Entity exercising\npermissions granted by this License.\n\n\"Source\" form shall mean the preferred form for making modifications, including\nbut not limited to software source code, documentation source, and configuration\nfiles.\n\n\"Object\" form shall mean any form resulting from mechanical transformation or\ntranslation of a Source form, including but not limited to compiled object code,\ngenerated documentation, and conversions to other media types.\n\n\"Work\" shall mean the work of authorship, whether in Source or Object form, made\navailable under the License, as indicated by a copyright notice that is included\nin or attached to the work (an example is provided in the Appendix below).\n\n\"Derivative Works\" shall mean any work, whether in Source or Object form, that\nis based on (or derived from) the Work and for which the editorial revisions,\nannotations, elaborations, or other modifications represent, as a whole, an\noriginal work of authorship. For the purposes of this License, Derivative Works\nshall not include works that remain separable from, or merely link (or bind by\nname) to the interfaces of, the Work and Derivative Works thereof.\n\n\"Contribution\" shall mean any work of authorship, including the original version\nof the Work and any modifications or additions to that Work or Derivative Works\nthereof, that is intentionally submitted to Licensor for inclusion in the Work\nby the copyright owner or by an individual or Legal Entity authorized to submit\non behalf of the copyright owner. For the purposes of this definition,\n\"submitted\" means any form of electronic, verbal, or written communication sent\nto the Licensor or its representatives, including but not limited to\ncommunication on electronic mailing lists, source code control systems, and\nissue tracking systems that are managed by, or on behalf of, the Licensor for\nthe purpose of discussing and improving the Work, but excluding communication\nthat is conspicuously marked or otherwise designated in writing by the copyright\nowner as \"Not a Contribution.\"\n\n\"Contributor\" shall mean Licensor and any individual or Legal Entity on behalf\nof whom a Contribution has been received by Licensor and subsequently\nincorporated within the Work.\n\n2. Grant of Copyright License.\n\nSubject to the terms and conditions of this License, each Contributor hereby\ngrants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,\nirrevocable copyright license to reproduce, prepare Derivative Works of,\npublicly display, publicly perform, sublicense, and distribute the Work and such\nDerivative Works in Source or Object form.\n\n3. Grant of Patent License.\n\nSubject to the terms and conditions of this License, each Contributor hereby\ngrants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,\nirrevocable (except as stated in this section) patent license to make, have\nmade, use, offer to sell, sell, import, and otherwise transfer the Work, where\nsuch license applies only to those patent claims licensable by such Contributor\nthat are necessarily infringed by their Contribution(s) alone or by combination\nof their Contribution(s) with the Work to which such Contribution(s) was\nsubmitted. If You institute patent litigation against any entity (including a\ncross-claim or counterclaim in a lawsuit) alleging that the Work or a\nContribution incorporated within the Work constitutes direct or contributory\npatent infringement, then any patent licenses granted to You under this License\nfor that Work shall terminate as of the date such litigation is filed.\n\n4. Redistribution.\n\nYou may reproduce and distribute copies of the Work or Derivative Works thereof\nin any medium, with or without modifications, and in Source or Object form,\nprovided that You meet the following conditions:\n\nYou must give any other recipients of the Work or Derivative Works a copy of\nthis License; and\nYou must cause any modified files to carry prominent notices stating that You\nchanged the files; and\nYou must retain, in the Source form of any Derivative Works that You distribute,\nall copyright, patent, trademark, and attribution notices from the Source form\nof the Work, excluding those notices that do not pertain to any part of the\nDerivative Works; and\nIf the Work includes a \"NOTICE\" text file as part of its distribution, then any\nDerivative Works that You distribute must include a readable copy of the\nattribution notices contained within such NOTICE file, excluding those notices\nthat do not pertain to any part of the Derivative Works, in at least one of the\nfollowing places: within a NOTICE text file distributed as part of the\nDerivative Works; within the Source form or documentation, if provided along\nwith the Derivative Works; or, within a display generated by the Derivative\nWorks, if and wherever such third-party notices normally appear. The contents of\nthe NOTICE file are for informational purposes only and do not modify the\nLicense. You may add Your own attribution notices within Derivative Works that\nYou distribute, alongside or as an addendum to the NOTICE text from the Work,\nprovided that such additional attribution notices cannot be construed as\nmodifying the License.\nYou may add Your own copyright statement to Your modifications and may provide\nadditional or different license terms and conditions for use, reproduction, or\ndistribution of Your modifications, or for any such Derivative Works as a whole,\nprovided Your use, reproduction, and distribution of the Work otherwise complies\nwith the conditions stated in this License.\n\n5. Submission of Contributions.\n\nUnless You explicitly state otherwise, any Contribution intentionally submitted\nfor inclusion in the Work by You to the Licensor shall be under the terms and\nconditions of this License, without any additional terms or conditions.\nNotwithstanding the above, nothing herein shall supersede or modify the terms of\nany separate license agreement you may have executed with Licensor regarding\nsuch Contributions.\n\n6. Trademarks.\n\nThis License does not grant permission to use the trade names, trademarks,\nservice marks, or product names of the Licensor, except as required for\nreasonable and customary use in describing the origin of the Work and\nreproducing the content of the NOTICE file.\n\n7. Disclaimer of Warranty.\n\nUnless required by applicable law or agreed to in writing, Licensor provides the\nWork (and each Contributor provides its Contributions) on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,\nincluding, without limitation, any warranties or conditions of TITLE,\nNON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are\nsolely responsible for determining the appropriateness of using or\nredistributing the Work and assume any risks associated with Your exercise of\npermissions under this License.\n\n8. Limitation of Liability.\n\nIn no event and under no legal theory, whether in tort (including negligence),\ncontract, or otherwise, unless required by applicable law (such as deliberate\nand grossly negligent acts) or agreed to in writing, shall any Contributor be\nliable to You for damages, including any direct, indirect, special, incidental,\nor consequential damages of any character arising as a result of this License or\nout of the use or inability to use the Work (including but not limited to\ndamages for loss of goodwill, work stoppage, computer failure or malfunction, or\nany and all other commercial damages or losses), even if such Contributor has\nbeen advised of the possibility of such damages.\n\n9. Accepting Warranty or Additional Liability.\n\nWhile redistributing the Work or Derivative Works thereof, You may choose to\noffer, and charge a fee for, acceptance of support, warranty, indemnity, or\nother liability obligations and/or rights consistent with this License. However,\nin accepting such obligations, You may act only on Your own behalf and on Your\nsole responsibility, not on behalf of any other Contributor, and only if You\nagree to indemnify, defend, and hold each Contributor harmless for any liability\nincurred by, or claims asserted against, such Contributor by reason of your\naccepting any such warranty or additional liability.\n\nEND OF TERMS AND CONDITIONS\n\nAPPENDIX: How to apply the Apache License to your work\n\nTo apply the Apache License to your work, attach the following boilerplate\nnotice, with the fields enclosed by brackets \"{}\" replaced with your own\nidentifying information. (Don't include the brackets!) The text should be\nenclosed in the appropriate comment syntax for the file format. We also\nrecommend that a file or class name and description of purpose be included on\nthe same \"printed page\" as the copyright notice for easier identification within\nthird-party archives.\n\n   Copyright 2018 zhuangyan-stone\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n     http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License."
  },
  {
    "path": "README.md",
    "content": "- [零、几个原则](#零几个原则)\n  * [0.1 自己的狗粮自己吃](#01-自己的狗粮自己吃)\n  * [0.2 站在巨人的肩膀上](#02-站在巨人的肩膀上)\n  * [0.3 易用优于性能](#03-易用优于性能)\n  * [0.4 简单胜过炫技](#04-简单胜过炫技)\n  * [0.5 紧跟国内生产环境](#05-紧跟国内生产环境)\n- [一、快速了解](#一快速了解)\n  * [1.1 一个空转的Web Server](#11-一个空转的web-server)\n  * [1.2 Hello World!](#12-hello-world)\n    + [1.2.1 针对指定URL的响应](#121-针对指定url的响应)\n    + [1.2.2 返回HTML](#122-返回html)\n  * [1.3 处理请求](#13-处理请求)\n  * [1.4 引入Application](#14-引入application)\n  * [1.5 运行日志](#15-运行日志)\n  * [1.6 HTML模板](#16-html模板)\n  * [1.7 WebSocket](#17-websocket)\n    * [1.7.1 HTTP对比WebSocket](#171-http-对比-websocket)\n    * [1.7.2 大器WebSocket后台实现特性](#172-大器WebSocket后台实现特性)\n    * [1.7.3 使用示例](#173-使用示例)\n  * [1.8 更多](#18-更多)\n    + [1.8.1 框架更多集成功能](#181-框架更多集成功能)\n    + [1.8.2 框架外围可供集成的工具](#182-框架外围可供集成的工具)\n- [二、如何构建](#二如何构建)\n  * [2.1 基于生产环境构建](#21-基于生产环境构建)\n  * [2.2 准备编译工具](#22-准备编译工具)\n  * [2.3 准备第三方库](#23-准备第三方库)\n  * [2.4 下载大器源代码](#24-下载大器源代码)\n  * [2.5 编译“大器”库](#25-编译大器库)\n  * [2.6 在你的项目中使用 da4qi4库](#26-在你的项目中使用da4qi4)\n- [三、运行时外部配套系统](#三运行时外部配套系统)\n  * [3.1 运行时依赖说明](#31-运行时依赖说明)\n  * [3.2 Redis的安装](#32-redis的安装)\n  * [3.3 数据库](#33-数据库)\n\n# 零、几个原则\n\n## 0.1 自己的狗粮自己吃\n\n官网 [第2学堂 www.d2school.com](http://www.d2school.com) 后台使用 da4qi4作为Web Server开发。（nginx + da4qi4 + redis + mysql）。 \n给一个在手机上运行的网站效果：\n\n![第2学堂手机版](https://images.gitee.com/uploads/images/2019/1114/123659_60286a85_1463463.png \"手机屏幕截图.png\")\n\n样式丑，但这只和差劲的UI师，也就是我的美感有关，和后台使用什么Web框架没有关系。\n\n## 0.2 站在巨人的肩膀上\n\nda4qi4 Web 框架优先使用成熟的、C/C++开源项目的搭建。它的关键组成：\n\n- HTTP 基础协议解析：[Node.JS/llhttp](https://github.com/nodejs/llhttp)。 一直使用Node.JS底层的HTTP解析器，Node.JS v12 之前是[nodejs/http-parser](https://github.com/nodejs/http-parser)；之后升级迁移到 [llhttp](https://github.com/nodejs/llhttp) 。Node.JS 官方说法解析性能提升156%；\n- HTTP multi-part  : multipart-parsr [multipart-parser-c](https://github.com/iafonov/multipart-parser-c) ；\n- 网络异步框架： C++ boost.asio [boostorg/asio](https://github.com/boostorg/asio) （可能进入C++2x标准库）\n- JSON  :  [nlohmann-json JSON for Modern C++](https://github.com/nlohmann/json) (github上搜索JSON结果中第一个)；\n- 日志： [splogs](https://github.com/gabime/spdlog) 高性能的C++日志库 (微软公司选择将它绑定到 Node.JS 作日志库)；\n- 模板引擎： [inja](https://github.com/pantor/inja) 模板引擎 [Jinja](https://palletsprojects.com/p/jinja/) 的 C++ 实现版本，名气不大，但能和nlohmann-json完美配合实现C++内嵌的动态数据结构，加上我为它解决过bug，比较熟悉、放心。\n- TLS/SSL/数据加密： [OpenSSL](https://www.openssl.org/) （TLS）；\n- Redis 客户端： 基于[nekipelov/redisclient](https://github.com/nekipelov/redisclient)，为以类node.js访问redis进行专门优化（实现单线程异步访问，去锁）。 da4qi4默认使用redis缓存session等信息(以优先支持负载均衡下的节点无状态横向扩展)。\n- 静态文件服务： da4qi4自身支持静态文件（包括前端缓存逻辑）。实际项目部署建议与nginx配合。由nginx提供更高性能、更安全的接入及提从静态文件服务。\n\n注：\n\n1. 框架未绑定数据库访问方式。用户可使用 Oracle 官方 C++ Connector，或MySQL++，或 [三、运行时外部配套系统](#三运行时外部配套系统)提及的各类数据库连接器；\n2. 框架自身使用 redis 作为默认的（可跨进程的）SESSION支持。上层应用可选用框架的redis接口，也可以使用自己喜欢、 顺手 的redis C++客户端。\n\n## 0.3 易用优于性能\n\n使用C++开发，基于异步框架，目的就是为了有一个较好的原生性能起点，开发者不要过于费心性能。当然，性能也不能差，因为性能差必将影响产品的易用性）。\n暂时仅与 Tomcat 做了一个比较。由于Tomcat似乎是“Per Connection Per Thread/每连接每线程”，所以这个对比会有些胜之不武；但考虑到Tomcat曾广泛应用于实际系统，所以和它的对比数据有利于表明da4qi4在性能上的可用性。\n\n **基准测试环境：** \n\n- ubuntu 18.04 \n- 4核心8线程 、8G内存\n- 测试工具： Jmeter\n- 测试工具和服务端运行于同一机器（显然会影响服务端性能，不过本次测试重点是做相对性的对比）\n- 后台无业务，不访问数据库，仅返回简短字符串（造成吞吐量严重不足）\n- 不走nginx等Web Server的反向代理\n\n**Tomcat 运行配置**\n\n- JVM 1.8G 内存\n\n- 最大线程数：10000\n\n- 最大连接数：20000\n\n- 最大等待队列长度 200\n  \n  _对 Tomcat不算熟，因此以上配置基本照着网上的相关测试指南设置，有不合理之处，望指正。_ \n\n| -      | 并发数  | 平均响应（ms） | 响应时间中位数（ms） | 99% 用户响应时间（ms） | 最小响应（ms） | 最大响应（ms） | 错误率 | 吞吐量(s) | 每秒接收字节(KB） |\n| ------ | ---- | -------- | ----------- | -------------- | -------- | -------- | --- | ------ | ---------- |\n| tomcat | 1000 | 350      | 337         | 872            | 1        | 879      | 0   | 886.7  | 273        |\n| da4qi4 | 1000 | 1        | 1           | 20             | 0        | 24       | 0   | 1233   | 286.6      |\n\n另，官网 www.d2school.com 一度以 1M带度、1核CPU、1G 内存的一台服务器作为运行环境（即：同时还运行MySQL、redis服务）；后因线上编译太慢，做了有限的升级。\n\n后续会给出与其他Web Server的更多对比。但总体上，da4qi4 的当前阶段开发，基本不会以极端性能提升作为目标。\n\n## 0.4 简单胜过炫技\n\n众所周知C++语言很难，非常适于C++程序员“炫技”；所以有一票C++开源项目虽然技术上很优秀，但却很容易吓跑普通的C++程序员。比如，超爱用“模板元”……da4qi4 的代码强烈克制了这种“炫技”冲动，尽量代码看上去毫无技巧，特别是对外接口，遵循KISS原则，不会让你产生任何“惊奇”（头回看到程序员把无技可炫写得这么清新脱俗？）。\n\n不管怎样，在C++所大范围支持的“面向过程”、“基于对象”、“面向对象”和“泛型”等编程模式中，你只需熟悉“面向过程”，并且会一点“基于对象”，就可以放心地用这个库。\n\n## 0.5 紧跟国内生产环境\n\n用哪个版本的C++？用哪个版本的boost库？用哪个版本的OpenSSL？用哪个版本的CMake？\n\n就一个标准：当前国内主要云计算提供商，已经提供哪些现成的版本，我们就用那个版本——这意味着你几乎只需编译好你写的代码可以完成在线构建、部署了。不用编译boost、不用编译OpenSSL、不用下载编译新版的CMake……\n\n[阿里云](https://cn.aliyun.com/)、[腾讯云](https://cloud.tencent.com/)、[百度云](https://cloud.baidu.com/)、[华为云](https://www.huaweicloud.com/)、[七牛云](https://www.qiniu.com/)……无论哪家，只要你在上面申请一台Ubuntu 18.04 （或更高版本）的服务器，简单向行指令就能在线编译、部署好，让它成为一台跑着“大器 INSIDE”的WEB 服务器，为你的用户提供网站服务。对服务器配置的最低要求是：4G内存、1M带宽、1核CPU。\n\n# 一、快速了解\n\n## 1.1 一个空转的Web Server\n\n我们需要一个C++文件，假设名为“main.cpp”，内容如下：\n\n```C++\n#include \"daqi/da4qi4.hpp\"\n\nusing namespace da4qi4;\n\nint main()\n{\n    auto svc = Server::Supply(4098);\n    svc->Run();\n}\n```\n\n不到10行代码，我们创建了一个空转的，似乎不干活的Web Server。\n\n编译、运行，然后在浏览器地址栏输入：http://127.0.0.1:4098 ，而后回车，浏览器将显示一个页面，上面写着：\n\n```\nNot Found\n```\n\n虽然说它“不干活”，但这个Web Server的运行完全合乎逻辑：我们没有为它配备任何资源或响应操作、，所以对它的任何访问，都返回404页面：“Not Found”。\n\n## 1.2 Hello World!\n\n接下来实现这么一个功能：当访问网站的根路径时，它能响应：“Hello World!”。\n\n### 1.2.1 针对指定URL的响应\n\n这需要我们大代码中指示框架遇上访问网站根路径时，做出必要的响应。响应可以是函数指针、std::function、类方法或C++11引入的lambda，我们先来使用最后者：\n\n```C++\n#include \"daqi/da4qi4.hpp\"\n\nusing namespace da4qi4;\n\nint main()\n{\n    auto svc = Server::Supply(4098);\n\n    svc->AddHandler(_GET_, \"/\", [](Context ctx)\n    {\n        ctx->Res().ReplyOk(\"Hello World!\");\n        ctx->Pass();\n    });\n\n    svc->Run();\n}\n```\n\n例中使用到的Server类的AddHandler()方法，并提供三个入参：\n\n1. 指定的HTTP访问方法： \\_GET\\_;\n\n2. 指定的访问URL： /，即根路径 ;\n\n3. 匿名的lambda表达式。\n\n三个入参以及方法名合起来表达：如果用户以GET方法访问网站的根路径，框架就调用lambda表达式以做出响应。\n\n编译、运行。现在用浏览器访问 http://127.0.0.1:4098 ，将看到：\n\n```\nHello World!\n```\n\n作为对比，下面给出同样功能使用自由函数的实现：\n\n```C++\n#include \"daqi/da4qi4.hpp\"\n\nusing namespace da4qi4;\n\nvoid hello(Context ctx)\n{\n    ctx->Res().ReplyOk(\"Hello World!\");\n    ctx->Pass();\n}\n\nint main()\n{\n    auto svc = Server::Supply(4098);\n\n    svc->AddHandler(_GET_, \"/\",  hello); \n    svc->Run();\n}\n```\n\n为节省代码篇幅，后续演示均使用lambda表达式来表达HTTP的响应操作。实际系统显然不可能将代码全塞在main()函数中，因此平实的自由函数会用得更多。不仅lambda不是必需，实际是连“class/类”都很少使用——这符号Web Server基本的要求：尽量不要带状态；自由函数相比类的成员函数（或称方法），更“天然的”不带状态。\n\n### 1.2.2 返回HTML\n\n以上代码返回给浏览器纯文本内容，接下来，应该来返回HTML格式的内容。出于演示目的，我们干了一件有“恶臭”的事：直接在代码中写HTML字符串。后面很快会演示正常的做法：使用静态文件，或者基于网页模板文件来定制网页的页面内容；但现在，让我们来修改第11行代码调用ReplyOK()函数的入参，原来是“Hello World!”，现在将它改成一串HTML：\n\n```c++\n……\n   ctx->Res().ReplyOk(\"<html><body><h1>Hello World!</h1></body></html>\");\n……\n```\n\n## 1.3 处理请求\n\n接下来，我们希望请求和响应的内容都能够有点变化，并且二者的变化存在一定的匹配关系。具体是：在请求的URL中，加一个参数，假设是“name=Tom”，则我们希望后台能返回“Hello Tom!”。\n\n这就需要用到“Request/请求”和“Response/响应”：\n\n```C++\n#include \"daqi/da4qi4.hpp\"\n\nusing namespace da4qi4;\n\nint main()\n{\n    auto svc = Server::Supply(4098);\n\n    svc->AddHandler(_GET_, \"/\", [](Context ctx)\n    {\n        std::string name = ctx->Req(\"name\");\n        std::string html = \"<html><body><h1>Hello \" + name + \"!</h1></body></html>\";\n        ctx->Res().ReplyOk(html);\n        ctx->Pass();\n    });\n\n    svc->Run();\n}\n```\n\n> 重要： 这里为方便演示而使用 lambda 表达式，但实际系统不可能把所有代码都放在main()函数中写。所以肯定是一个个函数。用编程语言中最最基础的函数并不丢人，因为，我们要的是实用，而不是非在代码秀一下“我会lambda哦！”。（参看：[0.4 简单胜过炫技](#04-简单胜过炫技)）\n\n编译、运行。通过浏览器访问 “http://127.0.0.1:4098/?name=Tom” ，将得到带有HTML格式控制的 “Hello Tom!”。\n\n## 1.4 引入Application\n\n编译、运行。通过浏览器访问 “http://127.0.0.1:4098/?name=Tom” ，将得到带有HTML格式控制的 “Hello Tom!”。\n\nServer代表一个Web 服务端，但同一个Web Server系统很可能可分成多个不同的人群。\n\n> 举例：比如写一个在线商城，第一类用户，也是主要的用户，当然就是来商城在线购物的买家，第二类用户则是卖家和商城的管理员。这种区别，也可以称作是：一个服务端，多个应用。在大器框架中，应用以Application表达。\n\n就当前而言，还不到演示一个Server上挂接多个Application的复杂案例，那我们为什么要开始介绍Application呢？Application才是负责应后台行为的主要实现者。在前面的例子中，虽然没有在代码中虽然只看到Server，但背后是由Server帮我们创建一个默认的 Application 对象，然后依靠该默认对象以实现演示中的相关功能。\n\n下面我们就通过“Server | 服务”对象，取出这个“Application | 应用”，并代替前者实现前面最后一个例子的功能。\n\n```C++\n#include \"daqi/da4qi4.hpp\"\n\nusing namespace da4qi4;\n\nint main()\n{\n    auto svc = Server::Supply(4098);\n\n    auto app = svc->DefaultApp(); //取出自动生成的默认应用对象\n    app->AddHandler(_GET_, \"/\", [](Context ctx)\n    {\n        std::string name = ctx->Req(\"name\");\n        std::string html = \"<html><body><h1>Hello \" + name + \"!</h1></body></html>\";\n        ctx->Res().ReplyOk(html);\n        ctx->Pass();\n    });\n\n    svc->Run();\n}\n```\n\n除了“AddHandler()”的实施对象以前是svc，现在是“app”以外，基本没有什么变化。代码和前面没有显式引入Application之前功能一致。但为什么我们一定要引入Application呢？除了前述的，为将来一个Server对应多个Application做准备之外，从设计及运维上讲，还有一个目的：让Server和Application各背责任。 **Application负责较为高层的逻辑，重点是具体的某类业务，而Server则负责服务器较基础的逻辑，重点是网络方面的功能** 。下一小节将要讲到日志，正好是二者分工的一个典型体现。\n\n## 1.5 运行日志\n\n一个Web Server在运行时，当然容易遇到或产生各种问题。这时候后台能够输出、存储运行时的各种日志是大有必要的功能。并且，最最重要的是，如果你写一个服务端程序，运行大半年没有什么屏幕输出，看起来实在是“不够专业”，很有可能会影响你的工资收入……\n\n结合前面所说的Server与Application的分工。日志在归集上就被分成两大部分：服务日志和应用日志。\n\n- 服务层日志：全局唯一，记录底层网络、相关的周边运行支撑环境(缓存/Redis、数据库/MySQL)等基础设施的运行状态。\n\n- 应用层日志：每个应用都对应一个日志记录器，记录该应用的运行日志。\n\n其中，相对底层的Server日志由框架自动创建；而应用层日志自然是每个应用对应一套日志。程序可以为服务层和应用层日志创建不同的日志策略。事实上，如果有多个应用，那自然可以为每个应用定制不同的日志策略。如果不主动为某个应用创建日志记录器，则该应用只管全速运行，不输出任何日志——听起很酷，但你不应该对自己写的代码这么有信心。\n\n```C++\n#include \"daqi/da4qi4.hpp\"\n\nusing namespace da4qi4;\n\nint main()\n{\n    //初始化服务日志，需指定日志文件要存在哪里？以及日志记录的最低级别\n    log::InitServerLogger(\"你希望/服务日志文件/要存储的/目录/\" \n                        , log::Level::debug));        \n\n    auto svc = Server::Supply(4098);\n    log::Server()->info(\"服务已成功加载.\");          //强行输出一条服务日志\n\n    auto app = svc->DefaultApp();\n\n    //再来初始化应用日志\n    app->InitLogger(\"你希望/当前应用的/要存储的/目录/\");\n\n    app->AddHandler(_GET_, \"/\", [](Context ctx)\n    {\n        std::string name = ctx->Req(\"name\");\n        std::string html = \"<html><body><h1>Hello \" + name + \"!</h1></body></html>\";\n        ctx->Res().ReplyOk(html);\n        ctx->Pass();\n    });\n\n    svc->Run();\n    log::Server()->info(\"再见！\");                  //强行再输出一条服务日志\n}\n```\n\n所有日志功能都在“log::”名字空间之下。以上日志配置不仅会将信息输出到终端（控制台），也会自动输出指定目录下的文件中，服务日志和各应用日志是独立的文件。文件带有默认的最大尺寸和最大个数限制。实际在linux服务器上运行时，程序通常在后台运行并将本次运行的屏幕输出重定向到某个文件。\n\n日志的输出控制，支持常见的：跟踪(trace)、调试(debug)、信息(info)、警告(warn)、错误(err)、致命错误(critical)等级别。例中对“app->InitLogger()” 使用默认级别：info。\n\n下面是运行日志截图示例。\n\n![输入图片说明](https://images.gitee.com/uploads/images/2019/1114/123346_2e261b35_1463463.jpeg \"da4qi4运行日志界面\")\n\n看起来有点像个后台程序，可以申请领导过来视察你的工作成果了。\n\n## 1.6 HTML模板\n\n是时候解决在代码中直接写HTML的问题了。\n\n用户最终看到的网页的内容，有一些在系统设计阶段就很清楚，有一些则必须等用户访问时才知道。比如前面的例子中，在设计时就清楚的有：页面字体格式，以及“Hello, _ _ _ _ !”；而需要在运行时用户访问后才能知道的，就是当中的下划线处所要填写的内容。\n\n下面是适用于本例的，一个相当简单的的HTMl网页模板：\n\n```html\n<!DOCTYPE html>\n<html lang=\"zh\">\n<head>\n    <title>首页</title>\n    <meta content=\"text/html; charset=UTF-8\">\n</head>\n<body>\n    <h1>你好，{=_URL_PARAMETER_(\"name\")=} ！</h1>\n    <p>您正在使用的浏览器： {=_HEADER_(\"User-Agent\")=}</p>\n    <p>您正在通过该网址访问本站：{=_HEADER_(\"Host\")=}</p>\n</body>\n</html>\n```\n\n“你好，”后面的特定格式{=_URL_PARAMETER_(\"name\")=} ，将会被程序的模板解析引擎识别，并填写上运行时的提供的name的值。\n\n解释：\n\n- \\_URL_PARAMETER\\_() 是网页模板脚本内置提供的一个函数，它将自动得取浏览器地址栏输入URL后，所带的参数。\n- \\_HEADER\\_() 同样是网页模板脚本内置的一个函数，用以获得当前HTTP请求的报头数据项。在本例中无实际业务作用，常用于辅助页面调试。\n\n假设这个文件被存放在 “你的/网页模板/目录”。下面代码中的 “app->SetTemplateRoot()”将用到这个目录的路径。\n\n```C++\n#include \"daqi/da4qi4.hpp\"\n\nusing namespace da4qi4;\n\nint main()\n{\n    log::InitServerLogger(\"你希望/服务日志文件/要存储的/目录/\", log::Level::debug));\n\n    auto svc = Server::Supply(4098);\n    log::Server()->info(\"服务已成功加载.\");\n\n    auto app = svc->DefaultApp();\n\n    //新增的两行：\n    app->SetTemplateRoot(\"你的/网页模板/目录/\"); //模板文件根目录\n    app->InitTemplates(); //加载并将模板文件“编译成” 字节码\n\n    app->InitLogger(\"你希望/当前应用的/要存储的/目录/\");\n\n    //下面这行让sever定时检测模板文件的变动（包括新增）\n    svc->EnableDetectTemplates(5); //5秒，实际项目请设置较大间隔，如10分钟\n\n    svc->Run();\n    log::Server()->info(\"再见！\");\n}\n```\n\n现在，使用火狐浏览器访问URL并带上“name”参数：http://127.0.0.1:4098?name=大器da4qi4 ，将得到以下HTML内容：\n\n```html\n<h1>你好，大器da4qi4 ！</h1>\n<p>您正在使用的浏览器：Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:71.0) Gecko/20100101 Firefox/71.0 </p>\n<p>您正在通过该网址访问本站：127.0.0.1:4098</p>\n```\n\n小提示：“为什么代码更短了？” 你应该注意到，基于模板响应后，代码原有“AddHandler()” 都不见了。因为这个例子没有实质业务逻辑：用户访问一个URL地址，并且带参数，服务依据事先定义的模板样式，将这个参数原样展现出来。实际业务系统当然不可能这么简单（否则要我们后端程序员干什么？），但是，当我们在快速搭建一个系统时，在初始开发过程中，这种情况非常常见，不需要修改源代码，不需要重启服务程序，就能直接看到新增或修改的网页内容，带给我们很大的方便。\n\n框架提供的模板引擎，不仅能替换数据，也支持基本的条件判断、循环、自定函数等功能，类似一门“脚本”。\n\n> 重要：多数情况下我们写C++程序用以高性能地、从各种来源（数据库、缓存、文件、网络等）、以各种花样（同步、异步）获取数据、处理数据。而HTML模板引擎在C++程序中以解释的方式运行，因此正常的做法是不要让一个模板引擎干太复杂的，毕竟，在C++这种 “彪形大汉”的语言面，页面模板引擎“语言”无论在功能还是性能上，都只能算是一个小孩子。\n\n接下来，我们应该有一个带业务逻辑的例子。这个业务逻辑非常的复杂，并且严重依赖于CPU的计算速度……我们要做一个加法器。用户在浏览器地址栏输入:\n\n```html\nhttp://127.0.0.1:4098/add?a=1&b=2\n```\n\n浏览器将显示a+b的结果。显然，业务逻辑就是计算两个整数相加，我们的强大的，计算力过剩的C++语言终于可以派上用场。\n\n首先，准备一个用于显示加法结果的页面模板，文件名为 “add.daqi.HTML”：\n\n```html\n<!DOCTYPE html>\n<html lang=\"zh\">\n<head>\n    <title>加法</title>\n    <meta content=\"text/html; charset=UTF-8\">\n</head>\n<body>\n    <p>\n       {=c=} \n    </p>\n</body>\n</html>\n```\n\n重点在 “{=c=}”身上。 {==} 仍然用来标识一个可变内容，但其内不再是一个内置函数，而是一个普通的变量名称：c。为此我们在C++代码中要做的事变成两件：一是计算 a 加 b的和，二是将和以 c 为名字，填入模板对应位置。\n\n然后需要一个add的自由函数：\n\n```C++\nvoid add(Context ctx)\n{\n    //第一步：取得用户输入的参数 a 和 b:\n    std::string a = ctx->Req().GetUrlParameter(\"a\");\n    std::string b = ctx->Req().GetUrlParameter(\"b\");\n\n    //第二步：把字符串转换为整数:\n    int na = std::stoi(a);  //stoi 是 C++11新标中的字符串转换整数的函数\n    int nb = std::stoi(b);\n\n    //第三步：核心核心核心业务逻辑：加法计算\n    int c = na + nb;\n\n    //第四步：把结果按模板指定的名字\"c\"，设置到“Model”数据中：\n    ctx->ModelData()[\"c\"] = c;\n\n    //最后一步：渲染，并把最终页面数据传回浏览器： （即：输出结果 = 模板 + 数据）\n    ctx->Render().Pass();  //Render 是动词：渲染\n}\n```\n\n暂时为了简化，我们不写日志、不作错误处理，现在，除了add函数的内部实现外，完整的main.cpp文件内容是：\n\n```C++\n#include \"daqi/da4qi4.hpp\"\n\nusing namespace da4qi4;\n\nvoid add(Context ctx)\n{ \n      /* 实现见上 */\n}\n\nint main()\n{\n    auto svc = Server::Supply(\"127.0.0.1\", 4098);\n    auto app = svc->DefaultApp(); \n\n    app->SetTemplateRoot(\"你的/网页模板/目录/\"); \n    app->InitTemplates();\n\n    //AddHandler 又回来了：\n    app->AddHandler(_GET_, \"/add\", add);\n\n    svc->EnableDetectTemplates(5);\n    svc->Run();\n}\n```\n\n如前所述通过浏览器访问  .../add?a=1&b=2 ，将看一个简单的3。\n\n甲方说这也太不人性化了，好歹显示一个 “1 + 2 = 3” 啊！ 太好了，我们正好借此演示如何不修改代码，不重启服务程序就达成目标。\n\n需要修改的是模板文件：“add.daqi.HTML”：\n\n```html\n<!DOCTYPE html>\n<html lang=\"zh\">\n<head>\n    <title>加法</title>\n    <meta content=\"text/html; charset=UTF-8\">\n</head>\n<body>\n    <p>\n        <!-- 展示内容类似：1 + 2 = 3  -->\n        {=_URL_PARAMETER_(\"a\")=}  +  {=_URL_PARAMETER_(\"b\")=} = {=c=} \n    </p>\n</body>\n</html>\n```\n\n修改、保存，5秒过后再访问，就看到新成果了。\n\n会有人担心C++写的程序容易出错，并且一出错就直接挂掉——上面程序，如果用户无意有意或干脆就是恶意搞破坏，输入 “.../add?a=A&b=BBBB”……会怎样呢？ add 函数中的 “std::stoi()” 调用可能抛出异常？不管怎样，请放心，程序并不会挂掉，它会继续运行，只是：\n\n- 一来、用户只会看到一个典型的HTTP 500 错误 “Internal Server Error  ”  (即：服务内部错误),这对用户来说，不太友好。\n\n- 二来，后台什么日志记录也没有，对系统的维护人员来说，也不友好。\n\n很简单，对add的业务逻辑加上异常处理，出现异常时，向客户回复一句相对友好点的内容，并且留下应用日志即可。以下是关注异常后的add函数：\n\n```C++\n#include \"daqi/da4qi4.hpp\"\n\nusing namespace da4qi4;\n\nvoid add(Context ctx)\n{\n    try\n    {\n        std::string a = ctx->Req().GetUrlParameter(\"a\");\n        std::string b = ctx->Req().GetUrlParameter(\"b\");\n\n        int na = std::stoi(a); \n        int nb = std::stoi(b);\n\n        int c = na + nb;\n\n        ctx->ModelData()[\"c\"] = c;\n    }\n   catch(std::exception const& e)\n   {\n        ctx->Logger()->warn(\"hand add exception. {}. {}. {}.\", a, b, e.what());\n        ctx->ModelData()[\"c\"] = std::string(\"同学，不要乱输入加数嘛！\") + e.what();\n   }\n\n   ctx->Render().Pass();\n}\n```\n\n关键在异常处理。第一行是：\n\n```C++\nctx->Logger()->warn(\"hand add exception. {}. {}. {}.\", a, b, e.what());\n```\n\n三个重点：\n\n- 一是如何通过上下文（Context）得到当前应用的日志记录器：ctx->Logger()。它实际上是 ctx->App().GetLogger() 的简写。\n\n- 二是得益于“spdlog”的语法，记日志就这么简单：要显示三个信息：a、b和异常，就在前面的格式字符串中，写上三个 {} ，最终就可以在日志中看到一行完整的内容。\n\n- 三是我们使用“warn()”，而不是“error()”，这体现了服务程序在此刻的淡定内心：不就是用户输入错误嘛？有什么因结什么果。用户输入错误，就返回给他一行出错信息。何事慌张？警告而已。\n\n第二行是：\n\n```C++\nctx->ModelData()[\"c\"] = std::string(\"同学，不要乱输入加数嘛！\") + e.what();\n```\n\n重点在于：赋值操作的右值，是一个字符串。“ModelData”，即“模型数据”在这里指的是即将写往页面模板的数据，和C++的强类型相比，页面上的数据不用太区分类型。所以，“c” 本是a+b之和，按理说是整数类型，但我们却可以往里写入一行字符串，这样，当用户捣乱造成 a + b 无法执行时，他就会看到一行出错信息。\n\n> main() 函数中如何初始化日志，已经演示过，不再给出代码。\n\n## 1.7 WebSocket\n\n### 1.7.1 HTTP 对比 WebSocket\n\n先简单说下在业务与技术上，传统HTTP访问和WebSocket访问的核心区别。\n\nHTTP访问讲究“无状态”，当然，一个业务系统怎么可能无状态，只不过是将状态都放在数据中（缓存、数据库），所谓的无状态是指业务逻辑相关的“类/class”应该无状态——这正好和“class/类”或“object/对象”本质是一个“状态机”相冲突——幸好C++支持多范式开发，所以在前面的例子中，我们几乎不设计“class”，而是使用天生无状态的自由函数。“类与对象”想写成不带状态的状态，难；而自由函数想写出带“状态”来，还真不简单。\n\n到了WebSocket，长连接，通常这时候就有状态——甚至此时底层的网络连接保持或断开本身就是一种状态。比如使用WebSocket写一个页面聊天室，有人连线，就是上线了（进聊天室）；有人断线，那就是下线了（出聊天室）。再比如，假设我们的“聊天室”要限制“潜水”用户，就至少得记录每个用户这些状态：上线多久一直没有说话？反过来，如果要限制话痨用户，也至少需要记录一个用户说话记录的记数——这些都是状态。\n\n结论：HTTP访问后端讲究无状态，所以很适合使用“面向过程”的自由函数，而WebSocket 的后端往往需要保持状态，所以这时候“面向对象”比较合适。da4qi4的WebSocket 在保持对无状态的支持下，增加并且主要使用“有状态”的类设计做支持。\n\n### 1.7.2 大器WebSocket后台实现特性\n\n- 支持直接接入WebSokcet支持，也支持从nginx继续反向代理。\n\n- 支持一个端口同时响应HTTP和WebSocket请求。\n\n- 支持ws和wss。\n\n- 支持服务端推送（其实是WebSocket的要求）。\n\n- 支持大报文分段传输（其实也是WebSocket的要求）。\n\n- 支持群发。\n\n- 保持和HTTP相对一致的概念与设计，比如上下文：Context。\n\n- WebSocket连接时，可以方便获得连接升级(upgrade)前的Cookie、HTTP报头、URL等信息。\n\n### 1.7.3 使用示例\n\n一、先演示面向对象思路的写法。\n\n1. 先写一个类，派生自 da4qi4::Websocket::EventsHandler。\n\n```C++\nusing namespace da4qi4;\n\nclass MyEventsHandler : public Websocket::EventsHandler\n{\npublic:\n    bool Open(Websocket::Context ctx)　{ return　true; }   //允许该ws连接\n    \n    void OnText(Websocket::Context ctx, std::string&& data, bool isfinish)\n    {\n        ctx->Logger()->info(\"收到： {}.\", data);\n        ctx->SendText(\"已阅!\"); \n    }\n    \n    void OnBinary(Websocket::Context ctx, std::string&& data, bool isfinish)\n    {\n        //此时data是二进制数据，比如图片什么的，可以保存下来...\n    }\n    \n    void OnError(Websocket::Context ctx\n                , Websocket::EventOn evt //在哪个环节出错，读或写？\n                , int code //出错编号\n                , std::string const& msg //出错信息\n                )    \n    {\n        ctx->Logger()->error(\"出错了. {} - {}.\", code, msg);\n    }\n    \n    void OnClose(Websocket::Context ctx, Websocket::EventOn evt) \n    {\n        ctx->Logger()->info(\"Websocket连接已经关闭.\");\n    }   \n};\n```\n\n2. 在主函数中，在某个“Application”上注册一个WebSocket的后台处理方法。这个方法用来创建(new)出刚刚定义的那个“MyEventsHandler”的对象，我们使用lambda实现：\n\n```C++\n#include \"daqi/da4qi4.hpp\"\n#include \"daqi/websocket/websocket.hpp\" //引入websocket相关定义\n\nusing namespace da4qi4;\n\nclass MyEventsHandler : public Websocket::EventsHandler\n{\n     //见上\n};\n\nint main()\n{\n    auto svc = Server::Supply(4098);\n    auto app = svc->DefaultApp();\n    app->InitLogger(\"log/\");\n　\n    //在某个app的指定URL下，挂接一个websocket响应处理\n    app->RegistWebSocket(\"/ws\", UrlFlag::url_full_path, \n           [](){ return new MyEventsHandler; }\n    );\n\n    svc->Run();\n}\n```\n\n现在，让你的前端开发人员，在ＨＴＭＬ页面里，用JS写一段代码，类似于：\n\n```javascript\nvar ws = new WebSocket(\"ws://127.0.0.1:4098/ws\");\n\nws.onopen = function(evt) {\n    this.send(\"Hello WebSocket.\");\n}\n\nws.onmessage = function (evt) {\n    console.log(evt.data);\n}\n……\n```\n\n前后端就可以聊起来了。\n\n二、如果后台业务逻辑确实很简单，那写一个类，还派生什么的确实显得很笨。此时也可以使用简单的函数、labmbda来快速响应。\n\n方法是定义一个大器预定的　“ Websocket::EventHandleFunctor”　变量：\n\n```C++\n#include \"daqi/da4qi4.hpp\"\n#include \"daqi/websocket/websocket.hpp\" //引入websocket相关定义\n\nusing namespace da4qi4;\n\n/*不需要类定义了*/\n\nint main()\n{\n    auto svc = Server::Supply(4098);\n    auto app = svc->DefaultApp();\n    app->InitLogger(\"log/\");\n\n    Websocket::EventHandleFunctor functor;\n    functor.DoOnText = [] (Websocket::Context ctx, std::string&& data, bool isfinished)\n    {\n        ctx->Logger()->info(\"收到： {}.\", data);\n        ctx->SendText(\"已阅!\");\n    }\n\n    app->RegistWebSocket(\"/ws\", UrlFlag::url_full_path, functor);\n\n    svc->Run();\n}\n```\n\n## 1.8 更多\n\n### 1.8.1 框架更多集成功能\n\n1. cookie支持\n\n2. 前端（浏览器）缓存支持\n\n3. Redis 缓存支持\n\n4. Session 支持\n\n5. 静态文件\n\n6. 模板文件更新检测及热加载\n\n7. HTTP/HTTPS 客户端组件（已基于此实现微信扫码登录、阿里云短信的C++SDK，见下）\n\n8. POST响应支持\n\n9. 文件上传、下载\n\n10. 访问限流\n\n11. JSON\n\n12. 纯数据输出的API接口，与前端AJAX配合\n\n13. 框架全方式集成：(a) 基于源代码集成、(b) 基于动态库集成、(c) 基于静态库集成\n\n14. 常用编码转换（UTF-8、UCS、GBK、GB18030）\n\n15. ……\n\n### 1.8.2 框架外围可供集成的工具\n\n1. 数据库访问\n\n2. 和nginx配合（实现负载均衡的快速横向扩展）\n\n3. 阿里短信云异步客户端\n\n4. 微信扫一扫登录异步客户端\n\n5. 基于OpenSSL的数据加密工具\n\n6. 常用字符串处理\n\n7. ……\n\n# 二、如何构建\n\n## 2.1 基于生产环境构建\n\n尽管使用的组件都支持跨平台，但大器当前仅支持在Linux下环境编译；大多数实际项目的服务，都运行在Linux下。\n\n> Web 服务端部署在Linux上，这是有原因的： (1) 前述的外围组件：nginx、mysql、redis 在Linux下安装都是一行命令的事，远比Windows方便。(2) 如果你使用当前非常流行的Docker，更是如此。 (3) 事实上Web 端的开源大杀器都是先提供Linux版，然后再考虑出Windows版，甚至有官方拒绝出Windows版（比如Redis 作者就“无情”地拒绝了微软提供的，将Redis变成也可以在Windows执行的补丁包）。\n\n大器框架同样会在后续某个时间，提供Windows版本。\n\n当前国内各云计算提供商，均提供 Ubuntu Server 版本为 18.04 LTS 版本。如“[0.5 紧跟国内生产环境](#05-紧跟国内生产环境)” 小节所述，你有一台2019年或更新的Ubuntu云服务器，那么在其上构建大器，则所需的软件、依赖库等，暂时只有一个用于中文编码转换的 iconv 库，需要手动下载编译之外，其它的都可以从Ubuntu 软件仓库中获取。\n\n以下内容均以 Ubuntu 18.04  为例，考虑日常开发不会直接使用Server版，因此严格讲，以下内容均假设系统环境为 Ubuntu 18.04 桌面版。\n\n> 小提示-服务器与开发机的区别：\n> \n> 开发机（桌面版）为安装组件时，需临时提升用户权限，即相关指令前面多出个“sudo ”。如果是在服务版的Ubuntu操作，默认就是拥有更高管理权限的根用户，因此不需要该指令。例如：\n> 开发机：sudo apt install git\n> 服务器：apt install git\n\n## 2.2 准备编译工具\n\n1. 如果未安装或不知道有没有安装（以下简称为“准备”） GCC 编译器：\n\n```shell\nsudo apt install build-essential\n```\n\n2. 准备 CMake构建套件，请：\n\n```shell\nsudo apt install cmake\n```\n\n## 2.3 准备第三方库\n\n1. 准备 boost 开发库：\n\n```shell\nsudo apt install libboost-dev libboost-filesystem libboost-system\n```\n\n2. 准备openssl及其开发库：\n\n```shell\nsudo apt install openssl libssl-dev\n```\n\n3. 准备 libiconv 库\n\n我们使用汉字，而汉字有多种编码方案，因此，汉字的编码转换，是开发包括Web应用在内各种软件系统的常见需求。大器框架通过集成iconv库用以实现支持多国语言多种编码的转换功能。\n\n先下载：https://ftp.gnu.org/pub/gnu/libiconv/libiconv-1.16.tar.gz\n\n在Ubuntu图形界面中，双击该.gz文件，再点击其内.tar文件，解压后得到 “libiconv-1.16”文件夹。在终端进入该文件夹，依次输入以下三行，完成安装：\n\n```shell\n./configure --prefix=/usr/local\nmake\nsudo make install\n```\n\n4. 最后，确保生效所安装的动态库在系统中能被找到：\n\n```shell\nsudo ldconfig\n```\n\n## 2.4 下载大器源代码\n\n通常你应该安装 git 工具，如果没有或不确定，请打开终端（Ctrl + Alt + T），按如下指令安装。\n\n```shell\nsudo apt install git \n```\n\n然后在本地新建一文件夹，假设命名为 daqi，打开终端进入该目录，从github克隆代码：\n\n```shell\ngit clone https://github.com/d2school/da4qi4.git\n```\n\n或者从国内的gitee克隆代码（速度比较快）：\n\n```shell\ngit  clone  https://gitee.com/zhuangyan-stone/da4qi4_public.git\n```\n\n最终，你**将在前述的“daqi”目录下，得到一个子目录“da4qi4”(也可能是别的，看git源)**。大器项目的代码位于后者内，其内你应该能看到“src”、“include”等多个子目录。\n\n> 感谢你看到这里。如有余力，建议在以上两个网站均为本开源项目打个星 。\n\n## 2.5 编译“大器”库\n\n**重要：以下假设大器源代码位于“daqi/da4qi4”目录下。**\n\n1. 准备构建目录\n\n请在“daqi”之下（和“da4qi4”平级）的位置，新建一目录，名为“build”：\n\n```shell\nmkdir build\n```\n\n进入该当目录：\n\n```shell\ncd build\n```\n\n2. 执行CMake\n\n> 如果你使用的是1.66或更高版本的boost库，请先打开项目下的CMakefile.txt文件，找到第13行：set(USE_LOCAL_BOOST_VERSION OFF) 将OFF改为ON： set(USE_LOCAL_BOOST_VERSION ON)\n\n\n```shell\ncmake -D_DAQI_TARGET_TYPE_=SHARED_LIB -DCMAKE_BUILD_TYPE=Release ../da4qi4/\n```\n\n将生成目标为“发行版（Release）”的大器“动态库（SHARED_LIB）”。\n\n* 如果希望生成调试版本，请将“Release”替换为“Debug”;\n* 如果希望生成静态库版本，请将“SHARED_LIB”替换为“STATIC_LIB”;\n* 更多编译目标设置，请到本项目官网“www.d2school.com”\n\n一切正常的看，将看到终端上输出“Generating done”等字样。其中更多内容中，包含有boost库的版本号、库所在路径，以及一行“\\~BUILD DAQI AS SHARED LIB\\~”字样以指示大器的编译形式（SHARED LIB)。\n\n3. 开始编译\n\n```shell\nmake\n```\n\n> 小提示：并行编译\n> 如果你的电脑拥有多核CPU，并且内存足够大（至少8G），可以按如下方式并行编译（其中 -j 后面的数字，指明并行编译的核数，以下以四核数例）：\n> make -j4 \n\n完成make之后，以上过程将在build目录内，得到“libda4qi4.so”；如果是调试版，将得到 “libda4qi4_d.so”。 如果是静态库，则相应的扩展名为 “.a”。\n\n以上工作都是一次性的，以后你再使用da4qi4开发新项目，都从下面的步骤开始。\n\n## 2.6 在你的项目中使用da4qi4库\n\n现在，你可以使用你熟悉IDE（Code::Blocks、Qt Creator、CodeLite等）中，构建你的项目，然后以类型使用其它开发库的方式，添加大器的库文件（就是前一步构建所得的.so或.a文件），及大器的头文件。\n\n1. da4qi4库文件。  即前面编译大器库得到的库文件，如“libda4qi4.so”或“libda4qi4.a”，“libda4qi4_d.so”、“libda4qi4_d.a”等文件。\n2. da4qi4库依赖的文件。 在Linux下，它们是 pthread、ssl、crypto、boost_filesystem、boost_system\n3. da4qi4头文件：“大器项目目录”、“大器项目目录/include”及“大器项目目录/nlohmann_json/include/”\n\n下面以CMake的CMakefiles.txt为例：\n\n```cmake\ncmake_minimum_required(VERSION 3.5)\n\nproject(hello_daqi LANGUAGES CXX)\n\nset(CMAKE_CXX_STANDARD 17)\nset(CMAKE_CXX_STANDARD_REQUIRED ON)\nset(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -g -Wall\")\n\n# 此处设置大器项目目录\nset(_DAQI_PROJECT_PATH_ \"你的大器项目所在目录\")\n# 此处设置大器项目编译后得到的 .so 文件所在目录\nset(_DAQI_LIBRARY_PATH_ \"你的大器项目动态库所在目录\")\n\ninclude_directories(${_DAQI_PROJECT_PATH_})\ninclude_directories(${_DAQI_PROJECT_PATH_}/include)\ninclude_directories(${_DAQI_PROJECT_PATH_}/nlohmann_json/include/)\n\nfind_package(Boost 1.65.0 REQUIRED COMPONENTS filesystem system)\nlink_directories(${_DAQI_LIBRARY_PATH_})\n\nlink_libraries(da4qi4)\n\nlink_libraries(pthread)\nlink_libraries(ssl)\nlink_libraries(crypto)\nlink_libraries(boost_filesystem)\nlink_libraries(boost_system)\n\nadd_executable(hello_daqi main.cpp)\n```\n\n现在你可以从之前 [1.1 一个空转的Web Server](#11-一个空转的web-server) 重新看起。\n\n# 三、运行时外部配套系统\n\n## 3.1 运行时依赖说明\n\n一个Web系统常用到缓存系统和数据库系统。大器框架对二者依赖情况如下：\n\n* 完全不依赖数据库；\n* 简单例子不依赖缓存系统，但一旦需要用到Web 系统常见的“会话/SESSION”功能，则需要依赖redis缓存库。\n\n## 3.2 Redis的安装\n\n显然，这已经不是本开源项目的自己的说明内容。不过，反正在Ubuntu Linux下安装Redis就一行话：\n\n```C++\nsudo apt install redis-server\n```\n\n这不仅会安装redis服务，而且会顺便在本机redis的命令行客户端 redis-cli。\n\n* 有关如何在你写的大器Web Server中实现SESSION，请参看本项目官网www.d2school.com 相关（免费视频）课程；\n* 有关Redis的学习，请关注www.d2school.com 课程。\n\n## 3.3 数据库\n\n* 可以使用 mysql 官方的 MySQL C++ Connector；\n* 新人强烈推荐： 相对传统的C++封装 ： [MySQL++](https://tangentsoft.com/mysqlpp/home) （注：欢迎关注《白话 C++》下册，有详细的 MySQL 数据库及 MySQL++使用的章节；\n* 新人推荐： [CppDB](http://cppcms.com/sql/cppdb/) \n* 到 [github](https://github.com)上，搜索 “MySQL C++”，你将找到大量国内或国外的MySQL C++连接库；\n* 有经验的C++程序员推荐：[sqlpp11](https://github.com/rbock/sqlpp11)\n\n更多课程（视频课程、文字课程），请到 [第2学堂](https://www.d2school.com)查看。\n谢谢。\n"
  },
  {
    "path": "cmake_install.cmake",
    "content": "# Install script for directory: /home/zhuangyan/Projects/CPP/da4qi4\n\n# Set the install prefix\nif(NOT DEFINED CMAKE_INSTALL_PREFIX)\n  set(CMAKE_INSTALL_PREFIX \"/usr/local\")\nendif()\nstring(REGEX REPLACE \"/$\" \"\" CMAKE_INSTALL_PREFIX \"${CMAKE_INSTALL_PREFIX}\")\n\n# Set the install configuration name.\nif(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME)\n  if(BUILD_TYPE)\n    string(REGEX REPLACE \"^[^A-Za-z0-9_]+\" \"\"\n           CMAKE_INSTALL_CONFIG_NAME \"${BUILD_TYPE}\")\n  else()\n    set(CMAKE_INSTALL_CONFIG_NAME \"\")\n  endif()\n  message(STATUS \"Install configuration: \\\"${CMAKE_INSTALL_CONFIG_NAME}\\\"\")\nendif()\n\n# Set the component getting installed.\nif(NOT CMAKE_INSTALL_COMPONENT)\n  if(COMPONENT)\n    message(STATUS \"Install component: \\\"${COMPONENT}\\\"\")\n    set(CMAKE_INSTALL_COMPONENT \"${COMPONENT}\")\n  else()\n    set(CMAKE_INSTALL_COMPONENT)\n  endif()\nendif()\n\n# Install shared libraries without execute permission?\nif(NOT DEFINED CMAKE_INSTALL_SO_NO_EXE)\n  set(CMAKE_INSTALL_SO_NO_EXE \"1\")\nendif()\n\n# Is this installation the result of a crosscompile?\nif(NOT DEFINED CMAKE_CROSSCOMPILING)\n  set(CMAKE_CROSSCOMPILING \"FALSE\")\nendif()\n\nif(NOT CMAKE_INSTALL_LOCAL_ONLY)\n  # Include the install script for each subdirectory.\n  include(\"/home/zhuangyan/Projects/CPP/da4qi4/nlohmann_json/cmake_install.cmake\")\n\nendif()\n\nif(CMAKE_INSTALL_COMPONENT)\n  set(CMAKE_INSTALL_MANIFEST \"install_manifest_${CMAKE_INSTALL_COMPONENT}.txt\")\nelse()\n  set(CMAKE_INSTALL_MANIFEST \"install_manifest.txt\")\nendif()\n\nstring(REPLACE \";\" \"\\n\" CMAKE_INSTALL_MANIFEST_CONTENT\n       \"${CMAKE_INSTALL_MANIFEST_FILES}\")\nfile(WRITE \"/home/zhuangyan/Projects/CPP/da4qi4/${CMAKE_INSTALL_MANIFEST}\"\n     \"${CMAKE_INSTALL_MANIFEST_CONTENT}\")\n"
  },
  {
    "path": "da4qi4.astylerc",
    "content": "# Allman Coding Style Options\r\n# Based on an old AStyle release.\r\n\r\n# braces and indent\r\nstyle=allman\r\nindent=spaces\r\n\r\n# indentation\r\nmin-conditional-indent=0\r\nmax-continuation-indent=80\r\nindent-switches\r\nindent-continuation=3\r\nindent-preproc-block\r\nindent-preproc-define\r\nindent-col1-comments\r\n\r\n# padding\r\npad-oper\r\npad-header\r\nunpad-paren\r\nalign-pointer=type\r\nbreak-blocks\r\npad-oper\r\npad-header\r\nalign-pointer=type\r\nalign-reference=type\r\n\r\n# formatting\r\nbreak-one-line-headers\r\nbreak-closing-braces\r\nkeep-one-line-statements\r\nconvert-tabs\r\nadd-braces\r\nclose-templates\r\nmax-code-length=120\r\n\r\n\r\n"
  },
  {
    "path": "include/daqi/application.hpp",
    "content": "#ifndef DAQI_APPLICATION_HPP\n#define DAQI_APPLICATION_HPP\n\n#include <set>\n#include <map>\n#include <memory>\n\n#include \"daqi/def/log_def.hpp\"\n#include \"daqi/def/boost_def.hpp\"\n#include \"daqi/utilities/string_utilities.hpp\"\n\n#include \"daqi/router.hpp\"\n#include \"daqi/templates.hpp\"\n#include \"daqi/intercepter.hpp\"\n\n#include \"daqi/websocket/handler_websocket.hpp\"\n#include \"daqi/websocket/connection_websocket.hpp\"\n\nnamespace da4qi4\n{\n\nstruct UploadFileSaveOptions\n{\n    enum Strategy\n    {\n        always_save\n        , alway_no_save\n        , size_greater_than\n        , size_lesser_than\n        , extension_is\n        , extension_is_not\n    };\n\n    bool IsNeedSave(std::string const& extension, size_t filesize_kb) const;\n\n    Strategy strategy = always_save;\n    size_t size_base_kb;\n    std::set<std::string, Utilities::IgnoreCaseCompare> extensions;\n};\n\nstruct AppLocalDiskSetting\n{\n    AppLocalDiskSetting()\n        : template_ext(get_daqi_HTML_template_ext())\n    {}\n\n    AppLocalDiskSetting(AppLocalDiskSetting const&) = default;\n    AppLocalDiskSetting(AppLocalDiskSetting&&) = default;\n\n    std::string log_dir;\n    std::string static_dir;\n\n    std::string template_dir;\n    std::string template_ext;\n\n    std::string temporary_dir;\n    std::string upload_dir;\n};\n\nstruct AppLoggerSetting\n{\n    static log::Level const  default_log_level = log::Level::info;\n    static std::size_t const default_max_log_file_size_kb = 5 * 1024;\n    static std::size_t const default_max_log_file_count = 9;\n\n    AppLoggerSetting()\n        : level(default_log_level),\n          max_log_file_size_kb(default_max_log_file_size_kb),\n          max_log_file_count(default_max_log_file_count)\n    {}\n\n    log::Level level;\n    size_t max_log_file_size_kb;\n    size_t max_log_file_count;\n};\n\n\nclass Application;\nusing ApplicationPtr = std::shared_ptr<Application>;\n\nclass Application\n{\nprivate:\n    Application();\n    Application(std::string const& name);\n\n    Application(std::string const& name\n                , std::string const& root_url\n                , fs::path const& root_log\n                , fs::path const& root_static\n                , fs::path const& root_template\n                , fs::path const& root_upload\n                , fs::path const& root_temporary\n                , std::string const& template_ext\n               );\npublic:\n    static ApplicationPtr Default()\n    {\n        return ApplicationPtr(new Application());\n    }\n\n    static ApplicationPtr Default(std::string const& name)\n    {\n        return ApplicationPtr(new Application(name));\n    }\n\n    static ApplicationPtr Customize(std::string const& name\n                                    , std::string const& root_url\n                                    , fs::path const& root_log\n                                    , fs::path const& root_static = \"\"\n                                    , fs::path const& root_template = \"\"\n                                    , fs::path const& root_upload = \"\"\n                                    , fs::path const& root_temporary = \"\"\n                                    , std::string const& template_ext = get_daqi_HTML_template_ext())\n    {\n        return ApplicationPtr(new Application(name,\n                                              root_url, root_log, root_static,\n                                              root_template, root_upload,\n                                              root_temporary, template_ext));\n    }\n\n    static ApplicationPtr Customize(std::string const& name, std::string const& url\n                                    , AppLocalDiskSetting const& ads)\n    {\n        return Customize(name,\n                         url, ads.log_dir, ads.static_dir,\n                         ads.template_dir, ads.upload_dir,\n                         ads.temporary_dir, ads.template_ext);\n    }\n\n    static ApplicationPtr Abortive();\n\n    Application(Application const&) = delete;\n    Application& operator()(Application const&) = delete;\n\n    ~Application();\n\n    bool Init(AppLoggerSetting const& logger_setting, std::string const& template_ext = \"\")\n    {\n        return Init(logger_setting.level\n                    , logger_setting.max_log_file_size_kb, logger_setting.max_log_file_count, template_ext);\n    }\n\n    bool Init(log::Level level, std::string const& template_ext)\n    {\n        return Init(level\n                    , AppLoggerSetting::default_max_log_file_size_kb, AppLoggerSetting::default_max_log_file_count\n                    , template_ext);\n    }\n\n    bool Init(log::Level level = AppLoggerSetting::default_log_level,\n              size_t max_log_file_size_kb = AppLoggerSetting::default_max_log_file_size_kb,\n              size_t max_log_file_count = AppLoggerSetting::default_max_log_file_count,\n              std::string const& template_ext = \"\")\n    {\n        return InitLogger(level, max_log_file_size_kb, max_log_file_count)\n               && InitPathes()\n               && InitTemplates(template_ext);\n    }\n\n    bool Init(std::string const& log_root, log::Level level)\n    {\n        return Init(log_root, level, AppLoggerSetting::default_max_log_file_size_kb\n                    , AppLoggerSetting::default_max_log_file_count);\n    }\n\n    bool Init(std::string const& log_root, log::Level level = AppLoggerSetting::default_log_level,\n              size_t max_log_file_size_kb = AppLoggerSetting::default_max_log_file_size_kb,\n              size_t max_log_file_count = AppLoggerSetting::default_max_log_file_count)\n    {\n        return InitLogger(log_root, level, max_log_file_size_kb, max_log_file_count)\n               && InitPathes() && InitTemplates();\n    }\n\n    bool InitLogger(std::string const& log_root, AppLoggerSetting const& logger_setting)\n    {\n        return InitLogger(log_root\n                          , logger_setting.level, logger_setting.max_log_file_size_kb\n                          , logger_setting.max_log_file_count);\n    }\n\n    bool InitLogger(std::string const& log_root,\n                    log::Level level = AppLoggerSetting::default_log_level,\n                    size_t max_log_file_size_kb = AppLoggerSetting::default_max_log_file_size_kb,\n                    size_t max_log_file_count = AppLoggerSetting::default_max_log_file_count);\n\n    bool InitLogger(AppLoggerSetting const& logger_setting)\n    {\n        return InitLogger(logger_setting.level, logger_setting.max_log_file_size_kb, logger_setting.max_log_file_count);\n    }\n\n    bool InitLogger(log::Level level = AppLoggerSetting::default_log_level,\n                    size_t max_log_file_size_kb = AppLoggerSetting::default_max_log_file_size_kb,\n                    size_t max_log_file_count = AppLoggerSetting::default_max_log_file_count);\n\n    bool InitPathes();\n    bool InitTemplates(std::string const& template_ext = \"\");\n    void UndesiredTemplates();\n\n#ifdef NDEBUG\n    bool IsAbortive() const\n    {\n        return _is_abortive;\n    }\n#endif\n\n    void Mount()\n    {\n        _mounted = true;\n    }\n\n    bool IsRuning() const\n    {\n        return  _mounted && !_disabled;\n    }\n\n    Application& SetStaticRoot(std::string const& root_static)\n    {\n        _root_static = root_static;\n        return *this;\n    }\n\n    Application& SetLogRoot(std::string const& root_log)\n    {\n        if (!IsRuning() && log::IsNull(_logger))\n        {\n            _root_log = root_log;\n        }\n\n        return *this;\n    }\n\n    Application& SetTemplateRoot(std::string const& root_template)\n    {\n        if (!IsRuning())\n        {\n            _root_template = root_template;\n        }\n\n        return *this;\n    }\n\n    Application& SetTemplateExt(std::string const& template_ext)\n    {\n        if (!IsRuning() && _template_ext != template_ext)\n        {\n            _template_ext = template_ext;\n        }\n\n        return *this;\n    }\n\n    Application& SetTemporaryRoot(std::string const& root_temporary)\n    {\n        if (!IsRuning())\n        {\n            _root_temporary = root_temporary;\n        }\n\n        return *this;\n    }\n\n    Application& SetDefaultCharset(std::string const& charset)\n    {\n        if (!IsRuning())\n        {\n            _default_charset = charset;\n        }\n\n        return *this;\n    }\n\n    Application& SetUploadRoot(std::string const& root_upload)\n    {\n        if (!IsRuning())\n        {\n            _root_upload = root_upload;\n        }\n\n        return *this;\n    }\n\n    std::string const& GetName() const\n    {\n        return _name;\n    }\n\n    std::string const& GetDefaultCharset() const\n    {\n        return _default_charset;\n    }\n\n    std::string const& GetUrlRoot() const\n    {\n        return _root_url;\n    }\n\n    fs::path const& GetLogRoot() const\n    {\n        return _root_log;\n    }\n\n    fs::path const& GetStaticRootPath() const\n    {\n        return _root_static;\n    }\n\n    fs::path const& GetTemplateRoot() const\n    {\n        return _root_template;\n    }\n\n    fs::path const& GetUploadRoot() const\n    {\n        return _root_upload;\n    }\n\n    std::string const& GetTempateExt() const\n    {\n        return _template_ext;\n    }\n\n    bool IsEnable() const\n    {\n        return !_disabled;\n    }\n\n    void Disable();\n    void Enable();\n\n    void CheckUpdate();\n\n    size_t GetUpoadMaxSizeLimitKB() const\n    {\n        return _upload_max_size_limit_kb;\n    }\n\n    void SetUpoadMaxSizeLimitKB(size_t size_limit_kb)\n    {\n        _upload_max_size_limit_kb = size_limit_kb;\n    }\n\n    UploadFileSaveOptions const& GetUploadFileSaveOptions() const\n    {\n        return _upload_file_save_opt;\n    }\n\n    UploadFileSaveOptions& GetUploadFileSaveOptions()\n    {\n        return _upload_file_save_opt;\n    }\n\n    Templates const& GetTemplates() const\n    {\n        return _templates;\n    }\n\n    Templates& GetTemplates()\n    {\n        return _templates;\n    }\n\n    log::LoggerPtr GetLogger()\n    {\n        return _logger;\n    }\n\n    void Handle(Context ctx);\n\npublic:\n    bool AddHandler(HandlerMethod m, std::string const& url, Handler h, std::string const& t = \"\")\n    {\n        return AddHandler(m, router_equals(url), h, t);\n    }\n\n    bool AddHandler(HandlerMethod m, router_equals r, Handler h, std::string const& t = \"\");\n    bool AddHandler(HandlerMethod m, router_starts r, Handler h, std::string const& t = \"\");\n    bool AddHandler(HandlerMethod m, router_regex r, Handler h, std::string const& t = \"\");\n\n    bool AddHandler(HandlerMethods ms, std::string const& url, Handler h, std::string const& t = \"\")\n    {\n        return AddHandler(ms, router_equals(url), h, t);\n    }\n    bool AddHandler(HandlerMethods ms, router_equals e, Handler h, std::string const& t = \"\");\n    bool AddHandler(HandlerMethods ms, router_starts e, Handler h, std::string const& t = \"\");\n    bool AddHandler(HandlerMethods ms, router_regex e, Handler h, std::string const& t = \"\");\n\n    bool AddEqualsRouter(HandlerMethod m, std::vector<std::string> const& urls, Handler h\n                         , std::string const& t = \"\");\n    bool AddStartsRouter(HandlerMethod m, std::vector<std::string> const& urls, Handler h\n                         , std::string const& t = \"\");\n    bool AddRegexRouter(HandlerMethod m, std::vector<std::string> const& urls, Handler h\n                        , std::string const& t = \"\");\n\npublic:\n    bool AddIntercepter(Intercepter::Handler intercepter);\n\n    std::pair<Intercepter::ChainIterator, Intercepter::ChainIterator>\n    GetIntercepterChainRange()\n    {\n        return { _intercepters.begin(), _intercepters.end() };\n    }\n\npublic:\n    std::vector<UniformItem> GetEqualsRouterUniformItems() const;\n    std::vector<UniformItem> GetStartsRouterUniformItems() const;\n    std::vector<UniformRegexItem> GetRegexRouterUniformItems() const;\n\npublic:\n    bool RegistWebSocket(std::string const& url, UrlFlag urlflag, Websocket::EventHandlersFactory factory);\n    bool IsWebSocketRegistered(std::string const& url, UrlFlag urlflag) const;\n\n    std::unique_ptr<Websocket::EventsHandler> CreateWebSocketHandler(std::string const& url, UrlFlag urlflag);\npublic:\n    void AddWebSocketConnection(Websocket::Connection::Ptr connection);\n    Websocket::Connection::Ptr WebsocketConnection(std::string const& url, UrlFlag urlflag, std::string const& id);\n    bool RemoveWebSocketConnection(std::string const& url, UrlFlag urlflag, std::string const& id);\n    bool RenameWebSocketConnectionID(std::string const& url, UrlFlag urlflag\n                                     , std::string const& old_id, std::string const& new_id);\n\n    std::list<Websocket::Connection::Ptr> AllWebSocketConnections(std::string const& url, UrlFlag urlflag);\n    std::list<std::string> AllWebSocketConnectionsID(std::string const& url_full, UrlFlag urlflag);\n\nprivate:\n    void default_init();\n    void default_init_pathes();\n    void default_init_logger();\n    void default_init_templates();\n\nprivate:\n    Handler* find_handler(const Context& ctx, bool& url_exists, bool& unsupport_method\n                          , std::string const& retry_path = \"\");\n    void do_handle(Context& ctx);\n\nprivate:\n    EqualsRoutingTable _equalRouter;\n    StartsWithRoutingTable _startwithsRouter;\n    RegexMatchRoutingTable _regexRouter;\n\nprivate:\n    bool _disabled = false;\n    bool _mounted = false;\n\n    std::string _name;\n    std::string _default_charset = \"UTF-8\";\n\n    std::string _root_url;\n    fs::path _root_log;\n    fs::path _root_static;\n    fs::path _root_template;\n    fs::path _root_upload;\n    fs::path _root_temporary;\n    std::string _template_ext;\n\n    size_t _upload_max_size_limit_kb = 1 * 1024 * 1024;\n\n    Templates _templates;\n\n    UploadFileSaveOptions _upload_file_save_opt;\n\nprivate:\n    Intercepter::Chain _intercepters;\n\nprivate:\n    log::LoggerPtr _logger = log::Null();\n\n#ifdef NDEBUG\n    bool _is_abortive = false;\n#endif\n\nprivate:\n    std::map<std::string /* url-full */, Websocket::EventHandlersFactory> _websocket_handlers_factory;\n\nprivate:\n    std::mutex _m_4_websocket_connections;\n    std::map <std::string /* url-full */, Websocket::Connections> _websocket_connections;\n};\n\nusing ApplicationPtr = std::shared_ptr<Application>;\n\nusing ApplicationMap = std::map<std::string /* url */\n                       , ApplicationPtr, Utilities::IgnoreCaseCompareDESC>;\n\nclass ApplicationMgr\n{\npublic:\n    ApplicationMgr() = default;\n    ApplicationMgr(ApplicationMgr const&) = delete;\n    ApplicationMgr& operator = (ApplicationMgr&) = delete;\n\n    void CreateDefault(std::string const& app_name = \"\");\n    bool MountApplication(ApplicationPtr app);\n\n    void Enable(std::string const& name);\n    void Disable(std::string const& name);\n\n    bool IsExists(std::string const& name) const;\n    bool IsEnable(std::string const& name) const;\n\n    ApplicationPtr FindByURL(std::string const& url);\n\n    ApplicationPtr FindByName(std::string const& name);\n    ApplicationPtr const FindByName(std::string const& name) const;\n\n    log::LoggerPtr GetApplicationLogger(std::string const& application_name);\n\n    ApplicationMap const& All() const\n    {\n        return _map;\n    }\n\n    void Mount();\n    void CheckTemplatesUpdate();\n\n    bool IsEmpty() const\n    {\n        return _map.empty();\n    }\n    size_t Count() const\n    {\n        return _map.size();\n    }\n\n    bool IsFailedApp(ApplicationPtr ptr)\n    {\n#ifdef NDEBUG\n        return _abortive_app == ptr;\n#else\n        return false;\n#endif\n    }\n\n    static void InitAbortiveAppLogRoot(std::string const& log_path);\n    static std::string const& GetAbortiveAppLogRoot();\n\nprivate:\n#ifdef NDEBUG\n    ApplicationPtr _abortive_app = Application::Abortive();\n#endif\n\n    ApplicationMap _map;\n    bool _mounted = false;\n\n    using ApplicationLoggerMap = std::map<std::string /* name */, log::LoggerPtr>;\n\n    ApplicationLoggerMap _app_loggers;\n};\n\nApplicationMgr& AppMgr();\n\nvoid AddDa4Qi4DefaultHandler(ApplicationPtr app);\n\n} // namespace da4qi4\n\n#endif // DAQI_APPLICATION_HPP\n"
  },
  {
    "path": "include/daqi/client/connection_client.hpp",
    "content": "#ifndef DAQI_CLIENT_CONNECTION_HPP\n#define DAQI_CLIENT_CONNECTION_HPP\n\n#include <memory>\n#include <boost/asio/ssl/stream.hpp>\n\n#include \"llhttp/llhttp.h\"\n\n#include \"daqi/def/def.hpp\"\n\n#include \"daqi/net-detail/net_detail_client.hpp\"\n\n#include \"daqi/utilities/http_utilities.hpp\"\n#include \"daqi/utilities/string_utilities.hpp\"\n#include \"daqi/utilities/html_utilities.hpp\"\n\nnamespace da4qi4\n{\nnamespace Client\n{\n\nclass Connection final\n{\n    typedef llhttp_t http_parser;\n    typedef llhttp_settings_t http_parser_settings;\n\n    Connection(IOC& ioc, std::string const& server);\n    Connection(IOC& ioc, std::string const& server, std::string const& service);\n    Connection(IOC& ioc, std::string const& server, unsigned short port);\n\n    Connection(IOC& ioc, boost::asio::ssl::context& ctx, std::string const& server);\n    Connection(IOC& ioc, boost::asio::ssl::context& ctx, std::string const& server\n               , std::string const& service);\n    Connection(IOC& ioc, boost::asio::ssl::context& ctx, std::string const& server\n               , unsigned short port);\n\npublic:\n    typedef std::unique_ptr<Connection> Ptr;\n\n    static Ptr Create(IOC& ioc, std::string const& server)\n    {\n        return Ptr(new Connection(ioc, server));\n    }\n\n    static Ptr Create(IOC& ioc, std::string const& server, std::string const& service)\n    {\n        return Ptr(new Connection(ioc, server, service));\n    }\n\n    static Ptr Create(IOC& ioc, std::string const& server, unsigned short port)\n    {\n        return Ptr(new Connection(ioc, server, port));\n    }\n\n    static Ptr Create(IOC& ioc, boost::asio::ssl::context& ctx, std::string const& server)\n    {\n        return Ptr(new Connection(ioc, ctx, server));\n    }\n\n    static Ptr Create(IOC& ioc, boost::asio::ssl::context& ctx, std::string const& server\n                      , std::string const& service)\n    {\n        return Ptr(new Connection(ioc, ctx, server, service));\n    }\n\n    Ptr Create(IOC& ioc, boost::asio::ssl::context& ctx, std::string const& server\n               , unsigned short port)\n    {\n        return Ptr(new Connection(ioc, ctx, server, port));\n    }\n\n    Connection(const Connection&) = delete;\n    Connection& operator=(const Connection&) = delete;\n\n    ~Connection();\n\npublic:\n    enum class Error {on_none = 0,\n                      on_resolver,\n                      on_connect,\n                      on_write,\n                      on_read,\n                      on_close\n                     };\n\npublic:\n    Connection& SetMethod(std::string const& method, std::string const& uri);\n    Connection& SetHTTPVersion(std::string const& version);\n\n    Connection& ResetHeaders();\n    Connection& AddHeader(std::string const& name, std::string const& value);\n\n    enum class BodySetAction {none, reset_content_length};\n    Connection& SetBody(std::string body\n                        , BodySetAction action = BodySetAction::none);\n\n    using NotifyFunction = std::function<void (errorcode const&)>;\n\npublic:\n    void Connect(NotifyFunction notify);\n\n    void Write(NotifyFunction notify);\n    void Write(std::string const& body, NotifyFunction notify)\n    {\n        SetBody(body);\n        Write(notify);\n    }\n\n    void Read(NotifyFunction notify);\n\n    enum class ActionAfterRequest { keep_connection, close_connection };\n    void Request(NotifyFunction notify\n                 , ActionAfterRequest action = ActionAfterRequest::keep_connection);\npublic:\n    bool ConnectSync();\n    bool WriteSync(std::size_t& bytes_transferred);\n    bool ReadSync(std::size_t& bytes_transferred);\n    bool RequestSync(std::size_t& bytes_wrote, std::size_t& bytes_read\n                     , ActionAfterRequest action = ActionAfterRequest::keep_connection);\n\n    bool RequestSync(ActionAfterRequest action = ActionAfterRequest::keep_connection)\n    {\n        std::size_t w(0), r(0);\n        return RequestSync(w, r, action);\n    }\n\npublic:\n    void Reset();\n    void Close();\n\npublic:\n    IOC& GetIOC()\n    {\n        return _ioc;\n    }\n\n    bool IsWithSSL() const\n    {\n        return _with_ssl;\n    }\n\n    std::string const& GetServer() const\n    {\n        return  _server;\n    }\n\n    Tcp::endpoint const& GetServerAddress() const\n    {\n        return _server_endpoint;\n    }\n\n    std::string const& GetRequestMedthod() const\n    {\n        return _method;\n    }\n    std::string const& GetRequestURI() const\n    {\n        return _uri;\n    }\n    std::string const& GetRequestHTTPVersion() const\n    {\n        return  _http_version;\n    }\n\n    ICHeaders const& GetRequestHeaders() const\n    {\n        return _request_headers;\n    }\n    std::string const& GetRequestBody() const\n    {\n        return _request_body;\n    }\n\n    ICHeaders const& GetResponseHeaders() const\n    {\n        return _response_headers;\n    }\n    std::string const& GetResponseBody() const\n    {\n        return _response_body;\n    }\n\n    bool HasError() const\n    {\n        return _error != Error::on_none;\n    }\n\n    Error GetError() const\n    {\n        return this->_error;\n    }\n\n    std::string const& GetErrorMessage() const\n    {\n        return this->_error_msg;\n    }\n\n    unsigned int GetResponseStatusCode() const\n    {\n        return (_parser != nullptr) ? _parser->status_code : 0;\n    }\n\n    std::string const& GetResponseStatus() const\n    {\n        return _status_buffer;\n    }\n\nprivate:\n    std::string make_request_buffer();\n\n    void do_resolver(NotifyFunction notify);\n    void do_connect(NotifyFunction notify);\n\n    void do_write(NotifyFunction notify);\n    void do_read(NotifyFunction notify);\n\n    errorcode do_resolver();\n    errorcode do_connect();\n    errorcode do_write(std::size_t& bytes_transferred);\n    errorcode do_read(std::size_t& bytes_transferred);\n\n    void do_close();\n\nprivate:\n    void init();\n    void init_parser();\n    void init_parser_setting();\n\n    static int on_header_field(http_parser* parser, char const* at, size_t length);\n    static int on_header_value(http_parser* parser, char const* at, size_t length);\n    static int on_headers_complete(http_parser* parser);\n\n    void try_commit_reading_response_header();\n\n    static int on_message_begin(http_parser* parser);\n    static int on_message_complete(http_parser* parser);\n\n    static int on_status(http_parser* parser, char const* at, size_t length);\n    static int on_body(http_parser* parser, char const* at, size_t length);\n\nprivate:\n    void reset();\n\nprivate:\n    bool _with_ssl;\n    IOC& _ioc;\n    Tcp::resolver _resolver;\n    net_detail::SocketBase* _socket_ptr;\n\n    size_t _ioc_index;\n    net_detail::ReadBuffer _read_buffer;\n\n    bool _is_connected = false;\nprivate:\n    http_parser* _parser;\n    http_parser_settings _parser_setting;\n\n    enum ReadingHeaderPart {header_none_part, header_field_part, header_value_part};\n    ReadingHeaderPart  _reading_header_part = header_none_part;\n    std::string _reading_header_field;\n    std::string _reading_header_value;\n\n    enum ReadCompletePart {read_none_complete,\n                           read_header_complete,\n                           read_message_complete\n                          };\n\n    ReadCompletePart _read_complete = read_none_complete;\n\nprivate:\n    std::string _server;\n    std::string _service;\n    Tcp::endpoint _server_endpoint;\n\n    std::string _method;\n    std::string _uri;\n    std::string _http_version;\n\n    ICHeaders _request_headers;\n    std::string _request_body;\n\n    std::string _url_buffer;\n    std::string _status_buffer;\n    ICHeaders _response_headers;\n    std::string _response_body;\n\nprivate:\n    Error _error;\n    std::string _error_msg;\n\n    NotifyFunction _notify;\n};\n\n} // namespace Client\n} // namespace da4qi4\n\n#endif // DAQI_CLIENT_CONNECTION_HPP\n"
  },
  {
    "path": "include/daqi/connection.hpp",
    "content": "#ifndef DAQI_CONNECTION_HPP\n#define DAQI_CONNECTION_HPP\n\n#include <memory>\n#include <string>\n\n#include \"llhttp/llhttp.h\"\n#include \"multipart-parser/multipart_parser.h\"\n\n#include \"daqi/request.hpp\"\n#include \"daqi/response.hpp\"\n#include \"daqi/handler.hpp\"\n\n#include \"daqi/net-detail/net_detail_server.hpp\"\n\nnamespace da4qi4\n{\n\nclass Application;\n\nclass Connection\n    : public std::enable_shared_from_this<Connection>\n{\n    typedef llhttp_t http_parser;\n    typedef llhttp_settings_t http_parser_settings;\n\n    explicit Connection(IOC& ioc, size_t ioc_index);\n    explicit Connection(IOC& ioc, size_t ioc_index, boost::asio::ssl::context& ssl_ctx);\n\npublic:\n    static ConnectionPtr Create(IOC& ioc, size_t ioc_index)\n    {\n        return ConnectionPtr(new Connection(ioc, ioc_index));\n    }\n\n    static ConnectionPtr Create(IOC& ioc, size_t ioc_index, boost::asio::ssl::context& ssl_ctx)\n    {\n        return ConnectionPtr(new Connection(ioc, ioc_index, ssl_ctx));\n    }\n\n    Connection(const Connection&) = delete;\n    Connection& operator=(const Connection&) = delete;\n\npublic:\n    void Start();\n    void StartRead();\n    void StartWrite();\n    void Stop();\n\npublic:\n    Request const& GetRequest() const\n    {\n        return _request;\n    }\n    Request& GetRequest()\n    {\n        return _request;\n    }\n\n    Response& GetResponse()\n    {\n        return _response;\n    }\n    Response const& GetResponse() const\n    {\n        return _response;\n    }\n\n    bool HasApplication() const\n    {\n        return _app != nullptr;\n    }\n\n    std::shared_ptr<Application> GetApplication();\n\n    size_t GetIOContextIndex() const\n    {\n        return _ioc_index;\n    }\n\npublic:\n    Tcp::socket& GetSocket()\n    {\n        return _socket_ptr->get_socket();\n    }\n\n    bool IsWithSSL() const\n    {\n        return _with_ssl;\n    }\n\nprivate:\n    void do_handshake();\n\n    void do_read();\n    void do_write();\n    void do_close();\n\n    void do_write_header_for_chunked();\n    void do_write_next_chunked_body(clock_t start_wait_clock = 0);\n    void do_write_chunked_body_finished(errorcode const& ec, size_t bytes_transferred);\n\n    void do_upgrade();\nprivate:\n    void init_parser();\n    void init_parser_setting();\n\n    static int on_header_field(http_parser* parser, char const* at, size_t length);\n    static int on_header_value(http_parser* parser, char const* at, size_t length);\n    static int on_headers_complete(http_parser* parser);\n\n    static int on_message_begin(http_parser* parser);\n    static int on_message_complete(http_parser* parser);\n\n    static int on_url(http_parser* parser, char const* at, size_t length);\n    static int on_body(http_parser* parser, char const* at, size_t length);\n\nprivate:\n    static int on_multipart_header_field(multipart_parser* parser, char const* at, size_t length);\n    static int on_multipart_header_value(multipart_parser* parser, char const* at, size_t length);\n    static int on_multipart_headers_complete(multipart_parser* parser);\n\n    static int on_multipart_data_begin(multipart_parser* parser);\n    static int on_multipart_data(multipart_parser* parser, char const* at, size_t length);\n    static int on_multipart_data_end(multipart_parser* parser);\n    static int on_multipart_body_end(multipart_parser* parser);\n\nprivate:\n    void update_request_after_header_parsed();\n    void update_request_url_after_app_resolve();\n\n    void try_commit_reading_request_header();\n    void process_100_continue_request();\n    void process_app_no_found();\n    void process_too_large_size_upload();\n\n    void try_fix_multipart_bad_request_without_boundary();\n    void try_init_multipart_parser();\n\n    enum MultpartParseStatus { mp_cannot_init = -1, mp_parsing = 0,  mp_parse_fail = 1};\n    MultpartParseStatus do_multipart_parse();\n\n    bool try_route_application();\n\nprivate:\n    void prepare_response_headers_about_connection();\n    void prepare_response_headers_for_chunked_write();\n    void reset();\n\nprivate:\n    bool _with_ssl;\n    std::unique_ptr<net_detail::SocketInterface> _socket_ptr;\n\n    size_t _ioc_index;\n\nprivate:\n    std::unique_ptr<http_parser> _parser;\n    http_parser_settings _parser_setting;\n\n    std::string  _url_buffer;\n\n    enum ReadingHeaderPart {header_none_part, header_field_part, header_value_part};\n    ReadingHeaderPart  _reading_header_part = header_none_part;\n    std::string _reading_header_field;\n    std::string _reading_header_value;\n\n    std::string _body_buffer;\n\n    enum ReadCompletePart {read_none_complete,\n                           read_header_complete,\n                           read_message_complete\n                          };\n\n    ReadCompletePart _read_complete = read_none_complete;\n\nprivate:\n    enum MultipartParsePart {mp_parse_none,\n                             mp_parse_header_field, mp_parse_header_value, mp_parse_headers_complete,\n                             mp_parse_data_begin, mp_parse_data, mp_parse_data_end, mp_parse_body_end\n                            };\n\n    void init_multipart_parser(std::string const& boundary);\n    enum mp_free_flag  {will_free_mp_setting = 1, will_free_mp_parser = 2, will_free_mp_both = 3 };\n    void free_multipart_parser(mp_free_flag flag = will_free_mp_both);\n\n    std::unique_ptr<multipart_parser_settings> _mp_parser_setting;\n    typedef void (* multipart_parser_deleter_t)(multipart_parser*);\n    std::unique_ptr<multipart_parser, multipart_parser_deleter_t> _mp_parser;\n\n    MultiPart _reading_part;\n    std::string _reading_part_buffer;\n    MultipartParsePart _multipart_parse_part = mp_parse_none;\n\n    net_detail::ReadBuffer _buffer;\n    net_detail::WriteBuffer _write_buffer;\n    net_detail::ChunkedBuffer _current_chunked_body_buffer;\nprivate:\n    Request _request;\n    Response _response;\n    std::shared_ptr<Application> _app;\n};\n\n} //namespace da4qi4\n\n#endif // DAQI_CONNECTION_HPP\n"
  },
  {
    "path": "include/daqi/context.hpp",
    "content": "#ifndef DAQI_CONTEXT_HPP\n#define DAQI_CONTEXT_HPP\n\n#include <memory>\n#include <functional>\n#include <list>\n\n#include \"daqi/def/def.hpp\"\n#include \"daqi/def/asio_def.hpp\"\n#include \"daqi/def/json_def.hpp\"\n\n#include \"daqi/request.hpp\"\n#include \"daqi/response.hpp\"\n#include \"daqi/templates.hpp\"\n#include \"daqi/intercepter.hpp\"\n#include \"daqi/rediscli_pool.hpp\"\n\nnamespace da4qi4\n{\n\nclass Connection;\nusing ConnectionPtr = std::shared_ptr<Connection>;\n\nclass ContextIMP;\nusing Context = std::shared_ptr<ContextIMP>;\n\nclass Application;\n\nclass ContextIMP\n    : public std::enable_shared_from_this<ContextIMP>\n{\n    ContextIMP(ConnectionPtr cnt);\npublic:\n    static Context Make(ConnectionPtr cnt);\n    ~ContextIMP();\n\n    ContextIMP(ContextIMP const&) = delete;\n    ContextIMP& operator = (ContextIMP const&) = delete;\n\n    Request const& Req() const;\n    Response& Res();\n\n    std::string const& Req(std::string const& name) const\n    {\n        return Req().GetParameter(name);\n    }\n\n    Application& App();\n    Application const& App() const;\n\n    Json const& Data(std::string const& name) const\n    {\n        Json::const_iterator it = _data.find(name);\n\n        if (it == _data.cend())\n        {\n            return theNullJson;\n        }\n\n        return *it;\n    }\n\n    Json& Data(std::string const& name)\n    {\n        auto it = _data.find(name);\n\n        if (it != _data.end())\n        {\n            return *it;\n        }\n\n        _data[name] = Json();\n        return _data[name];\n    }\n\n    Json const& LoadData(std::string const& name) const\n    {\n        return Data(name);\n    }\n\n    void SaveData(std::string const& name, Json const& data)\n    {\n        _data[name] = data;\n    }\n\n    void RemoveData(std::string const& name)\n    {\n        auto it = _data.find(name);\n\n        if (it != _data.end())\n        {\n            _data.erase(it);\n        }\n    }\n\n    Json& ModelData()\n    {\n        return Data(model_data_name);\n    }\n\n    Json const& ModelData() const\n    {\n        return Data(model_data_name);\n    }\n\n    Json const& LoadModelData() const\n    {\n        return LoadData(model_data_name);\n    }\n\n    void SaveModelData(Json const& data)\n    {\n        SaveData(model_data_name, data);\n    }\n\n    Json& SessionData()\n    {\n        return Data(session_data_name);\n    }\n\n    Json const& SessionData() const\n    {\n        return Data(session_data_name);\n    }\n\n    Json LoadSessionData() const\n    {\n        return LoadData(session_data_name);\n    }\n\n    void SaveSessionData(Json const& data)\n    {\n        SaveData(session_data_name, data);\n    }\n\n    void ClearSessionData();\n\n    std::string GetSessionID() const;\n    Cookie GetSessionCookie() const;\n\n    static std::string const& ModelDataName()\n    {\n        return model_data_name;\n    }\n\n    static std::string const& SessionDataName()\n    {\n        return session_data_name;\n    }\n\n    IOC& IOContext();\n    size_t IOContextIndex() const;\n\n    log::LoggerPtr Logger()\n    {\n        return logger();\n    }\n\npublic:\n    std::string const& GetTemplateName() const\n    {\n        return _template_name;\n    }\n\n    void SetTemplateName(std::string const& template_name)\n    {\n        _template_name = template_name;\n    }\n\n    void ClearTemplateName()\n    {\n        _template_name.clear();\n    }\n\npublic:\n    void InitRequestPathParameters(std::vector<std::string> const& names\n                                   , std::vector<std::string> const& values);\n\n    void InitRequestPathParameter(std::string const& value);\npublic:\n    ContextIMP& Render();\n    ContextIMP& Render(Json const& data);\n    ContextIMP& Render(char const* template_name, Json const& data = theNullJson)\n    {\n        return (template_name && *template_name) ? Render(std::string(template_name), data) : Render(data);\n    }\n    ContextIMP& Render(std::string const& template_name, Json const& data = theNullJson);\n    ContextIMP& Render(http_status status, Json const& data);\n    ContextIMP& Render(std::string const& template_name, http_status status, Json const& data = theNullJson);\n\n    ContextIMP& RenderWithoutData(http_status status)\n    {\n        return render_with_data(status, theNullJson);\n    }\n    ContextIMP& RenderWithoutData(std::string const& template_name)\n    {\n        return render_with_data(template_name, theNullJson);\n    }\n    ContextIMP& RenderWithoutData(std::string const& template_name, http_status status)\n    {\n        return render_with_data(template_name, status, theNullJson);\n    }\n    ContextIMP& RenderWithoutData()\n    {\n        return render_with_data(theNullJson);\n    }\n\npublic:\n    ContextIMP& RenderNofound(Json const& data = theNullJson)\n    {\n        return render_with_data(HTTP_STATUS_NOT_FOUND, data);\n    }\n    ContextIMP& RenderNofound(std::string const& template_name, Json const& data = theNullJson)\n    {\n        return render_with_data(template_name, HTTP_STATUS_NOT_FOUND, data);\n    }\n    ContextIMP& RenderNofound(char const* const template_name, Json const& data = theNullJson)\n    {\n        return render_with_data(std::string(template_name), HTTP_STATUS_NOT_FOUND, data);\n    }\n\n    ContextIMP& RenderBadRequest(Json const& data = theNullJson)\n    {\n        return render_with_data(HTTP_STATUS_BAD_REQUEST, data);\n    }\n    ContextIMP& RenderBadRequest(std::string const& template_name, Json const& data = theNullJson)\n    {\n        return render_with_data(template_name, HTTP_STATUS_BAD_REQUEST, data);\n    }\n    ContextIMP& RenderBadRequest(char const* const template_name, Json const& data = theNullJson)\n    {\n        return render_with_data(std::string(template_name), HTTP_STATUS_BAD_REQUEST, data);\n    }\n\n    ContextIMP& RenderUnauthorized(Json const& data = theNullJson)\n    {\n        return render_with_data(HTTP_STATUS_UNAUTHORIZED, data);\n    }\n    ContextIMP& RenderUnauthorized(std::string const& template_name, Json const& data = theNullJson)\n    {\n        return render_with_data(template_name, HTTP_STATUS_UNAUTHORIZED, data);\n    }\n    ContextIMP& RenderUnauthorized(char const* const template_name, Json const& data = theNullJson)\n    {\n        return render_with_data(std::string(template_name), HTTP_STATUS_UNAUTHORIZED, data);\n    }\n\n    ContextIMP& RenderForbidden(Json const& data = theNullJson)\n    {\n        return render_with_data(HTTP_STATUS_FORBIDDEN, data);\n    }\n    ContextIMP& RenderForbidden(std::string const& template_name, Json const& data = theNullJson)\n    {\n        return render_with_data(template_name, HTTP_STATUS_FORBIDDEN, data);\n    }\n    ContextIMP& RenderForbidden(char const* const template_name, Json const& data = theNullJson)\n    {\n        return render_with_data(std::string(template_name), HTTP_STATUS_FORBIDDEN, data);\n    }\n\n    ContextIMP& RenderNotImplemented(Json const& data = theNullJson)\n    {\n        return render_with_data(HTTP_STATUS_NOT_IMPLEMENTED, data);\n    }\n    ContextIMP& RenderNotImplemented(std::string const& template_name, Json const& data = theNullJson)\n    {\n        return render_with_data(template_name, HTTP_STATUS_NOT_IMPLEMENTED, data);\n    }\n    ContextIMP& RenderNotImplemented(char const* const template_name, Json const& data = theNullJson)\n    {\n        return render_with_data(std::string(template_name), HTTP_STATUS_NOT_IMPLEMENTED, data);\n    }\n\n    ContextIMP& RenderServiceUnavailable(Json const& data = theNullJson)\n    {\n        return render_with_data(HTTP_STATUS_SERVICE_UNAVAILABLE, data);\n    }\n    ContextIMP& RenderServiceUnavailable(std::string const& template_name, Json const& data = theNullJson)\n    {\n        return render_with_data(template_name, HTTP_STATUS_SERVICE_UNAVAILABLE, data);\n    }\n    ContextIMP& RenderServiceUnavailable(char const* const template_name, Json const& data = theNullJson)\n    {\n        return render_with_data(std::string(template_name), HTTP_STATUS_SERVICE_UNAVAILABLE, data);\n    }\n\n    ContextIMP& RenderInternalServerError(Json const& data = theNullJson)\n    {\n        return render_with_data(HTTP_STATUS_INTERNAL_SERVER_ERROR, data);\n    }\n    ContextIMP& RenderInternalServerError(std::string const& template_name, Json const& data = theNullJson)\n    {\n        return render_with_data(template_name, HTTP_STATUS_INTERNAL_SERVER_ERROR, data);\n    }\n    ContextIMP& RenderInternalServerError(char const* const template_name, Json const& data = theNullJson)\n    {\n        return render_with_data(std::string(template_name), HTTP_STATUS_INTERNAL_SERVER_ERROR, data);\n    }\n\npublic:\n    ContextIMP&  Redirect(std::string const& dst_location)\n    {\n        this->Res().ReplyRedirect(dst_location);\n        return *this;\n    }\n\npublic:\n    bool HasRedis() const\n    {\n        return _redis != nullptr;\n    }\n\n    RedisClientPtr Redis()\n    {\n        return _redis;\n    }\n\npublic:\n    void Start();\n    void Pass();\n    void Stop();\n\npublic:\n    void StartChunkedResponse();\n    void NextChunkedResponse(std::string const& body);\n    void StopChunkedResponse();\n\nprivate:\n    ContextIMP& render_with_data(std::string const& template_name, http_status status, Json const& data);\n    ContextIMP& render_with_data(http_status status, Json const& data);\n    ContextIMP& render_with_data(std::string const& template_name, Json const& data);\n    ContextIMP& render_with_data(Json const& data);\n\nprivate:\n    void do_intercepter_on_req_dir();\n    void do_intercepter_on_res_dir();\n\n    void next(Intercepter::Result result);\n    void next_intercepter_on_req_dir(Intercepter::Result result);\n    void start_intercepter_on_res_dir(Intercepter::Result result);\n    void next_intercepter_on_res_dir(Intercepter::Result result);\n\nprivate:\n    void end();\n\nprivate:\n    log::LoggerPtr logger();\n\nprivate:\n    using Self = ContextIMP;\n    typedef std::string const& (Self::*PSSFun)(std::string const&) const;\n    void regist_string_function_with_one_string_parameter(char const* function_name,\n                                                          PSSFun func,\n                                                          std::string defaultValue = Utilities::theEmptyString);\n\n    typedef bool (Self::*PBSFun)(std::string const&) const;\n    void regist_bool_function_with_one_string_parameter(char const* function_name,\n                                                        PBSFun func, bool defaultValue = false);\n\nprivate:\n    void render_on_template(std::string const& templ_name, Template const& templ, Json const& data, http_status status);\n    std::string render_on_template(std::string const& templ_name, Template const& templ, Json const& data\n                                   , bool& server_render_error\n                                   , std::string& error_what);\n\n    void regist_template_enginer_common_functions();\n\n    std::string const& parameter(std::string const& name) const\n    {\n        return this->Req().GetParameter(name);\n    }\n\n    bool is_exists_parameter(std::string const& name) const\n    {\n        return this->Req().IsExistsParameter(name);\n    }\n\n    std::string const& header(std::string const& field) const\n    {\n        return this->Req().GetHeader(field);\n    }\n\n    bool is_exists_header(std::string const& field) const\n    {\n        return this->Req().IsExistsHeader(field);\n    }\n\n    std::string const& url_parameter(std::string const& name) const\n    {\n        return this->Req().GetUrlParameter(name);\n    }\n\n    bool is_exists_url_parameter(std::string const& name) const\n    {\n        return this->Req().IsExistsUrlParameter(name);\n    }\n\n    std::string const& path_parameter(std::string const& name) const\n    {\n        return this->Req().GetPathParameter(name);\n    }\n\n    bool is_exists_path_parameter(std::string const& name) const\n    {\n        return this->Req().IsExistsPathParameter(name);\n    }\n\n    std::string const& form_data(std::string const& name) const\n    {\n        return this->Req().GetFormData(name);\n    }\n\n    bool is_exists_form_data(std::string const& name) const\n    {\n        return this->Req().IsExistsFormData(name);\n    }\n\n    std::string const& cookie(std::string const& name) const\n    {\n        return this->Req().GetCookie(name);\n    }\n\n    bool is_exists_cookie(std::string const& name) const\n    {\n        return this->Req().IsExistsCookie(name);\n    }\n\n    void prepair_template_env();\n    std::string auto_match_template();\n\nprivate:\n    ConnectionPtr _cnt;\n\n    Json _data;\n    TemplatesEnv _env; //every context has it's templats env;\n\n    Intercepter::On _intercepter_on;\n    Intercepter::ChainIterator  _intercepter_iter;\n    Intercepter::ChainIterator _intercepter_beg, _intercepter_end;\n\n    RedisClientPtr _redis;\n\n    std::string _template_name;\nprivate:\n    static std::string session_data_name;\n    static std::string model_data_name;\n};\n\n\n} //namespace da4qi4\n\n\n#endif // DAQI_CONTEXT_HPP\n"
  },
  {
    "path": "include/daqi/cookie.hpp",
    "content": "#ifndef DAQI_COOKIE_HPP\n#define DAQI_COOKIE_HPP\n\n#include <ctime>\n\n#include <iostream>\n#include <string>\n#include <limits>\n\n#include \"daqi/def/json_def.hpp\"\n\nnamespace da4qi4\n{\nstruct Cookie\n{\n    enum class HttpOnly {for_http_and_js = 0, for_http_only = 1};\n    enum class Secure {for_http_and_https = 0, for_https_only = 1};\n    enum class SameSite {none = 0, lax, strict};\n\n    Cookie() = default;\n    Cookie(Cookie const&) = default;\n    Cookie(Cookie&& o)\n    {\n        _old_version = o._old_version;\n\n        _name = std::move(o._name);\n        _value = std::move(o._value);\n        _domain = std::move(o._domain);\n        _path = std::move(o._path);\n\n        _max_age = o.expires_after_brower_close;\n\n        _http_only = o._http_only;\n        _secure = o._secure;\n\n        _samesite = o._samesite;\n    }\n\n    Cookie& operator = (Cookie const& o) = default;\n    Cookie& operator = (Cookie&& o) = default;\n\n    Cookie(std::string const& name, std::string const& value)\n        : _name(name), _value(value)\n    {}\n\n    Cookie(std::string const& name, std::string const& value, std::string const& domain)\n        : _name(name), _value(value), _domain(domain)\n    {}\n\n    Cookie(std::string const& name, std::string const& value\n           , std::string const& domain, std::string const& path)\n        : _name(name), _value(value), _domain(domain), _path(path)\n    {}\n\n    std::string const& GetName() const\n    {\n        return _name;\n    }\n\n    std::string const& GetDomain() const\n    {\n        return _domain;\n    }\n\n    std::string const& GetPath() const\n    {\n        return _path;\n    }\n\n    std::string const& GetValue() const\n    {\n        return _value;\n    }\n\n    Cookie& SetName(std::string const& name)\n    {\n        _name = name;\n        return *this;\n    }\n\n    Cookie& SetValue(std::string const& value)\n    {\n        _name = value;\n        return *this;\n    }\n\n    Cookie& SetDomain(std::string const& domain)\n    {\n        _domain = domain;\n        return *this;\n    }\n\n    Cookie& SetPath(std::string const& path)\n    {\n        _path = path;\n        return *this;\n    }\n\n    Cookie& ApplyHttpVersion(unsigned short http_version_major, unsigned short http_version_minor)\n    {\n        _old_version = ((http_version_major < 1)\n                        || (http_version_major == 1 && http_version_minor == 0));\n        return *this;\n    }\n\n    Cookie& SetHttpOnly(HttpOnly only)\n    {\n        _http_only = only == HttpOnly::for_http_only;\n        return *this;\n    }\n\n    bool IsHttpOnly() const\n    {\n        return _http_only;\n    }\n\n    Cookie& SetMaxAge(int seconds)\n    {\n        _max_age = (seconds >= 0) ? seconds : 0;\n        return *this;\n    }\n\n    int GetMaxAge() const\n    {\n        return _max_age;\n    }\n\n    Cookie& SetExpires(std::time_t a_time_point);\n\n    Cookie& SetExpiredAfterBrowerClose()\n    {\n        _max_age = expires_after_brower_close;\n        return *this;\n    }\n\n    bool IsExpiredAfterBrowerClose() const\n    {\n        return _max_age == expires_after_brower_close;\n    }\n\n    Cookie& SetExpiredImmediately()\n    {\n        _max_age = expires_immediately;\n        return *this;\n    }\n\n    bool IsExpiredImmediately() const\n    {\n        return _max_age == expires_immediately;\n    }\n\n    bool IsOldVersion() const\n    {\n        return _old_version;\n    }\n\n    bool IsSecure() const\n    {\n        return _secure;\n    }\n\n    Cookie& SetSecure(Secure secure)\n    {\n        _secure = (secure == Secure::for_https_only);\n        return *this;\n    }\n\n    SameSite GetSameSite() const\n    {\n        return _samesite;\n    }\n\n    Cookie& SetSameSite(SameSite ss)\n    {\n        _samesite = ss;\n        return *this;\n    }\n\n    void ClearValue()\n    {\n        _value.clear();\n    }\n\n    bool IsEmpty() const\n    {\n        return _name.empty() && _value.empty();\n    }\n\nprivate:\n    enum\n    {\n        expires_after_brower_close = std::numeric_limits<int>::min()\n        , expires_immediately\n    };\n\n    bool _old_version = false;\n\n    std::string _name;\n    std::string _value;\n    std::string _domain;\n    std::string _path;\n    int _max_age = expires_after_brower_close;\n\n    bool _http_only = false;\n    bool _secure = false;\n\n    SameSite _samesite = SameSite::none;\n\n    friend std::ostream& operator << (std::ostream&, Cookie const&);\n    friend void to_json(Json&,  Cookie const&);\n    friend void from_json(Json const&, Cookie&);\n};\n\nstd::ostream& operator << (std::ostream& os, Cookie const& c);\nvoid to_json(Json& j, Cookie const& c);\nvoid from_json(Json const& j, Cookie& c);\n\n\n} //namespace da4qi4\n#endif // DAQI_COOKIE_HPP\n"
  },
  {
    "path": "include/daqi/da4qi4.hpp",
    "content": "#ifndef DAQI_DA4QI4_HPP\n#define DAQI_DA4QI4_HPP\n\n#include \"daqi/def/log_def.hpp\"\n\n#include \"daqi/server.hpp\"\n#include \"daqi/router.hpp\"\n#include \"daqi/application.hpp\"\n\n#endif // DAQI_DA4QI4_HPP\n"
  },
  {
    "path": "include/daqi/def/asio_def.hpp",
    "content": "#ifndef DAQI_ASIO_DEF_HPP\n#define DAQI_ASIO_DEF_HPP\n\n#include <boost/asio.hpp>\n#include <boost/asio/ssl.hpp>\n\nnamespace da4qi4\n{\n\n#ifdef _USE_BOOST_VERSION_GE_1_66_\n    #define HAS_IO_CONTEXT\n    #define HAS_RESOLVER_RESULT\n#endif\n\n#ifdef HAS_IO_CONTEXT\n    using IOC = boost::asio::io_context;\n#else\n    using IOC = boost::asio::io_service;\n#endif\n\nusing Tcp = boost::asio::ip::tcp;\n\n#ifdef HAS_RESOLVER_TYPE_RESULT\n    typedef Tcp::resolver::results_type ResolverResultT;\n#else\n    typedef Tcp::resolver::iterator ResolverResultT;\n#endif\n\ntypedef boost::asio::ssl::context_base SSLContextBase;\n\n}\n\n#endif // DAQI_ASIO_DEF_HPP\n"
  },
  {
    "path": "include/daqi/def/boost_def.hpp",
    "content": "#ifndef DAQI_BOOST_DEF_HPP\n#define DAQI_BOOST_DEF_HPP\n\n#include <string>\n\n#include <boost/optional.hpp>\n#include <boost/filesystem.hpp>\n#include <boost/uuid/uuid.hpp>\n#include <boost/uuid/uuid_io.hpp>\n#include <boost/asio/placeholders.hpp>\n\nnamespace da4qi4\n{\n\nextern boost::none_t NoneObject;\nusing errorcode = boost::system::error_code;\nnamespace fs = boost::filesystem;\n\nusing OptionalString = boost::optional<std::string>;\nusing OptionalStringRef = boost::optional<std::string&>;\nusing OptionalStringRefConst = boost::optional<std::string const&>;\n\nnamespace asio_placeholders = boost::asio::placeholders;\n\n} //namesapce da4qi4\n\n#endif // DAQI_BOOST_DEF_HPP\n"
  },
  {
    "path": "include/daqi/def/debug_def.hpp",
    "content": "#ifndef DAQI_DEBUG_DEF_HPP\n#define DAQI_DEBUG_DEF_HPP\n\n#include <iostream>\n\n#endif // DAQI_DEBUG_DEF_HPP\n"
  },
  {
    "path": "include/daqi/def/def.hpp",
    "content": "#ifndef DAQI_DEF_HPP\n#define DAQI_DEF_HPP\n\n#include <string>\n#include <map>\n#include <functional>\n#include <memory>\n#include <list>\n#include <vector>\n#include <set>\n\n#include \"daqi/utilities/string_utilities.hpp\"\n\nnamespace da4qi4\n{\n\nextern char const* const the_daqi_name;\nextern char const* const the_daqi_version;\n\nenum class CacheControl {Public, Private};\nenum PathResolve {is_relative, is_absolute}; //for url and dist-directory\n\nusing Headers = std::map<std::string, std::string>;\nusing ICHeaders = std::map<std::string, std::string, Utilities::IgnoreCaseCompare>;\nusing ICCookies = ICHeaders;\nusing UrlParameters = std::map<std::string, std::string>;\n\n} //namespace da4qi4\n\n#endif // DAQI_DEF_HPP\n"
  },
  {
    "path": "include/daqi/def/inja_def.hpp",
    "content": "#ifndef DAQI_INJA_DEF_HPP\n#define DAQI_INJA_DEF_HPP\n\n#include <memory>\n\n#include \"inja/inja.hpp\"\n\nnamespace da4qi4\n{\n\nusing Template = inja::Template;\nusing TemplatePtr = std::shared_ptr<Template>;\n\n}\n\n#endif // INJA_DEF_HPP\n"
  },
  {
    "path": "include/daqi/def/json_def.hpp",
    "content": "#ifndef DAQI_JSON_DEF_HPP\n#define DAQI_JSON_DEF_HPP\n\n#include \"nlohmann/json.hpp\"\n\n#include <ctime>\n\nnamespace da4qi4\n{\n\nusing Json = nlohmann::json;\nextern Json const theNullJson;\n\nnamespace Valuetool\n{\n\nextern double const zero_compare_value;\n\nbool is_exists(Json const& j, std::string const& item_name);\nbool is_exists(Json const& j, std::vector<std::string>const& name_pathes);\n\nbool boolean_value(Json const& j, bool default_value = false);\nbool boolean_value(Json const& j, std::string const& item_name, bool default_value = false);\nbool boolean_value(Json const& j, std::vector<std::string>const& name_pathes, bool default_value = false);\n\nint integer_value(Json const& j, int default_value = 0);\nint integer_value(Json const& j, std::string const& item_name, int default_value = 0);\nint integer_value(Json const& j, std::vector<std::string>const& name_pathes, int default_value = 0);\n\nstd::size_t size_value(Json const& j, std::size_t default_value = 0);\nstd::size_t size_value(Json const& j, std::string const& item_name, std::size_t default_value = 0);\nstd::size_t size_value(Json const& j, std::vector<std::string>const& name_pathes, std::size_t default_value = 0);\n\nstd::time_t time_value(Json const& j, std::time_t default_value = 0);\nstd::time_t time_value(Json const& j, std::string const& item_name, std::time_t default_value = 0);\nstd::time_t time_value(Json const& j, std::vector<std::string>const& name_pathes, std::time_t default_value = 0);\n\ndouble double_value(Json const& j, double default_value = 0.0);\ndouble double_value(Json const& j, std::string const& item_name, double default_value = 0.0);\ndouble double_value(Json const& j, std::vector<std::string>const& name_pathes, double default_value = 0.0);\n\nstd::string string_value(Json const& j);\nstd::string string_value(Json const& j, std::string const& item_name\n                         , std::string const& default_value = \"\");\nstd::string string_value(Json const& j, std::vector<std::string>const& name_pathes,\n                         std::string const& default_value = \"\");\n\n} // namespace Valuetool\n\n\n} //namespace da4qi4\n\n#endif // DAQI_JSON_DEF_HPP\n"
  },
  {
    "path": "include/daqi/def/log_def.hpp",
    "content": "#ifndef DAQI_LOG_DEF_HPP\n#define DAQI_LOG_DEF_HPP\n\n#include <memory>\n\n#include \"spdlog/spdlog.h\"\n#include \"spdlog/sinks/stdout_sinks.h\"\n#include \"spdlog/sinks/file_sinks.h\"\n\nnamespace da4qi4\n{\nnamespace log\n{\n\nusing Level = spdlog::level::level_enum;\nusing LoggerPtr = std::shared_ptr<spdlog::logger>;\n\nbool InitLogger(std::string const& name\n                , std::string const& server_name\n                , std::string& error\n                , std::string const& log_dir, Level level = Level::info\n                , size_t max_file_size_kb = 5 * 1024\n                , size_t max_file_count = 9);\n\nbool InitServerLogger(std::string const& log_dir, Level level = Level::info,\n                      size_t max_file_size_kb = 5 * 1024,\n                      size_t max_file_count = 9);\n\nLoggerPtr CreateAppLogger(std::string const& application_name,\n                          std::string const& application_root_log,\n                          Level level,\n                          size_t max_file_size_kb,\n                          size_t max_file_count);\n\nLoggerPtr Null();\nLoggerPtr Server();\nLoggerPtr App(std::string const& application_name);\nbool IsNull(LoggerPtr logger);\n\nvoid SetLogLevel(Level level);\nvoid SetServerLogLevel(Level level);\nvoid SetAppLogLevel(std::string const& application_name, Level level);\n\n} // namespace log\n\n}\n#endif // DAQI_LOG_DEF_HPP\n"
  },
  {
    "path": "include/daqi/def/redis_def.hpp",
    "content": "#ifndef DAQI_REDIS_DEF_HPP\n#define DAQI_REDIS_DEF_HPP\n\nnamespace da4qi4\n{\n\nextern unsigned short int const redis_server_default_port;\nextern char const* const redis_server_default_host;\n\n} //namespace da4qi4\n\n#endif // DAQI_REDIS_DEF_HPP\n"
  },
  {
    "path": "include/daqi/handler.hpp",
    "content": "#ifndef DAQI_HANDLER_HPP\n#define DAQI_HANDLER_HPP\n\n#include \"llhttp/llhttp.h\"\n\n#include \"daqi/context.hpp\"\n\n#include <bitset>\n#include <initializer_list>\n\nnamespace da4qi4\n{\n\nenum class HandlerMethod\n{\n    UNSUPPORT = -1,\n\n    DELETE = 0,\n    GET,\n    HEAD,\n    POST,\n    PUT,\n\n    ANY = 999\n};\n\nextern HandlerMethod _DELETE_, _GET_, _HEAD_, _POST_, _PUT_;\n\nchar const* HandlerMethodName(HandlerMethod hm);\n\nHandlerMethod from_http_method(llhttp_method_t m);\n\nusing HandlerMethodMark = std::bitset<5>;\n\nstruct HandlerMethods\n{\n    HandlerMethods() = default;\n\n    HandlerMethods(HandlerMethod m);\n    HandlerMethods(HandlerMethodMark mark)\n        : mark(mark)\n    {\n    }\n\n    HandlerMethods(std::initializer_list<HandlerMethod> lst);\n\n    operator HandlerMethodMark() const\n    {\n        return mark;\n    }\n\n    void Set(HandlerMethod m);\n    bool IsSet(HandlerMethod m) const;\n\n    HandlerMethodMark mark;\n};\n\nusing Handler = std::function<void (Context)>;\n\nextern Handler theEmptyHandler;\n\ntemplate<typename C>\nHandler member_handler(C* o, void (C::*f)(Context))\n{\n    return std::bind(f, o, std::placeholders::_1);\n}\n\n} //namespace da4qi4\n\n#endif // DAQI_HANDLER_HPP\n"
  },
  {
    "path": "include/daqi/intercepter.hpp",
    "content": "#ifndef INTERCEPTER_HPP\n#define INTERCEPTER_HPP\n\n#include <functional>\n\n#include \"daqi/def/def.hpp\"\n#include \"daqi/def/json_def.hpp\"\n\nnamespace da4qi4\n{\n\nclass ContextIMP;\nusing Context = std::shared_ptr<ContextIMP>;\n\nnamespace Intercepter\n{\n\nenum class Result { Pass, Stop };\nenum class On {Request, Handle, Response};\n\nusing Handler = std::function<void (Context ctx, On on)>;\nusing Chain = std::list<Handler>;\n\nusing ChainIterator = Chain::iterator;\nusing ChainReverseIterator = std::reverse_iterator<Chain::iterator>;\n\n} //namespace Intercepter\n} //namespace da4qi4\n\n#endif // INTERCEPTER_HPP\n"
  },
  {
    "path": "include/daqi/intercepters/session_redis.hpp",
    "content": "#ifndef DAQI_INTERCEPTER_SESSION_REDIS_HPP\n#define DAQI_INTERCEPTER_SESSION_REDIS_HPP\n\n#include <string>\n\n#include \"daqi/def/json_def.hpp\"\n\n#include \"daqi/intercepter.hpp\"\n#include \"daqi/session.hpp\"\n#include \"daqi/rediscli_pool.hpp\"\n\nnamespace da4qi4\n{\nnamespace Intercepter\n{\n\nstruct SessionOnRedis\n{\n    SessionOnRedis() = default;\n\n    SessionOnRedis(std::string const& name,\n                   std::string const& prefix,\n                   int session_max_age_seconds)\n    {\n        _options.name = name;\n        _options.prefix = prefix;\n        _options.max_age = session_max_age_seconds;\n    }\n\n    SessionOnRedis(int session_max_age_seconds)\n    {\n        _options.max_age = session_max_age_seconds;\n    }\n\n    SessionOnRedis(SessionOptions const& options)\n        : _options(options)\n    {\n    }\n\n    SessionOnRedis(SessionOnRedis const&) = default;\n    SessionOnRedis& operator = (SessionOnRedis const&) = default;\n\n    SessionOnRedis& SetName(std::string const& name)\n    {\n        _options.name = name;\n        return *this;\n    }\n\n    SessionOnRedis& SetPrefix(std::string const& prefix)\n    {\n        _options.prefix = prefix;\n        return *this;\n    }\n\n    SessionOnRedis& SetMaxAge(int max_age)\n    {\n        _options.max_age = max_age;\n        return *this;\n    }\n\n    SessionOnRedis& SetDomain(std::string const& domain)\n    {\n        _options.domain = domain;\n        return *this;\n    }\n\n    SessionOnRedis& SetPath(std::string const& path)\n    {\n        _options.path = path;\n        return *this;\n    }\n\n    SessionOnRedis& SetHttpOnly(Cookie::HttpOnly http_only)\n    {\n        _options.http_only = http_only;\n        return *this;\n    }\n\n    SessionOnRedis& SetSecure(Cookie::Secure secure)\n    {\n        _options.secure = secure;\n        return *this;\n    }\n\n    SessionOnRedis& SetSameSite(Cookie::SameSite samesite)\n    {\n        _options.samesite = samesite;\n        return *this;\n    }\n\n    SessionOptions const& GetOptions() const\n    {\n        return _options;\n    }\n\npublic:\n    void operator()(Context ctx, On on) const;\n\nprivate:\n    void on_request(Context& ctx) const;\n    void on_response(Context& ctx) const;\n\n    Json create_new_session() const;\n\nprivate:\n    SessionOptions _options;\n};\n\n\n} //namespace Intercepter\n} //namespace da4qi4\n\n#endif // DAQI_INTERCEPTER_SESSION_REDIS_HPP\n"
  },
  {
    "path": "include/daqi/intercepters/static_file.hpp",
    "content": "#ifndef DAQI_INTERCEPTER_STATIC_FILE_HPP\n#define DAQI_INTERCEPTER_STATIC_FILE_HPP\n\n#include <functional>\n#include <vector>\n#include <string>\n#include <map>\n\n#include \"daqi/def/boost_def.hpp\"\n#include \"daqi/intercepter.hpp\"\n\nnamespace da4qi4\n{\n\nnamespace Intercepter\n{\n\nstruct StaticFile\n{\n    static std::string const data_name;\n\n    StaticFile()\n        : _cache_max_age(300)\n        , _url_resolve_type(PathResolve::is_relative)\n        , _dir_resolve_type(PathResolve::is_relative)\n    {\n    }\n\n    StaticFile(int cache_max_age\n               , PathResolve url_resolve_type = PathResolve::is_relative\n               , PathResolve dir_resolve_type = PathResolve::is_relative)\n        : _cache_max_age(cache_max_age)\n        , _url_resolve_type(url_resolve_type)\n        , _dir_resolve_type(dir_resolve_type)\n    {\n    }\n\n    StaticFile(StaticFile const&) = default;\n    StaticFile& operator = (StaticFile const&) = default;\n\n    int GetCacheMaxAge() const\n    {\n        return _cache_max_age;\n    }\n\n    StaticFile& SetCacheMaxAge(int seconds)\n    {\n        _cache_max_age = seconds;\n        return *this;\n    }\n\n    PathResolve GetUrlResolveType() const\n    {\n        return _url_resolve_type;\n    }\n\n    StaticFile& SetUrlResolveType(PathResolve type)\n    {\n        _url_resolve_type = type;\n        return *this;\n    }\n\n    PathResolve GetDirResolveType() const\n    {\n        return _dir_resolve_type;\n    }\n\n    StaticFile& SetDirResolveType(PathResolve type)\n    {\n        _dir_resolve_type = type;\n        return *this;\n    }\n\n    StaticFile& AddEntry(std::string const& url_root, std::string const& dir_root = \"\");\n    StaticFile& AddDefaultFileName(std::string const& index_filename);\n    StaticFile& AddDefaultFileNames(std::vector<std::string> const& index_filenames);\n\n    std::vector<std::string> const& GetDefaultFileNames() const\n    {\n        return _default_filenames;\n    }\n\n    void operator()(Context ctx, On on) const;\n\nprivate:\n    void on_request(Context& ctx) const;\n    void on_response(Context& ctx) const;\n\nprivate:\n    int _cache_max_age;\n    PathResolve _url_resolve_type, _dir_resolve_type;\n    std::map<std::string, std::string, Utilities::CompareDESC> _root_entries;\n    std::vector<std::string> _default_filenames;\n};\n\n} //namespace Intercepter\n} //namespace da4qi4\n\n#endif // DAQI_INTERCEPTER_STATIC_FILE_HPP\n"
  },
  {
    "path": "include/daqi/net-detail/net_detail_client.hpp",
    "content": "#ifndef NET_DETAIL_CLIENT_HPP\n#define NET_DETAIL_CLIENT_HPP\n\n#include \"daqi/def/boost_def.hpp\"\n#include \"daqi/def/asio_def.hpp\"\n\nnamespace da4qi4\n{\nnamespace Client\n{\nnamespace net_detail\n{\n\nusing ReadBuffer = std::array<char, 1024 * 2>;\nusing SocketConnectionCompletionCallback = std::function<void (errorcode const&)>;\nusing SocketCompletionCallback = std::function<void (errorcode const&, std::size_t)>;\n\nstruct SocketBase\n{\n    virtual ~SocketBase();\n\n    virtual void async_connect(Tcp::endpoint const&, SocketConnectionCompletionCallback) = 0;\n\n    virtual void async_read_some(ReadBuffer&, SocketCompletionCallback) = 0;\n\n    virtual void async_write(char const*, std::size_t, SocketCompletionCallback) = 0;\n\n    virtual errorcode sync_connect(Tcp::endpoint const&) = 0;\n    virtual errorcode sync_read_some(ReadBuffer&, std::size_t& bytes_transferred) = 0;\n    virtual errorcode sync_write(char const* write_buffer\n                                 , std::size_t write_buffer_size\n                                 , std::size_t& bytes_transferred) = 0;\n\n    virtual void close(errorcode& ec) = 0;\n\n    virtual Tcp::socket& get_socket() = 0;\n};\n\nstruct Socket : SocketBase\n{\n    Socket(IOC& ioc)\n        : _socket(ioc)\n    {\n    }\n\n    ~Socket() override;\n    Tcp::socket& get_socket() override;\n\n    void async_connect(Tcp::endpoint const& ep,\n                       SocketConnectionCompletionCallback on_connect) override;\n\n    void async_read_some(ReadBuffer& read_buffer, SocketCompletionCallback on_read) override;\n\n    void async_write(char const* write_buffer, std::size_t size, SocketCompletionCallback on_wrote) override;\n\n    errorcode sync_connect(Tcp::endpoint const& ep) override;\n    errorcode sync_read_some(ReadBuffer& read_buffer, std::size_t& bytes_transferred) override;\n    errorcode sync_write(char const* write_buffer, std::size_t write_buffer_size\n                         , std::size_t& bytes_transferred) override;\n\n    void close(errorcode& ec) override;\nprivate:\n    Tcp::socket _socket;\n};\n\nstruct SocketWithSSL : SocketBase\n{\n    SocketWithSSL(IOC& ioc, boost::asio::ssl::context& ssl_ctx)\n        : _stream(ioc, ssl_ctx)\n    {\n    }\n\n    ~SocketWithSSL() override;\n\n    Tcp::socket& get_socket() override;\n\n    void async_connect(Tcp::endpoint const& ep,\n                       SocketConnectionCompletionCallback on_connect) override;\n\n    void async_read_some(ReadBuffer& read_buffer, SocketCompletionCallback on_read) override;\n\n    void async_write(char const* write_buffer, std::size_t size, SocketCompletionCallback on_wrote) override;\n\n    errorcode sync_connect(Tcp::endpoint const& ep) override;\n    errorcode sync_read_some(ReadBuffer& read_buffer, std::size_t& bytes_transferred) override;\n    errorcode sync_write(char const* write_buffer, std::size_t write_buffer_size\n                         , std::size_t& bytes_transferred) override;\n\n    void close(errorcode& ec) override;\n\nprivate:\n    boost::asio::ssl::stream<Tcp::socket> _stream;\n};\n\n} // namespace net_detail\n} // namespace Client\n} // namespace da4qi4\n\n\n#endif // NET_DETAIL_CLIENT_HPP\n"
  },
  {
    "path": "include/daqi/net-detail/net_detail_server.hpp",
    "content": "#ifndef DAQI_NET_DETAIL_SERVER_HPP\n#define DAQI_NET_DETAIL_SERVER_HPP\n\n#include <boost/asio/ssl/stream.hpp>\n\n#include \"daqi/def/asio_def.hpp\"\n#include \"daqi/def/boost_def.hpp\"\n\nnamespace da4qi4\n{\nnamespace net_detail\n{\n\nusing ReadBuffer = std::array<char, 1024 * 4>;\nusing WriteBuffer = boost::asio::streambuf;\nusing ChunkedBuffer = std::string;\n\nusing SocketCompletionCallback = std::function<void (errorcode const&, std::size_t)>;\n\nstruct SocketInterface\n{\n    virtual ~SocketInterface();\n\n    virtual void close(errorcode& ec) = 0;\n\n    virtual IOC& get_ioc() = 0;\n    virtual Tcp::socket& get_socket() = 0;\n\n    virtual void async_read_some(ReadBuffer&, SocketCompletionCallback) = 0;\n    virtual void async_write(WriteBuffer&, SocketCompletionCallback) = 0;\n    virtual void async_write(ChunkedBuffer const&, SocketCompletionCallback) = 0;\n\n    virtual bool IsWithSSL() const = 0;\n};\n\nstruct Socket : SocketInterface\n{\n    Socket(IOC& ioc)\n        : _socket(ioc)\n    {\n    }\n\n    ~Socket() override;\n\n    void close(errorcode& ec) override\n    {\n        _socket.shutdown(boost::asio::socket_base::shutdown_both, ec);\n        _socket.close(ec);\n    }\n\n    bool IsWithSSL() const override\n    {\n        return false;\n    }\n\n    IOC& get_ioc() override;\n\n    Tcp::socket& get_socket() override\n    {\n        return _socket;\n    }\n\n    void async_read_some(ReadBuffer& read_buffer, SocketCompletionCallback on_read) override\n    {\n        _socket.async_read_some(boost::asio::buffer(read_buffer), on_read);\n    }\n\n    void async_write(WriteBuffer& write_buffer, SocketCompletionCallback on_wrote) override\n    {\n        boost::asio::async_write(_socket, write_buffer, on_wrote);\n    }\n\n    void async_write(ChunkedBuffer const& chunked_buffer, SocketCompletionCallback on_wrote) override\n    {\n        boost::asio::async_write(_socket, boost::asio::buffer(chunked_buffer), on_wrote);\n    }\n\nprivate:\n    Tcp::socket _socket;\n};\n\nstruct SocketWithSSL : SocketInterface\n{\n    SocketWithSSL(IOC& ioc, boost::asio::ssl::context& ssl_ctx)\n        : _stream(ioc, ssl_ctx)\n    {\n    }\n\n    ~SocketWithSSL() override;\n\n    void close(errorcode& ec) override\n    {\n        _stream.lowest_layer().cancel();\n        _stream.shutdown(ec);\n        _stream.next_layer().close(ec);\n    }\n\n    bool IsWithSSL() const override\n    {\n        return true;\n    }\n\n    IOC& get_ioc() override;\n\n    Tcp::socket& get_socket() override\n    {\n        return _stream.next_layer();\n    }\n\n    void async_read_some(ReadBuffer& read_buffer, SocketCompletionCallback on_read) override\n    {\n        _stream.async_read_some(boost::asio::buffer(read_buffer), on_read);\n    }\n\n    void async_write(WriteBuffer& write_buffer, SocketCompletionCallback on_wrote) override\n    {\n        boost::asio::async_write(_stream, write_buffer, on_wrote);\n    }\n\n    void async_write(ChunkedBuffer const& chunked_buffer, SocketCompletionCallback on_wrote) override\n    {\n        boost::asio::async_write(_stream, boost::asio::buffer(chunked_buffer), on_wrote);\n    }\n\npublic:\n    boost::asio::ssl::stream<Tcp::socket>& get_stream()\n    {\n        return _stream;\n    }\n\nprivate:\n    boost::asio::ssl::stream<Tcp::socket> _stream;\n};\n\n} //namespace net_detail\n} // namespace da4qi4\n\n#endif // DAQI_NET_DETAIL_SERVER_HPP\n"
  },
  {
    "path": "include/daqi/redis-client/redis_buffer.hpp",
    "content": "#ifndef DAQI_REDIS_BUFFER_H\n#define DAQI_REDIS_BUFFER_H\n\n#include <string>\n#include <vector>\n\nnamespace da4qi4\n{\n\nstruct RedisBuffer\n{\n    RedisBuffer() = default;\n    RedisBuffer(const char* ptr, size_t dataSize);\n    RedisBuffer(const char* s);\n    RedisBuffer(std::string s);\n    RedisBuffer(std::vector<char> buf);\n\n    template<typename SrcT>\n    RedisBuffer(SrcT const& value)\n        : data(std::move(std::to_string(value)))\n    {}\n\n    size_t size() const;\n\n    std::string data;\n};\n\n} // namespace da4qi4\n\n#endif // DAQI_REDIS_BUFFER_H\n"
  },
  {
    "path": "include/daqi/redis-client/redis_client.hpp",
    "content": "#ifndef DAQI_REDIS_CLIENT_HPP\n#define DAQI_FREDIS_CLIENT_HPP\n\n#include <string>\n#include <queue>\n#include <deque>\n\n#include <boost/noncopyable.hpp>\n\n#include \"daqi/def/asio_def.hpp\"\n#include \"daqi/redis-client/redis_buffer.hpp\"\n#include \"daqi/redis-client/redis_value.hpp\"\n\nnamespace da4qi4\n{\n\nenum class RedisClientErrorHandlePolicy {do_nothing, auto_reconnect};\n\nclass RedisParser;\n\n/*!!! THE REDISCLIENT IS DESIGNED FOR SINGLE-THREAD (BUT ASYNC-CALL SUPPORTED) !!!*/\nclass RedisClient\n    : public boost::noncopyable\n{\npublic:\n    RedisClient(IOC& ioc,\n                RedisClientErrorHandlePolicy policy = RedisClientErrorHandlePolicy::do_nothing)\n        : _socket(ioc), _reconnect_timer(ioc), _error_handle_policy(policy)\n    {\n    }\n\n    ~RedisClient();\n\n    void Connect(std::function<void (boost::system::error_code const& ec)> on = nullptr,\n                 std::string const& host = \"127.0.0.1\", unsigned short port = 6379);\n\n    void Reconnect(std::function<void (boost::system::error_code const& ec)> on = nullptr);\n    void Disconnect();\n\n#ifdef _DEBUG_REDIS_NEED_SYNC_OPERATOR_\n    bool ConnectSync(std::string const& host = \"127.0.0.1\", unsigned short port = 6379);\n    bool ReconnectSync()\n    {\n        if (IsConnected())\n        {\n            do_disconnect();\n            return do_sync_connect();\n        }\n\n        return true;\n    }\n\n    RedisValue CommandSync(std::string cmd, std::deque<RedisBuffer> args);\n#endif //_DEBUG_REDIS_NEED_SYNC_OPERATOR_\n\npublic:\n    void Command(std::string cmd, std::deque<RedisBuffer> args,\n                 std::function<void(RedisValue value)> on = nullptr);\n\n    bool IsConnected() const\n    {\n        return _connect_status == is_connected;\n    }\n\n    bool IsConnectting() const\n    {\n        return _connect_status == is_connectting;\n    }\n\nprivate:\n    void do_disconnect();\n\n#ifdef _DEBUG_REDIS_NEED_SYNC_OPERATOR_\n    bool do_sync_connect();\n#endif //_DEBUG_REDIS_NEED_SYNC_OPERATOR_\n\n    void do_async_connect(std::function<void (boost::system::error_code const& ec)> on);\n    void on_connect_finished(std::function<void (boost::system::error_code const& ec)> on\n                             , boost::system::error_code const& ec);\n    bool start_reconnect_timer(std::function<void (boost::system::error_code const& ec)> on);\n\n    void start_aysnc_read_and_parse(std::function<void(RedisValue value)> on);\n    void do_async_read_and_parse(std::shared_ptr<RedisParser> parser, std::function<void(RedisValue value)> on);\n\nprivate:\n    void start_async_write();\n\nprivate:\n    boost::asio::ip::tcp::socket _socket;\n    boost::asio::deadline_timer _reconnect_timer;\n    RedisClientErrorHandlePolicy _error_handle_policy;\n    std::string _host;\n    unsigned short _port = 0;\n    unsigned int _reconnect_count = 0;\n\nprivate:\n    using CommandNode = std::pair<std::vector<char>, std::function<void(RedisValue value)>>;\n    std::queue<CommandNode> _command_queue;\n\nprivate:\n    std::string _reply_buf;\n    std::size_t _reply_parse_beg;\n    static size_t const  _read_buffer_size_ = (1024);\n    char _tmp_read_buf[_read_buffer_size_];\n\nprivate:\n    enum ConnectStatus {not_connect, is_connectting, is_connected};\n    ConnectStatus _connect_status = not_connect;\n};\n\nusing RedisClientPtr = std::shared_ptr<RedisClient>;\n\n} // namespace da4qi4\n\n#endif // DAQI_REDIS_CLIENT_HPP\n"
  },
  {
    "path": "include/daqi/redis-client/redis_command.hpp",
    "content": "#ifndef DAQI_REDIS_COMMAND_HPP\n#define DAQI_REDIS_COMMAND_HPP\n\n#include <vector>\n#include <deque>\n\n#include \"daqi/redis-client/redis_buffer.hpp\"\n\nnamespace da4qi4\n{\n\nstd::vector<char> MakeCommand(std::deque<RedisBuffer> const& items);\n\n} // namespace da4qi4\n\n#endif // DAQI_REDIS_COMMAND_HPP\n"
  },
  {
    "path": "include/daqi/redis-client/redis_parser.hpp",
    "content": "#ifndef DAQI_REDIS_PARSER_HPP\n#define DAQI_REDIS_PARSER_HPP\n\n#include <vector>\n#include <stack>\n\n#include <boost/variant.hpp>\n\n#include \"daqi/redis-client/redis_value.hpp\"\n\nnamespace da4qi4\n{\n\nclass RedisParser\n{\npublic:\n    RedisParser();\n\n    enum ParseResult\n    {\n        Completed,\n        Incompleted,\n        Error,\n    };\n\n    std::pair<size_t, ParseResult> Parse(const char* ptr, size_t size);\n\n    RedisValue Result();\n\nprotected:\n    std::pair<size_t, ParseResult> parse_chunk(const char* ptr, size_t size);\n\n    inline bool is_char(int c)\n    {\n        return c >= 0 && c <= 127;\n    }\n\n    inline bool is_control(int c)\n    {\n        return (c >= 0 && c <= 31) || (c == 127);\n    }\n\n    long int buf_to_long(const char* str, size_t size);\n\nprivate:\n    enum State\n    {\n        Start = 0,\n        StartArray = 1,\n\n        String = 2,\n        StringLF = 3,\n\n        ErrorString = 4,\n        ErrorLF = 5,\n\n        Integer = 6,\n        IntegerLF = 7,\n\n        BulkSize = 8,\n        BulkSizeLF = 9,\n        Bulk = 10,\n        BulkCR = 11,\n        BulkLF = 12,\n\n        ArraySize = 13,\n        ArraySizeLF = 14,\n    };\n\n    std::stack<State> states;\n\n    long int bulkSize;\n    std::vector<char> buf;\n    RedisValue redisValue;\n\n    // temporary variables\n    std::stack<long int> arraySizes;\n    std::stack<RedisValue> arrayValues;\n\n    static const char stringReply = '+';\n    static const char errorReply = '-';\n    static const char integerReply = ':';\n    static const char bulkReply = '$';\n    static const char arrayReply = '*';\n};\n\n} //namesapce da4qi4\n\n#endif // DAQI_REDIS_PARSER_HPP\n"
  },
  {
    "path": "include/daqi/redis-client/redis_value.hpp",
    "content": "#ifndef DAQI_REDIS_VALUE_HPP\n#define DAQI_REDIS_VALUE_HPP\n\n#include <string>\n#include <stack>\n#include <vector>\n#include <utility>\n\n#include <boost/variant.hpp>\n\nnamespace da4qi4\n{\n\nclass RedisValue\n{\npublic:\n    struct ErrorTag {};\n\n    RedisValue();\n    RedisValue(RedisValue&& other);\n    RedisValue(int64_t i);\n    RedisValue(const char* s);\n    RedisValue(const std::string& s);\n    RedisValue(std::vector<char> buf);\n    RedisValue(std::vector<char> buf, struct ErrorTag);\n    RedisValue(std::string const& custom_error, struct ErrorTag);\n    RedisValue(std::vector<RedisValue> array);\n\n\n    RedisValue(const RedisValue&) = default;\n    RedisValue& operator = (const RedisValue&) = default;\n    RedisValue& operator = (RedisValue&&) = default;\n\n    // Return the value as a std::string if\n    // type is a byte string; otherwise returns an empty std::string.\n    std::string ToString() const;\n\n    // Return the value as a std::vector<char> if\n    // type is a byte string; otherwise returns an empty std::vector<char>.\n    std::vector<char> ToByteArray() const;\n\n    // Return the value as a std::vector<RedisValue> if\n    // type is an int; otherwise returns 0.\n    int64_t ToInt() const;\n\n    int ToInt32() const\n    {\n        return static_cast<int>(ToInt());\n    }\n\n    // Return the value as an array if type is an array;\n    // otherwise returns an empty array.\n    std::vector<RedisValue> ToArray() const;\n\n    // Return the string representation of the value. Use\n    // for dump content of the value.\n    std::string Inspect() const;\n\n    // Return true if value not a error\n    bool IsOk() const;\n    // Return true if value is a error\n    bool IsError() const;\n\n    // Return true if this is a null.\n    bool IsNull() const;\n    // Return true if type is an int\n    bool IsInt() const;\n    // Return true if type is an array\n    bool IsArray() const;\n    // Return true if type is a string/byte array. Alias for IsString();\n    bool IsByteArray() const;\n    // Return true if type is a string/byte array. Alias for IsByteArray().\n    bool IsString() const;\n\n    // Methods for increasing perfomance\n    // Throws: boost::bad_get if the type does not match\n    std::vector<char>& GetByteArray();\n    const std::vector<char>& GetByteArray() const;\n    std::vector<RedisValue>& GetArray();\n    const std::vector<RedisValue>& GetArray() const;\n\n    bool operator == (const RedisValue& rhs) const;\n    bool operator != (const RedisValue& rhs) const;\n\nprotected:\n    template<typename T>\n    T cast_to() const;\n\n    template<typename T>\n    bool type_eq() const;\n\nprivate:\n    struct NullTag\n    {\n        inline bool operator == (const NullTag&) const\n        {\n            return true;\n        }\n    };\n\n    boost::variant<NullTag, int64_t, std::vector<char>, std::vector<RedisValue>> _value;\n    bool _error;\n};\n\n\ntemplate<typename T>\nT RedisValue::cast_to() const\n{\n    return (_value.type() == typeid(T)) ? boost::get<T>(_value) : T();\n}\n\ntemplate<typename T>\nbool RedisValue::type_eq() const\n{\n    return (_value.type() == typeid(T));\n}\n\n} // namespace da4qi4\n\n#endif // DAQI_REDIS_VALUE_HPP\n"
  },
  {
    "path": "include/daqi/rediscli_pool.hpp",
    "content": "#ifndef DAQI_REDIS_CLI_POOL_HPP\n#define DAQI_REDIS_CLI_POOL_HPP\n\n#include <map>\n#include <queue>\n#include <mutex>\n#include <vector>\n#include <memory>\n#include <functional>\n\n#include <boost/asio/deadline_timer.hpp>\n\n#include \"daqi/def/redis_def.hpp\"\n#include \"daqi/redis-client/redis_client.hpp\"\n#include \"daqi/session.hpp\"\n\nnamespace da4qi4\n{\n\nclass IOContextPool;\nclass RedisClientPool\n{\n    RedisClientPool() = default;\n\npublic:\n    void CreateClients(IOContextPool* ioc_pool\n                       , std::string const& host = redis_server_default_host\n                       , unsigned short port = redis_server_default_port);\n\n    void Stop();\n\n    ~RedisClientPool()\n    {\n        clear();\n    }\n\n    RedisClientPtr Get(size_t index)\n    {\n        return (index >= 0 && index < _clients.size()) ? _clients[index] : nullptr;\n    }\n\nprivate:\n    void clear();\n    void on_connect_finished(std::size_t index, boost::system::error_code const& ec);\nprivate:\n    std::vector<RedisClientPtr> _clients;\n\n    friend RedisClientPool& RedisPool();\n};\n\nRedisClientPool& RedisPool();\n\n} //nampespace da4qi4\n\n#endif // DAQI_REDIS_CLI_POOL_HPP\n"
  },
  {
    "path": "include/daqi/request.hpp",
    "content": "#ifndef DAQI_REQUEST_HPP\n#define DAQI_REQUEST_HPP\n\n#include <string>\n#include <map>\n#include <bitset>\n#include <vector>\n\n#include \"llhttp/llhttp.h\"\n\n#include \"daqi/def/boost_def.hpp\"\n#include \"daqi/utilities/container_utilities.hpp\"\n\n#include \"daqi/url.hpp\"\n\nnamespace da4qi4\n{\nstruct RoutingPathParameters\n{\n    RoutingPathParameters() = default;\n    RoutingPathParameters(RoutingPathParameters const&) = default;\n    RoutingPathParameters(RoutingPathParameters&& o)\n        : _parameters(std::move(o._parameters))\n    {\n    }\n\n    size_t GetCount() const\n    {\n        return _parameters.size();\n    }\n\n    void Clear()\n    {\n        _parameters.clear();\n    }\n\n    std::map<std::string, std::string> const& Items() const\n    {\n        return _parameters;\n    }\n\n    bool IsExists(std::string const& name) const;\n    std::string const& Get(std::string const& name) const;\n    OptionalStringRefConst TryGet(std::string const& name) const;\n\n    void InitParameters(std::vector<std::string> const& names\n                        , std::vector<std::string> const& values);\nprivate:\n    std::map<std::string, std::string> _parameters;\n};\n\nstruct MultiPart\n{\n    struct SubHeaders\n    {\n        std::string value;\n        ICHeaders headers;\n\n        bool IsEmpty() const\n        {\n            return value.empty();\n        }\n    };\n\n    MultiPart() = default;\n    ~MultiPart() = default;\n\n    MultiPart(MultiPart const& o);\n    MultiPart(MultiPart&& o);\n\n    size_t HeaderCount() const\n    {\n        return _headers.size();\n    }\n    size_t DataSize() const\n    {\n        return _data.size();\n    }\n\n    bool IsExistsHeader(std::string const& field) const;\n    std::string const& GetHeader(std::string const& field) const;\n    OptionalStringRefConst TryGetHeader(std::string const& field) const;\n\n    void AppendHeader(std::string&& field, std::string&& value);\n\n    ICHeaders& GetHeaders()\n    {\n        return _headers;\n    }\n    ICHeaders const& GetHeaders() const\n    {\n        return _headers;\n    }\n\n    std::string const& GetData() const\n    {\n        return _data;\n    }\n\n    std::string&& GetData()\n    {\n        return std::move(_data);\n    }\n\n    void SetData(std::string&& data)\n    {\n        _data = std::move(data);\n    }\n\n    SubHeaders GetSubHeaders(std::string const& field);\n\n    void ClearData()\n    {\n        _data.clear();\n        _data.shrink_to_fit();\n    }\n\n    void Clear()\n    {\n        _headers.clear();\n        _data.clear();\n    }\n\n    enum TransferResult\n    {\n        transfer_none, tranfer_formdata,\n        transfer_file_memory, transfer_file_saved\n    };\n\n    TransferResult GetTransferResult() const\n    {\n        return _transfer_result;\n    }\n\n    void SetTransferResult(TransferResult transfer_result)\n    {\n        _transfer_result = transfer_result;\n    }\nprivate:\n    ICHeaders _headers;\n    std::string _data;\n    TransferResult _transfer_result = transfer_none;\n};\n\nstruct FormDataItem\n{\n    FormDataItem() = default;\n    FormDataItem(std::string const& name, std::string&& data)\n        : name(name), data(std::move(data))\n    {}\n\n    std::string name;\n    enum DataFlag {is_data, is_file_data, is_file_temporary_name};\n    DataFlag data_flag = is_data;\n    std::string filename;\n    std::string content_type;\n    std::string data;\n\n    bool IsData() const\n    {\n        return data_flag == is_data || data_flag == is_file_data;\n    }\n\n    bool IsFile() const\n    {\n        return data_flag == is_file_data || data_flag == is_file_temporary_name;\n    }\n\n    bool IsSavedFile() const\n    {\n        return data_flag == is_file_temporary_name;\n    }\n\n    std::string const& GetSavedFileTemporaryName() const\n    {\n        return (!IsSavedFile() ? Utilities::theEmptyString : data);\n    }\n\n    void Reset()\n    {\n        name.clear();\n        data_flag = is_data;\n        filename.clear();\n        content_type.clear();\n        data.clear();\n    }\n};\n\nclass Application;\nstruct UploadFileSaveOptions;\n\nstruct UploadFile\n{\n    UploadFile() = default;\n    UploadFile(UploadFile const&) = default;\n    UploadFile(UploadFile&& o)\n        : _field_name(std::move(o._field_name))\n        , _status(o._status), _stream(std::move(o._stream)), _memory(std::move(o._memory))\n        , _src_filename(std::move(o._src_filename)), _saved_filename(std::move(o._saved_filename))\n        , _content_type(std::move(o._content_type))\n    {\n    }\n\n    bool FromFormDataItem(FormDataItem const& item);\n\n    ~UploadFile()\n    {\n        if (_stream)\n        {\n            _stream.close();\n        }\n    }\n\n    operator bool () const\n    {\n        return (_status != no_found) && !((_status == in_stream) && !_stream)\n               && !((_status == in_memory) && _memory.empty());\n    }\n\n    bool InMemory() const\n    {\n        return _status == in_memory;\n    }\n    bool InStream() const\n    {\n        return _status == in_stream;\n    }\n\n    bool IsNoFound() const\n    {\n        return _status == no_found;\n    }\n\n    std::string const& GetSavedFileName() const\n    {\n        return _saved_filename;\n    }\n\n    std::string const& GetSourceFileName() const\n    {\n        return _src_filename;\n    }\n\n    std::string const& GetFieldName() const\n    {\n        return _field_name;\n    }\n\n    std::string const& GetContentType() const\n    {\n        return _content_type;\n    }\n\n    std::string const& Memory() const\n    {\n        return _memory;\n    }\n\n    std::ifstream& Stream()\n    {\n        return _stream;\n    }\n\n    bool ToMemory();\n    bool ToStream(Application const& app, std::string const& ext);\n    bool ToStream(std::string const& temp_filename);\n\n    bool SaveTo(std::string const& dst_filename);\n\nprivate:\n    enum Status {no_found, in_stream, in_memory};\n\n    std::string _field_name;\n\n    Status _status = no_found;\n\n    std::ifstream _stream;\n    std::string _memory;\n\n    std::string _src_filename;\n    std::string _saved_filename;\n    std::string _content_type;\n};\n\nclass Request\n{\npublic:\n    enum ParameterSrc\n    {\n        fromUnknown = 0, fromUrl, fromPath, fromForm, fromHeader, fromCookie\n    };\n\n    bool IsExistsHeader(std::string const& field) const;\n    std::string const& GetHeader(std::string const& field) const;\n    OptionalStringRefConst TryGetHeader(std::string const& field) const;\n\n    bool IsExistsUrlParameter(std::string const& name) const;\n    std::string const& GetUrlParameter(std::string const& name) const;\n    OptionalStringRefConst TryGetUrlParameter(std::string const& name) const;\n\n    void InitPathParameters(std::vector<std::string> const& names\n                            , std::vector<std::string> const& values)\n    {\n        _path_parameters.InitParameters(names, values);\n    }\n\n    bool IsExistsPathParameter(std::string const& name) const\n    {\n        return _path_parameters.IsExists(name);\n    }\n    std::string const& GetPathParameter(std::string const& name) const\n    {\n        return _path_parameters.Get(name);\n    }\n    OptionalStringRefConst TryGetPathParameter(std::string const& name) const\n    {\n        return _path_parameters.TryGet(name);\n    }\n\n    bool IsExistsFormData(std::string const& name) const;\n    std::string const& GetFormData(std::string const& name) const;\n    OptionalStringRefConst TryGetFormData(std::string const& name) const;\n\n    bool IsExistsCookie(std::string const& name) const;\n    std::string const& GetCookie(std::string const& name) const;\n    OptionalStringRefConst TryGetCookie(std::string const& name) const;\n\n    ParameterSrc IsExistsParameter(std::string const& name) const\n    {\n        //find order : url -> path -> formdata -> header -> cookie\n        return IsExistsUrlParameter(name) ? fromUrl\n               : (IsExistsPathParameter(name) ? fromPath\n                  : (IsExistsFormData(name) ? fromForm\n                     : (IsExistsHeader(name) ?  fromHeader\n                        : (IsExistsCookie(name) ? fromCookie\n                           : fromUnknown))));\n    }\n\n\n    bool IsExistsFile(std::string const& field_name) const;\n    UploadFile GetFile(std::string const& field_name) const;\n\n    std::string const& GetParameter(std::string const& name) const;\n    OptionalStringRefConst TryGetParameter(std::string const& name) const;\n    std::string const& operator[](std::string const& name) const\n    {\n        return GetParameter(name);\n    }\n\n    UrlUnderApp const& GetUrl() const\n    {\n        return _url;\n    }\n\n    UrlUnderApp& GetUrl()\n    {\n        return _url;\n    }\n\n    llhttp_method_t GetMethod() const\n    {\n        return static_cast<llhttp_method_t>(_method);\n    }\n\n    std::string GetHost() const\n    {\n        ICHeaders::const_iterator it = _headers.find(\"Host\");\n        return (it == _headers.cend() ? \"\" : it->second);\n    }\n\n    std::string GetMethodName() const\n    {\n        return llhttp_method_name(GetMethod());\n    }\n\n    ICHeaders const& GetHeader() const\n    {\n        return _headers;\n    }\n\n    ICHeaders& GetHeader()\n    {\n        return _headers;\n    }\n\n    ICCookies const& GetCookies() const\n    {\n        return _cookies;\n    }\n\n    ICCookies& GetCookies()\n    {\n        return _cookies;\n    }\n\n    RoutingPathParameters const& GetPathParameters() const\n    {\n        return _path_parameters;\n    }\n\n    std::string const& GetMultiPartBoundary() const\n    {\n        return _boundary;\n    }\n\n    std::vector<MultiPart>& GetMultiParts()\n    {\n        return _multiparts;\n    }\n\n    std::vector<MultiPart> const& GetMultiParts() const\n    {\n        return _multiparts;\n    }\n\n    void GetVersion(unsigned short& major, unsigned short& minor) const\n    {\n        major = _version_major;\n        minor = _version_minor;\n    }\n\n    std::pair<unsigned short, unsigned short> GetVersion()\n    {\n        return {_version_major, _version_minor};\n    }\n\n    bool IsContentLengthProvided() const\n    {\n        return (_flags & F_CONTENT_LENGTH) != 0;\n    }\n    uint64_t GetContentLength() const\n    {\n        return _content_length;\n    }\n\n    bool IsChunked() const\n    {\n        return (_flags & F_CHUNKED) != 0;\n    }\n    bool IsUpgrade() const\n    {\n        return _addition_flags[upgrade_bit];\n    }\n    bool IsFormData() const\n    {\n        return _addition_flags[formdata_bit];\n    }\n    bool IsFormUrlEncoded() const\n    {\n        return _addition_flags[formurlencoded_bit];\n    }\n    bool IsOctetStream() const\n    {\n        return _addition_flags[octetstream_bit];\n    }\n    bool IsMultiPart() const\n    {\n        return _addition_flags[multipart_bit];\n    }\n    bool IsKeepAlive() const\n    {\n        return _addition_flags[keepalive_bit];\n    }\n    bool IsBodySkipped() const\n    {\n        return (_flags & F_SKIPBODY) != 0;\n    }\n\n    bool HasBody() const\n    {\n        return !_body.empty();\n    }\n\n    std::string const& Body() const\n    {\n        return _body;\n    }\n\npublic:\n    bool ParseUrl(std::string&& url);\n    void ParseContentType();\n\n    void ApplyApplication(std::string const& app_url_root);\n\n    void AppendHeader(std::string&& field, std::string&& value);\n\n    void MarkUpgrade(bool upgrade)\n    {\n        _addition_flags.set(upgrade_bit, upgrade);\n    }\n    void MarkKeepAlive(bool keep)\n    {\n        _addition_flags.set(keepalive_bit, keep);\n    }\n    void MarkMultiPart(bool multipart)\n    {\n        _addition_flags.set(multipart_bit, multipart);\n    }\n    void MarkFormUrlEncoded(bool formurlencoded)\n    {\n        _addition_flags.set(formurlencoded_bit, formurlencoded);\n    }\n    void MarkOctetStream(bool octetstream)\n    {\n        _addition_flags.set(octetstream_bit, octetstream);\n    }\n    void MarkFormData(bool formdata)\n    {\n        _addition_flags.set(formdata_bit, formdata);\n    }\n\n    void SetMethod(unsigned int method)\n    {\n        _method = method;\n    }\n    void SetVersion(unsigned short major, unsigned short minor)\n    {\n        _version_major = major;\n        _version_minor = minor;\n    }\n    void SetContentLength(uint64_t content_length)\n    {\n        _content_length = content_length;\n    }\n    void SetFlags(unsigned int flags)\n    {\n        _flags = flags;\n    }\n    void SetBody(std::string&& body)\n    {\n        _body.swap(body);\n    }\n    void SetMultiPartBoundary(char const* at, size_t length);\n\n    void AddMultiPart(MultiPart&& part)\n    {\n        _multiparts.push_back(std::move(part));\n    }\n\n    void TransferHeadersToCookies();\n    void TransferMultiPartsToFormData(UploadFileSaveOptions const& options\n                                      , std::string const& dir);\n    void ParseFormUrlEncodedData();\n\n    void Reset();\n\n    std::string Dump() const;\n\nprivate:\n    static int const upgrade_bit = 0;\n    static int const keepalive_bit = 1;\n    static int const multipart_bit = 2;\n    static int const formurlencoded_bit = 3;\n    static int const formdata_bit = 4;\n    static int const octetstream_bit = 5;\n\n    std::bitset<6> _addition_flags;\n\n    UrlUnderApp _url;\n    unsigned int _method = HTTP_GET;\n    ICHeaders _headers;\n\n    unsigned short _version_major = 0;\n    unsigned short _version_minor = 0;\n\n    uint64_t _content_length = 0L;\n    unsigned int _flags = 0;\n\n    std::string _body;\n\n    std::string _boundary;\n    std::vector<MultiPart> _multiparts;\n\n    ICCookies _cookies;\n    std::vector<FormDataItem> _formdata;\n\n    RoutingPathParameters _path_parameters;\n};\n\n} //namespace da4qi4\n\n#endif // DAQI_REQUEST_HPP\n"
  },
  {
    "path": "include/daqi/response.hpp",
    "content": "#ifndef DAQI_RESPONSE_HPP\n#define DAQI_RESPONSE_HPP\n\n#include <iostream>\n#include <functional>\n#include <vector>\n\n#include <mutex>\n\n#include \"llhttp/llhttp.h\"\n#include \"llhttp/helper/http_status_def.h\"\n\n#include \"daqi/def/def.hpp\"\n#include \"daqi/def/boost_def.hpp\"\n#include \"daqi/def/json_def.hpp\"\n\n#include \"daqi/cookie.hpp\"\n\nnamespace da4qi4\n{\n\nstd::string const&  EmptyBody();\n\nstruct ChunkedBodies\n{\n    void PushBack(std::string const& body, bool is_last);\n    std::string PopFront(bool& is_last);\n    void Clear();\n\nprivate:\n    std::list<std::pair<std::string, bool>> _chunked_bodies;\n    std::mutex _m;\n};\n\nclass Response\n{\npublic:\n    Response();\n    Response(http_status code)\n        : _status_code(code)\n    {}\n\n    int GetStatusCode() const\n    {\n        return _status_code ;\n    }\n\n    void GetVersion(unsigned short& major, unsigned short& minor) const\n    {\n        major = _version_major;\n        minor = _version_minor;\n    }\n\n    std::pair<unsigned short, unsigned short> GetVersion() const\n    {\n        return {_version_major, _version_minor};\n    }\n\n    std::string const& GetCharset() const\n    {\n        return _charset;\n    }\n\n    enum ContentTypePart {without_chartset = 0, with_chartset = 1};\n    std::string GetContentType(ContentTypePart part = with_chartset) const;\n    std::string const& GetContentEncoding() const\n    {\n        return GetHeader(\"Content-Encoding\");\n    }\n\n    ICHeaders const& GetHeaders() const\n    {\n        return _headers;\n    }\n\n    std::string const& GetBody() const\n    {\n        return _body;\n    }\n\n    std::string PopChunkedBody(bool& is_last)\n    {\n        return _chunked_bodies.PopFront(is_last);\n    }\n\n    void PushChunkedBody(std::string const& body, bool is_last)\n    {\n        _chunked_bodies.PushBack(body, is_last);\n    }\n\n    bool IsExistsHeader(std::string const& field) const;\n    std::string const& GetHeader(std::string const& field) const;\n    OptionalStringRefConst TryGetHeader(std::string const& field) const;\n\n    void SetStatusCode(http_status code)\n    {\n        _status_code = code;\n    }\n\n    void SetVersion(unsigned short major, unsigned short minor)\n    {\n        _version_major = major;\n        _version_minor = minor;\n    }\n\n    void SetBody(std::string&& body)\n    {\n        _body = std::move(body);\n    }\n\n    void SetBody(std::string const& body)\n    {\n        _body = body;\n    }\n\n    void SetCharset(std::string const& charset);\n    void SetContentType(std::string const& content_type);\n    void SetContentType(std::string const& content_type\n                        , std::string const& content_charset);\n\n    void SetContentEncoding(std::string const& encoding)\n    {\n        AppendHeader(\"Content-Encoding\", encoding);\n    }\n\n    void AppendHeader(std::string const& field, std::string const& value);\n\n    bool IsRedirected() const\n    {\n        return IsExistsHeader(\"Location\");\n    }\n\n    void SetLocation(std::string const& dst_location)\n    {\n        AppendHeader(\"Location\", dst_location);\n    }\n\n    void SetExpires(std::time_t time_point)\n    {\n        AppendHeader(\"Expires\", Utilities::GMTFormatTime(time_point));\n    }\n\n    void CacheControlMaxAge(int max_age_seconds = 0, CacheControl cc = CacheControl::Public)\n    {\n        std::string s = (cc == CacheControl::Public) ? \"public\" : \"private\";\n        AppendHeader(\"Cache-Control\", s + \", max-age=\" + std::to_string(max_age_seconds));\n    }\n\n    void NoCache()\n    {\n        AppendHeader(\"Cache-Control\", \"no-cache\");\n    }\n\n    void TurnOffCache()\n    {\n        AppendHeader(\"Cache-Control\", \"no-cache, no-store, must-revalidate\");\n    }\n\n    void MarkKeepAlive();\n    void MarkClose();\n\n    bool IsKeepAlive() const;\n    bool IsClose() const;\n\n    void RemoveLocation()\n    {\n        _headers.erase(\"Location\");\n    }\n\n    bool IsChunked() const;\n    void MarkChunked()\n    {\n        AppendHeader(\"Transfer-Encoding\", \"chunked\");\n\n        if (_version_major < 1 || _version_minor < 1)\n        {\n            _version_major =  1;\n            _version_minor = 1;\n        }\n    }\n\n    void SetCookie(std::string const& name, std::string const& value)\n    {\n        Cookie cookie(name, value);\n        cookie.ApplyHttpVersion(_version_major, _version_minor);\n        SetCookie(cookie);\n    }\n\n    void SetSecureCookie(std::string const& name, std::string const& value)\n    {\n        Cookie cookie(name, value);\n        cookie.SetSecure(Cookie::Secure::for_https_only);\n        cookie.ApplyHttpVersion(_version_major, _version_minor);\n        SetCookie(cookie);\n    }\n\n    void SetCookie(std::string const& name, std::string const& value, Cookie::HttpOnly http_only)\n    {\n        Cookie cookie(name, value);\n        cookie.SetHttpOnly(http_only);\n        cookie.ApplyHttpVersion(_version_major, _version_minor);\n        SetCookie(cookie);\n    }\n\n    void SetSecureCookie(std::string const& name, std::string const& value, Cookie::HttpOnly http_only)\n    {\n        Cookie cookie(name, value);\n        cookie.SetSecure(Cookie::Secure::for_https_only);\n        cookie.SetHttpOnly(http_only);\n        cookie.ApplyHttpVersion(_version_major, _version_minor);\n        SetCookie(cookie);\n    }\n\n    void SetCookie(std::string const& name, std::string const& value\n                   , std::size_t max_age, Cookie::HttpOnly http_only = Cookie::HttpOnly::for_http_and_js)\n    {\n        Cookie cookie(name, value);\n        cookie.SetMaxAge(static_cast<int>(max_age));\n        cookie.SetHttpOnly(http_only);\n        cookie.ApplyHttpVersion(_version_major, _version_minor);\n        SetCookie(cookie);\n    }\n\n    void SetSecureCookie(std::string const& name, std::string const& value\n                         , std::size_t max_age, Cookie::HttpOnly http_only = Cookie::HttpOnly::for_http_and_js)\n    {\n        Cookie cookie(name, value);\n        cookie.SetSecure(Cookie::Secure::for_https_only);\n        cookie.SetMaxAge(static_cast<int>(max_age));\n        cookie.SetHttpOnly(http_only);\n        cookie.ApplyHttpVersion(_version_major, _version_minor);\n        SetCookie(cookie);\n    }\n\n    void SetCookie(std::string const& name, std::string const& value\n                   , std::string const& domain, std::string const& path\n                   , std::size_t max_age, Cookie::HttpOnly http_only = Cookie::HttpOnly::for_http_and_js)\n    {\n        Cookie cookie(name, value, domain, path);\n        cookie.SetHttpOnly(http_only);\n        cookie.SetMaxAge(static_cast<int>(max_age));\n        cookie.ApplyHttpVersion(_version_major, _version_minor);\n        SetCookie(cookie);\n    }\n\n    void SetSecureCookie(std::string const& name, std::string const& value\n                         , std::string const& domain, std::string const& path\n                         , std::size_t max_age, Cookie::HttpOnly http_only = Cookie::HttpOnly::for_http_and_js)\n    {\n        Cookie cookie(name, value, domain, path);\n        cookie.SetSecure(Cookie::Secure::for_https_only);\n        cookie.SetHttpOnly(http_only);\n        cookie.SetMaxAge(static_cast<int>(max_age));\n        cookie.ApplyHttpVersion(_version_major, _version_minor);\n        SetCookie(cookie);\n    }\n\n    void SetCookie(Cookie const& cookie);\n\n    void SetCookieExpiredImmediately(std::string const& name\n                                     , std::string const& domain = \"\"\n                                     , std::string const& path = \"\");\n\n    std::vector<Cookie> const& GetCookies() const\n    {\n        return _cookies;\n    }\n\n    std::vector<Cookie>& GetCookies()\n    {\n        return _cookies;\n    }\n\n    void Reset();\n\npublic:\n    void ReplyStatus(int code, std::string body = EmptyBody());\n\n    void ReplyOk();\n    void ReplyOk(const char* body);\n    void ReplyOk(std::string body);\n    void ReplyOk(Json const& result);\n\n    void ReplyOkJSON(std::string json_string,\n                     std::string const& content_type = \"application/json\",\n                     std::string const& content_encoding = \"utf-8\")\n    {\n        this->SetContentEncoding(content_encoding);\n        this->SetContentType(content_type);\n        ReplyOk(json_string);\n    }\n\n    void ReplyContinue()\n    {\n        _status_code = HTTP_STATUS_CONTINUE;\n    }\n\n    void ReplyNofound(std::string body = EmptyBody());\n    void ReplyGone(std::string body = EmptyBody());\n\n    void ReplyUnauthorized(std::string body = EmptyBody());\n    void ReplyNoAuthoritativeInfo(std::string body = EmptyBody());\n    void ReplyBadRequest(std::string body = EmptyBody());\n    void ReplyRangeNotSatisfiable(std::string body = EmptyBody());\n    void ReplyForbidden(std::string body = EmptyBody());\n    void ReplyMethodNotAllowed(std::string body = EmptyBody());\n    void ReplyHttpVersionNotSupported(std::string body = EmptyBody());\n\n    void ReplyPayloadTooLarge(std::string body = EmptyBody());\n    void ReplyUriTooLong(std::string body = EmptyBody());\n    void ReplyTooManyRequests(std::string body = EmptyBody());\n    void ReplyLengthRequired()\n    {\n        _status_code = HTTP_STATUS_LENGTH_REQUIRED;\n    }\n    void ReplyNotImplemented(std::string body = EmptyBody());\n    void ReplyUnsupportedMediaType(std::string body = EmptyBody());\n\n    void ReplyServiceUnavailable(std::string body = EmptyBody());\n    void ReplyInternalServerError(std::string body = EmptyBody());\n\n    void ReplyMovedPermanently(std::string const& dst_location, std::string body = EmptyBody());\n\n    enum class RedirectType {temporary,  permanent};\n    void ReplyRedirect(std::string const& dst_location\n                       , RedirectType type = RedirectType::temporary\n                       , std::string body = EmptyBody());\n\nprivate:\n    void set_or_default_body(std::string body, bool provide_default_if_body_is_empty = true);\n    void add_server_header();\nprivate:\n    int _status_code = HTTP_STATUS_OK;\n\n    ICHeaders _headers;\n    std::string _body;\n    std::string _charset = \"UTF-8\";\n\n    unsigned short _version_major = 1;\n    unsigned short _version_minor = 1;\n\n    std::vector<Cookie> _cookies;\nprivate:\n    ChunkedBodies _chunked_bodies;\n};\n\nstd::ostream& operator << (std::ostream& os, Response const& res);\n\n} //namespace da4qi4\n\n#endif // DAQI_RESPONSE_HPP\n"
  },
  {
    "path": "include/daqi/router.hpp",
    "content": "#ifndef DAQI_ROUTER_HPP\n#define DAQI_ROUTER_HPP\n\n#include <map>\n#include <list>\n#include <regex>\n\n#include \"daqi/utilities/string_utilities.hpp\"\n#include \"daqi/handler.hpp\"\n\nnamespace da4qi4\n{\n\nstruct UniformItem\n{\n    UniformItem() = default;\n    UniformItem(std::string const& url_matcher)\n        : url_matcher(url_matcher)\n    {}\n\n    std::string method;\n    std::string url_matcher;\n    std::string template_name;\n};\n\nstruct RouterItem\n{\n    std::map<HandlerMethod, Handler> handlers;\n    std::string template_name;\n};\n\nstruct RouterResult\n{\n    RouterResult() = default;\n\n    RouterResult(RouterItem* item, HandlerMethod method)\n    {\n        if (item)\n        {\n            template_name = item->template_name;\n\n            auto it = item->handlers.find(method);\n\n            if (it != item->handlers.end())\n            {\n                handler = &(it->second);\n            }\n        }\n    }\n\n    Handler* handler = nullptr;\n    std::string template_name;\n    std::string error;\n};\n\nstruct router_equals\n{\n    explicit router_equals(std::string const& s)\n        : s(s)\n    {}\n\n    operator std::string& ()\n    {\n        return s;\n    }\n\n    std::string s;\n};\n\nstruct router_starts\n{\n    explicit router_starts(std::string const& s)\n        : s(s)\n    {}\n\n    operator std::string& ()\n    {\n        return s;\n    }\n\n    std::string s;\n};\n\nstruct router_regex\n{\n    explicit router_regex(std::string const& s)\n        : s(s)\n    {}\n\n    operator std::string&  ()\n    {\n        return s;\n    }\n\n    std::string s;\n};\n\nrouter_equals operator \"\" _router_equals(char const* str, std::size_t n);\nrouter_starts operator \"\" _router_starts(char const* str, std::size_t n);\nrouter_regex operator \"\" _router_regex(char const*  str, std::size_t n);\n\ntemplate<typename IMP, typename Result, bool try_auto_make_template_name>\nclass RoutingTable\n{\nprivate:\n    IMP* imp()\n    {\n        return static_cast<IMP*>(this);\n    }\n\npublic:\n    bool Add(std::string const& url_matcher, HandlerMethod method,  Handler handler,\n             std::string const& template_name, std::string& error)\n    {\n        assert(!url_matcher.empty());\n\n        typename IMP::Item* item = imp()->Exists(url_matcher);\n\n        if (!item)\n        {\n            typename IMP::Item ri;\n\n            ri.template_name = template_name;\n\n            if (ri.template_name.empty() && try_auto_make_template_name)\n            {\n                ri.template_name = url_matcher;\n            }\n\n            if (!ri.template_name.empty() && *(--ri.template_name.end()) == '/')\n            {\n                ri.template_name += \"index\";\n            }\n\n            ri.handlers[method] = handler;\n            return imp()->Insert(url_matcher, ri, error);\n        }\n        else\n        {\n            item->handlers[method] = handler;\n            return true;\n        }\n    }\n\n    bool Add(std::string const& url_matcher, HandlerMethods methods, Handler handler,\n             std::string const& template_name, std::string& error)\n    {\n        for (size_t i = 0; i < methods.mark.size(); ++i)\n        {\n            if (methods.mark[i])\n            {\n                HandlerMethod method = static_cast<HandlerMethod>(i);\n\n                std::string const* p_template_name = (template_name.empty() ?\n                                                      &url_matcher : &template_name);\n\n                if (!this->Add(url_matcher, method, handler, *p_template_name, error))\n                {\n                    return false;\n                }\n            }\n        }\n\n        return true;\n    }\n\n    Result Search(std::string const& url, HandlerMethod method, bool& url_exists)\n    {\n        return imp()->Match(url, method, url_exists);\n    }\n};\n\nclass EqualsRoutingTable : public RoutingTable<EqualsRoutingTable, RouterResult, true>\n{\n    using Map = std::map<std::string, RouterItem, Utilities::IgnoreCaseCompare>;\npublic:\n    using Item = RouterItem;\n\n    using Result = RouterResult;\n\n    bool Insert(std::string const&  url_matcher, RouterItem const& item, std::string& error)\n    {\n        error.clear();\n        _map.insert(std::make_pair(url_matcher, item));\n        return true;\n    }\n\n    Item* Exists(std::string const& url_matcher)\n    {\n        auto it = _map.find(url_matcher);\n        return (it == _map.end() ? nullptr : & (it->second));\n    }\n\n    Result Match(std::string const& url, HandlerMethod method, bool& url_exists)\n    {\n        auto item = this->Exists(url);\n        url_exists = (item != nullptr);\n        return Result(item, method);\n    }\n\n    std::vector<UniformItem> Uniforms() const;\n\nprivate:\n    Map _map;\n};\n\nstruct StartsRouterResult : public RouterResult\n{\n    StartsRouterResult() = default;\n    StartsRouterResult(RouterItem* item, HandlerMethod method, std::string const& key)\n        : RouterResult(item, method), key(key)\n    {}\n\n    std::string key;\n};\n\nclass StartsWithRoutingTable\n    : public RoutingTable<StartsWithRoutingTable, StartsRouterResult, false>\n{\n    using Map = std::map<std::string, RouterItem, Utilities::IgnoreCaseCompareDESC>;\npublic:\n    using Item = RouterItem;\n    using Result = StartsRouterResult;\n\n    bool Insert(std::string const&  url_matcher, RouterItem const& item, std::string& error)\n    {\n        error.clear();\n        _map.insert(std::make_pair(url_matcher, item));\n        return true;\n    }\n\n    Item* Exists(std::string const& url_matcher)\n    {\n        auto it = _map.find(url_matcher);\n        return (it == _map.end() ? nullptr : & (it->second));\n    }\n\n    Result Match(std::string const& url, HandlerMethod method, bool& url_exists);\n    std::vector<UniformItem> Uniforms() const;\n\nprivate:\n    Map _map;\n};\n\n\nstruct UniformRegexItem : public UniformItem\n{\n    using UniformItem::UniformItem;\n\n    std::string regex_matcher;\n};\n\nstruct RegexRouterItem : public RouterItem\n{\n    std::string url_matcher;\n    std::string regex_matcher;\n    std::regex regex_pattern;\n\n    RegexRouterItem() = default;\n\n    explicit RegexRouterItem(RouterItem const& base)\n        : RouterItem(base)\n    {\n    }\n\n    std::vector<std::string> parameters;\n};\n\nstruct RegexRouterResult : public RouterResult\n{\n    RegexRouterResult() = default;\n    RegexRouterResult(RegexRouterItem* item, HandlerMethod method)\n        : RouterResult(static_cast<RouterItem*>(item), method)\n    {}\n\n    std::vector<std::string> parameters;\n    std::vector<std::string> values;\n};\n\nclass RegexMatchRoutingTable :\n    public RoutingTable<RegexMatchRoutingTable, RegexRouterResult, false>\n{\nprivate:\n    using List = std::list <RegexRouterItem>;\n\npublic:\n    using Item = RegexRouterItem;\n    using Result = RegexRouterResult;\n\n    bool Insert(std::string const&    url_matcher, RouterItem const& item, std::string& error);\n    Item* Exists(std::string const& url_matcher);\n    Result Match(std::string const& url, HandlerMethod method, bool& url_exists);\n\n    std::vector<UniformRegexItem> Uniforms() const;\n\nprivate:\n    List _lst;\n};\n\n} //namespace da4qi4\n\nda4qi4::router_equals operator \"\" _da4qi4_router_equals(char const* str, std::size_t n);\nda4qi4::router_starts operator \"\" _da4qi4_router_starts(char const* str, std::size_t n);\nda4qi4::router_regex operator \"\" _da4qi4_router_regex(char const*  str, std::size_t n);\n\n#endif // DAQI_ROUTER_HPP\n"
  },
  {
    "path": "include/daqi/server.hpp",
    "content": "#ifndef DAQI_SERVER_HPP\n#define DAQI_SERVER_HPP\n\n#include <atomic>\n#include <list>\n#include <string>\n#include <functional>\n\n#include <boost/asio/deadline_timer.hpp>\n\n#include \"daqi/def/asio_def.hpp\"\n\n#include \"daqi/server_engine.hpp\"\n#include \"daqi/application.hpp\"\n#include \"daqi/handler.hpp\"\n\nnamespace da4qi4\n{\n\nextern int const _detect_templates_interval_seconds_;\n\nclass Server\n{\npublic:\n    enum class WithSSL {no, yes};\n\n    using OnNeedSSLPassword = std::function <std::string(std::size_t max_length\n                                                         , SSLContextBase::password_purpose purpose)>;\n    struct SSLOptions\n    {\n        enum class PrivateKeyType  {normal, RSA};\n\n        explicit SSLOptions()\n            : options(boost::asio::ssl::context::default_workarounds\n                      | boost::asio::ssl::context::no_sslv2\n                      | boost::asio::ssl::context::no_sslv3\n                      | boost::asio::ssl::context::no_tlsv1)\n            , private_key_type(PrivateKeyType::normal), private_key_file_format(SSLContextBase::pem)\n            , will_verify_client(false), on_need_password(nullptr)\n        {\n        }\n\n        explicit SSLOptions(OnNeedSSLPassword&& password_callback)\n            : options(boost::asio::ssl::context::default_workarounds\n                      | boost::asio::ssl::context::no_sslv2\n                      | boost::asio::ssl::context::no_sslv3\n                      | boost::asio::ssl::context::no_tlsv1)\n            , private_key_type(PrivateKeyType::normal), private_key_file_format(SSLContextBase::pem)\n            , will_verify_client(false)\n            , on_need_password(std::forward<OnNeedSSLPassword>(password_callback))\n        {\n        }\n\n        SSLOptions(SSLContextBase::options options)\n            : options(options)\n            , private_key_file_format(SSLContextBase::pem)\n        {\n        }\n\n        SSLOptions(SSLContextBase::options options, OnNeedSSLPassword&& password_callback)\n            : options(options)\n            , private_key_type(PrivateKeyType::normal)\n            , private_key_file_format(SSLContextBase::pem)\n            , on_need_password(std::forward<OnNeedSSLPassword>(password_callback))\n        {\n        }\n\n        void EnableSSLV3()\n        {\n            options &= ~boost::asio::ssl::context::no_sslv3;\n        }\n\n        void EnableTLSV1()\n        {\n            options &= ~boost::asio::ssl::context::no_tlsv1;\n        }\n\n        void EnableVerifyClient()\n        {\n            will_verify_client = true;\n        }\n\n        void DisableVerifyClient()\n        {\n            will_verify_client = false;\n        }\n\n        void InitFiles(std::string certificate_chain_file\n                       , std::string private_key_file\n                       , PrivateKeyType private_key_type = PrivateKeyType::normal\n                       , std::string tmp_DiffieHellman_file = \"\"\n                       , SSLContextBase::file_format private_key_file_format = SSLContextBase::pem)\n        {\n            this->certificate_chain_file = std::move(certificate_chain_file);   //.pem\n\n            this->private_key_file = std::move(private_key_file);               //.key\n            this->private_key_type = private_key_type;                          //is RSA private key?\n            this->private_key_file_format = private_key_file_format;\n\n            if (!tmp_DiffieHellman_file.empty())\n            {\n                this->tmp_DiffieHellman_file = std::move(tmp_DiffieHellman_file);\n                options |= SSLContextBase::single_dh_use;\n            }\n        }\n\n        SSLContextBase::options options;\n\n        std::string certificate_chain_file;\n\n        std::string private_key_file;\n        PrivateKeyType private_key_type;\n        SSLContextBase::file_format private_key_file_format;\n\n        std::string tmp_DiffieHellman_file;\n\n        bool will_verify_client;\n\n        OnNeedSSLPassword on_need_password;\n    };\n\nprivate:\n    Server(Tcp::endpoint endpoint, size_t thread_count, SSLOptions const* ssl_opts = nullptr);\n\npublic:\n    using IdleFunction = std::function<void (void)>;\n\n    using Ptr = std::unique_ptr<Server>;\n\n    static Ptr Supply(unsigned short port, size_t thread_count);\n    static Ptr Supply(std::string const& host, unsigned short port, size_t thread_count);\n\n    static Ptr Supply(std::string const& host, unsigned short port);\n    static Ptr Supply(unsigned short port = 80);\n\n\n    static Ptr SupplyWithSSL(SSLOptions const& ssl_opt, unsigned short port, size_t thread_count);\n    static Ptr SupplyWithSSL(SSLOptions const& ssl_opt\n                             , std::string const& host, unsigned short port, size_t thread_count);\n\n    static Ptr SupplyWithSSL(SSLOptions const& ssl_opt, std::string const& host, unsigned short port);\n    static Ptr SupplyWithSSL(SSLOptions const& ssl_opt, unsigned short port = 443);\n\n    ~Server();\n\n    IOContextPool* GetIOContextPool()\n    {\n        return &_ioc_pool;\n    }\n\npublic:\n    bool IsWithSSL() const\n    {\n        return _withssl == WithSSL::yes;\n    }\npublic:\n    void Run();\n    void Stop();\n\npublic:\n    void PauseIdleTimer();\n    void ResumeIdleTimer();\n\n    bool IsIdleTimerRunning() const\n    {\n        return _idle_running;\n    }\n\n    void EnableDetectTemplates(int interval_seconds = _detect_templates_interval_seconds_)\n    {\n        assert(interval_seconds > 0);\n\n        _detect_templates_status.interval_seconds = interval_seconds;\n        _detect_templates_status.next_timepoint = std::time(nullptr) + interval_seconds;\n\n        _detect_templates = true;\n\n        if (_running && !_idle_running)\n        {\n            ResumeIdleTimer();\n        }\n    }\n\n    void DisableDetectTemplates()\n    {\n        _detect_templates = false;\n    }\n\n    bool IsEnabledDetetTemplates() const\n    {\n        return _detect_templates;\n    }\n\n    void AppendIdleFunction(int interval_seconds, IdleFunction func);\n\npublic:\n    ApplicationPtr DefaultApp(std::string const& name = \"\");\n\n    bool Mount(ApplicationPtr app);\n\npublic:\n    ApplicationPtr AddHandler(HandlerMethod m, std::string const& url, Handler h)\n    {\n        return AddHandler(m, router_equals(url), h);\n    }\n\n    ApplicationPtr AddHandler(HandlerMethod m, router_equals r, Handler h);\n    ApplicationPtr AddHandler(HandlerMethod m, router_starts r, Handler h);\n    ApplicationPtr AddHandler(HandlerMethod m, router_regex r, Handler h);\n\n    ApplicationPtr AddHandler(HandlerMethods ms, std::string const& url, Handler h)\n    {\n        return AddHandler(ms, router_equals(url), h);\n    }\n    ApplicationPtr AddHandler(HandlerMethods ms, router_equals r, Handler h);\n    ApplicationPtr AddHandler(HandlerMethods ms, router_starts r, Handler h);\n    ApplicationPtr AddHandler(HandlerMethods ms, router_regex r, Handler h);\n\n    bool AddEqualsRouter(HandlerMethod m, std::vector<std::string> const& urls, Handler h);\n    bool AddStartsRouter(HandlerMethod m, std::vector<std::string> const& urls, Handler h);\n    bool AddRegexRouter(HandlerMethod m, std::vector<std::string> const& urls, Handler h);\n\npublic:\n    ApplicationPtr PrepareApp(std::string const& url);\n\nprivate:\n    void start_accept();\n    void do_accept();\n    void do_stop();\n\nprivate:\n    void make_default_app_if_empty();\n    void make_default_app(std::string const& name);\n\n    void start_idle_timer();\n    void on_idle_timer(errorcode const& ec);\n    void stop_idle_timer();\n\nprivate:\n    WithSSL _withssl;\n    int _idle_interval_seconds;\n\nprivate:\n    std::atomic_bool _running;\n    std::atomic_bool _stopping;\n\n    IOContextPool _ioc_pool;\n    Tcp::acceptor _acceptor;\n    boost::asio::signal_set _signals;\n    std::unique_ptr<boost::asio::ssl::context> _ssl_ctx;\n\n    std::atomic_bool _idle_running;\n\n    std::atomic_bool _detect_templates;\n    boost::asio::deadline_timer _idle_timer;\n\n    struct IdleFunctionStatus\n    {\n        IdleFunctionStatus()\n            : interval_seconds(0), next_timepoint(static_cast<std::time_t>(0))\n        {}\n\n        IdleFunctionStatus(IdleFunctionStatus const&) = default;\n\n        IdleFunctionStatus(int interval_seconds, IdleFunction func)\n            : interval_seconds(interval_seconds),\n              next_timepoint(std::time(nullptr) + interval_seconds), func(func)\n        {}\n\n        int interval_seconds;\n        std::time_t next_timepoint;\n        IdleFunction func;\n    };\n\n    IdleFunctionStatus _detect_templates_status;\n    std::list<IdleFunctionStatus> _idle_functions;\n\nprivate:\n    static int call_idle_function_if_timeout(std::time_t now, IdleFunctionStatus& status);\n};\n\n}\n\n#endif // DAQI_SERVER_HPP\n"
  },
  {
    "path": "include/daqi/server_engine.hpp",
    "content": "#ifndef DAQI_SERVER_ENGINE_HPP\n#define DAQI_SERVER_ENGINE_HPP\n\n#include <memory>\n#include <thread>\n\n#include <list>\n#include <vector>\n#include <atomic>\n\n#include <boost/asio.hpp>\n#include <boost/noncopyable.hpp>\n\n#include \"def/asio_def.hpp\"\n\nnamespace da4qi4\n{\n\nclass IOContextPool\n    : private boost::noncopyable\n{\npublic:\n    explicit IOContextPool(std::size_t pool_size = 0);\n\n    void Run();\n    void Stop();\n\n    size_t Size() const\n    {\n        return _io_contexts.size();\n    }\n\n    IOC& GetIOContext();\n\n    std::pair<IOC&, size_t> GetIOContextAndIndex();\n    IOC& GetIOContextByIndex(size_t index);\n\nprivate:\n    using IOContextPtr = std::shared_ptr<IOC>;\n#ifdef HAS_IO_CONTEXT\n    using IOContextWork = boost::asio::executor_work_guard<IOC::executor_type>;\n#else\n    using IOContextWork = std::unique_ptr<IOC::work>;\n#endif\n\n    std::atomic_bool _stopping;\n\n    std::vector<IOContextPtr> _io_contexts;\n\n    std::list<IOContextWork> _work;\n    std::size_t _next_index;\n\n    std::vector<std::shared_ptr<std::thread>> _threads;\n};\n\n} //namespace da4qi4\n#endif // DAQI_SERVER_ENGINE_HPP\n"
  },
  {
    "path": "include/daqi/session.hpp",
    "content": "#ifndef DAQI_SESSION_HPP\n#define DAQI_SESSION_HPP\n\n#include <string>\n\n#include \"daqi/def/json_def.hpp\"\n#include \"daqi/cookie.hpp\"\n\nnamespace da4qi4\n{\n\nJson MakeNewSession(Cookie const& cookie);\nCookie GetSessionCookie(Json const& session);\n\nextern std::string const session_cookie_name;\n\nstruct SessionOptions\n{\n    std::string name = \"session_id\";\n    std::string prefix = \"sid:\";\n    bool prefix_with_time = true;\n    std::string domain;\n    std::string path = \"/\";\n    int max_age = 1800;\n    Cookie::HttpOnly http_only = Cookie::HttpOnly::for_http_only;\n    Cookie::Secure secure = Cookie::Secure::for_http_and_https;\n    Cookie::SameSite samesite = Cookie::SameSite::none;\n};\n\n} //namespace da4qi4\n\n#endif // DAQI_SESSION_HPP\n"
  },
  {
    "path": "include/daqi/templates.hpp",
    "content": "#ifndef DAQI_TEMPLATES_HPP\n#define DAQI_TEMPLATES_HPP\n\n#include <string>\n#include <mutex>\n#include <vector>\n#include <unordered_map>\n\n#include \"daqi/def/inja_def.hpp\"\n#include \"daqi/def/log_def.hpp\"\n\nnamespace da4qi4\n{\n\nvoid init_template_env(inja::Environment& env);\n\nstd::string const& get_daqi_HTML_template_ext();\nstd::string const& get_daqi_JSON_template_ext();\nstd::string const& get_daqi_XML_template_ext();\n\nstd::string make_daqi_template_ext(std::string const& ext);\n\nusing TemplatesEnv = inja::Environment;\n\nclass Templates\n{\npublic:\n    Templates()\n        : _disabled(false)\n    {}\n\n    Templates(Templates const&) = default;\n\n    Templates(std::string const& template_root, std::string const& app_url_root, std::string const& template_ext)\n        : _root(template_root), _app_prefix(app_url_root), _template_ext(template_ext), _disabled(false)\n    {}\n\n    void InitPathes(std::string const& template_root, std::string const& app_url_root, std::string const& template_ext)\n    {\n        auto len = template_root.size();\n\n        _root = (len && template_root[len - 1] == '/')\n                ? (template_root.substr(0, template_root.size() - 1))\n                : template_root;\n\n        _app_prefix = app_url_root;\n        _template_ext = template_ext;\n    }\n\n    bool Preload(log::LoggerPtr app_logger);\n\n    TemplatePtr const Get(std::string const& name);\n\n    void CopyIncludeTemplateTo(TemplatesEnv& env);\n\n    bool ReloadIfFindUpdate();\n    bool ReloadIfFindNew();\n\n    std::string const& GetRoot() const\n    {\n        return _root;\n    }\n\n    void Enable()\n    {\n        _disabled = false;\n    }\n\n    void Disable()\n    {\n        _disabled = true;\n    }\n\n    bool IsDisabled() const\n    {\n        return _disabled;\n    }\n\nprivate:\n    bool reload();\n\nprivate:\n    enum class TemplateFlag {for_normal, for_include};\n\n    std::pair<size_t, size_t>\n    load_templates(std::string const& template_ext, std::string const& key_ext);\n\n    std::pair<size_t, size_t>\n    load_templates(TemplatesEnv& env\n                   , std::string const& template_ext\n                   , std::string const& key_ext\n                   , TemplateFlag flag);\n\n    bool try_load_template(TemplatesEnv& env\n                           , std::string const& key\n                           , std::string const& template_filename\n                           , std::string const& full_template_filename\n                           , bool is_include_dir) noexcept;\n\n    enum class TemplateUpdateAction\n    {\n        none, appended, modified, removed\n    };\n\n    TemplateUpdateAction check_exists_template();\n\n    TemplateUpdateAction check_new_template(std::string const& template_ext\n                                            , std::string const& key_ext);\n\n    void hint_template_updated_found(TemplateUpdateAction action);\n    void hint_template_reload_fail();\n\n    struct Item\n    {\n        TemplatePtr templ;\n        std::string filename;\n    };\n\n    TemplateUpdateAction check_exists_template(std::unordered_map<std::string, Item> const& templates);\n\nprivate:\n    std::mutex _m;  // for _templates reload and get\n    log::LoggerPtr _app_logger;\n\n    std::time_t _loaded_time;\n    std::unordered_map<std::string, Item> _templates;\n    std::unordered_map<std::string, Item> _includes_templates;\n\n    std::string _root, _app_prefix, _template_ext;\n    bool _disabled;\n};\n\n} //namesapce da4qi4\n\n#endif // DAQI_TEMPLATE_LIBRARY_HPP\n"
  },
  {
    "path": "include/daqi/url.hpp",
    "content": "#ifndef DAQI_URL_HPP\n#define DAQI_URL_HPP\n\n#include <string>\n\n#include \"daqi/def/def.hpp\"\n\nnamespace da4qi4\n{\n\nstruct UrlBase\n{\n    std::string full;\n\n    std::string schema;\n    std::string host;\n\n    unsigned short port;\n\n    std::string path;\n    std::string query;\n    std::string fragment;\n    std::string userinfo;\n\n    UrlParameters parameters;\n\n    bool Parse(std::string&& url_value);\n\n    void Clear()\n    {\n        full.clear();\n        schema.clear();\n        host.clear();\n        port = 0;\n        path.clear();\n        query.clear();\n        fragment.clear();\n        userinfo.clear();\n        parameters.clear();\n    }\n};\n\nstruct UrlUnderApp : public UrlBase\n{\n    std::string full_under_app;\n    std::string path_under_app;\n\n    void UnderApplication(std::string const& app_url_root);\n};\n\nUrlBase FromUrlUnderApp(UrlUnderApp&& src);\n\ntypedef UrlUnderApp Url;\n\nenum class UrlFlag\n{\n    url_full_path, url_without_app_root\n};\n\nstd::string JoinUrlPath(std::string const& app_root, std::string const& path);\nstd::string MakesureFullUrlPath(std::string const& path, UrlFlag flag, std::string const& app_root);\n\n} //namespace da4qi4\n\n#endif // DAQI_URL_HPP\n"
  },
  {
    "path": "include/daqi/utilities/asio_utilities.hpp",
    "content": "#ifndef DAQI_ASIO_UTILITIES_HPP\n#define DAQI_ASIO_UTILITIES_HPP\n\n#include <string>\n#include <vector>\n#include <functional>\n\n#include \"daqi/def/asio_def.hpp\"\n#include \"daqi/def/boost_def.hpp\"\n\nnamespace da4qi4\n{\nnamespace Utilities\n{\n\nTcp::endpoint make_endpoint(char const* host, unsigned short port);\nTcp::endpoint make_endpoint(std::string const& host, unsigned short port);\n\nstd::vector<Tcp::endpoint> from_http_host_sync(std::string const& host, IOC& ioc\n                                               , std::string const& service //http ? https?\n                                               , std::string& exception);\n\nusing HostResolveHandler = std::function<void (errorcode const& ec, ResolverResultT)>;\nvoid from_host(std::string const& host\n               , std::string const& service //http ? https? or port numbers\n               , Tcp::resolver& resolver, HostResolveHandler handler);\n\nResolverResultT from_host(std::string const& host\n                          , std::string const& service //http ? https? or port numbers\n                          , Tcp::resolver& resolver\n                          , errorcode& ec);\n} //namespace Utilities\n} //namespace da4qi4\n\n\n#endif // DAQI_ASIO_UTILITIES_HPP\n"
  },
  {
    "path": "include/daqi/utilities/base64_utilities.hpp",
    "content": "#ifndef DAQI_BASE64_HPP\n#define DAQI_BASE64_HPP\n\n#include <cstdint>\n#include <string>\n\nnamespace da4qi4\n{\nnamespace Utilities\n{\n\nstd::string Base64Encode(std::uint8_t const* value, std::size_t len);\nstd::string Base64Encode(std::string const& value);\nstd::string Base64Decode(std::string const& base64);\n\n} // namespace Utilities\n} // namespace da4qi4\n\n#endif // DAQI_BASE64_HPP\n"
  },
  {
    "path": "include/daqi/utilities/container_utilities.hpp",
    "content": "#ifndef DAQI_CONTAINER_UTILITIES_HPP\n#define DAQI_CONTAINER_UTILITIES_HPP\n\n#include <string>\n\n#include \"daqi/def/def.hpp\"\n#include \"daqi/def/boost_def.hpp\"\n#include \"daqi/utilities/string_utilities.hpp\"\n\nnamespace da4qi4\n{\nnamespace Utilities\n{\n\ntemplate<typename HeadersT>\nbool IsExistsHeader(HeadersT const& headers, std::string const& field)\n{\n    auto const it = headers.find(field);\n    return it != headers.cend();\n}\n\ntemplate<typename HeadersT>\nstd::string const& GetHeader(HeadersT const& headers, std::string const& field)\n{\n    auto const it = headers.find(field);\n    return (it != headers.cend() ? it->second : Utilities::theEmptyString);\n}\n\ntemplate<typename HeadersT>\nOptionalStringRefConst TryGetHeader(HeadersT const& headers, std::string const& field)\n{\n    auto const it = headers.find(field);\n    return (it == headers.cend() ? OptionalStringRefConst(NoneObject)\n            : OptionalStringRefConst(it->second));\n}\n\n} //namespace Utilities\n} //namespace da4qi4\n\n#endif // DAQI_CONTAINER_UTILITIES_HPP\n\n"
  },
  {
    "path": "include/daqi/utilities/des3_utilities.hpp",
    "content": "#ifndef DAQI_DES3_UTILITIES_HPP\n#define DAQI_DES3_UTILITIES_HPP\n\n#include <string>\n\nnamespace da4qi4\n{\nnamespace Utilities\n{\n\nstd::string DESEncrypt(std::string const& clearText, std::string const& key);\nstd::string DESDecrypt(std::string const& cipherText, std::string const& key);\n\n} // namespace Utilities\n} // namespace da4qi4\n\n#endif // DES3_UTILITIES_HPP\n"
  },
  {
    "path": "include/daqi/utilities/encoding_utilities.hpp",
    "content": "#ifndef ENCODING_UTILITIES_HPP\n#define ENCODING_UTILITIES_HPP\n\n#include <iconv.h>\n#include <string>\n\nnamespace da4qi4\n{\nnamespace Utilities\n{\n\nnamespace iconvpp\n{\n\nclass Converter\n{\npublic:\n    Converter(char const* in_encode, char const* out_encode,\n              bool _ignore_error = false, std::size_t const& buf_size = 1024);\n\n    ~Converter();\n\n    std::string const& Error() const\n    {\n        return _err;\n    };\n\n    operator bool () const noexcept\n    {\n        return _err.empty() && _iconv && (_iconv != reinterpret_cast<iconv_t>(-1));\n    }\n\n    bool operator !() const noexcept\n    {\n        return !_err.empty() || !_iconv || (_iconv == reinterpret_cast<iconv_t>(-1));\n    }\n\n    std::size_t IgnoreCount() const noexcept\n    {\n        return _ignore_count;\n    }\n\n    bool Convert(std::string const& input, std::string& output);\n\nprivate:\n    iconv_t _iconv;\n    bool _ignore_error;\n    const size_t _buf_size;\n    std::string _err;\n    std::size_t _ignore_count;\n};\n\n} //namespace iconvpp\n\nstd::wstring FromUTF8(std::string const& utf8str, std::string& err);\nstd::string ToUTF8(std::wstring const& wstr, std::string& err);\n\nstd::wstring FromUTF8(std::string const& utf8str);\nstd::string ToUTF8(std::wstring const& wstr);\n\nstd::string ToGBK(std::string const& utf8str, std::string& err);\nstd::string ToGBK(std::string const& utf8str);\n\nstd::string FromGBK(std::string const& gbkstr, std::string& err);\nstd::string FromGBK(std::string const& gbkstr);\n\n} //namespace Utilities\n} //namespace da4qi4\n\n#endif // ENCODING_UTILITIES_HPP\n"
  },
  {
    "path": "include/daqi/utilities/file_utilities.hpp",
    "content": "#ifndef DAQI_FILE_UTILITIES_HPP\n#define DAQI_FILE_UTILITIES_HPP\n\n#include <string>\n#include \"daqi/def/boost_def.hpp\"\n\nnamespace da4qi4\n{\nnamespace Utilities\n{\n\nbool SaveDataToFile(std::string const& data, std::string const& filename_with_path, std::string& err);\nbool SaveDataToFile(std::string const& data, fs::path const& filename_with_path, std::string& err);\n\nbool IsFileExists(fs::path const& fullpath);\nbool IsFileExists(std::string const& fullpath);\n\nenum class FileOverwriteOptions\n{\n    ignore_success,\n    ignore_fail,\n    overwrite\n};\n\nstd::pair<bool, std::string /*msg*/>\nCopyFile(fs::path const& src, fs::path const& dst, FileOverwriteOptions overwrite);\n\nstd::pair<bool, std::string /*msg*/>\nMoveFile(fs::path const& src, fs::path const& dst, FileOverwriteOptions overwrite);\n\n} //namesapce Utilities\n} //namespace da4qi4\n\n#endif // DAQI_FILE_UTILITIES_HPP\n"
  },
  {
    "path": "include/daqi/utilities/hmac_sha1_utilities.hpp",
    "content": "#ifndef DAQI_HMAC_SHA1_UTILITIES_HPP\n#define DAQI_HMAC_SHA1_UTILITIES_HPP\n\n#include <cstdint>\n#include <vector>\n#include <string>\n\nnamespace da4qi4\n{\nnamespace Utilities\n{\n\nstd::vector<std::uint8_t> HMA_SHA1(std::string const& key, std::string const& src);\nstd::vector<std::uint8_t> HMA_SHA1(char const* key, int key_size, std::string const& src);\nstd::vector<std::uint8_t> HMA_SHA1(char const* key, int key_size, char const* src,  std::size_t src_size);\n\nstd::vector<std::uint8_t> SHA1(std::string const& src);\nstd::vector<std::uint8_t> SHA1(unsigned char const*& src, std::size_t src_size);\nstd::vector<std::uint8_t> SHA1(std::vector<unsigned char> const& src);\n\n} // namespace Utilities\n} // namespace da4qi4\n\n#endif // DAQI_HMAC_SHA1_UTILITIES_HPP\n"
  },
  {
    "path": "include/daqi/utilities/html_utilities.hpp",
    "content": "#ifndef DAQI_HTML_UTILITIES_HPP\n#define DAQI_HTML_UTILITIES_HPP\n\n#include <string>\n#include <map>\n#include <unordered_map>\n\nnamespace da4qi4\n{\nnamespace Utilities\n{\n\nstd::string const& GetMIMEType(std::string const&  extension);\nstd::string HTMLEscape(std::string const& s);\n\n} //Utilities\n} //da4qi4\n\n#endif // DAQI_HTML_UTILITIES_HPP\n"
  },
  {
    "path": "include/daqi/utilities/http_utilities.hpp",
    "content": "#ifndef DAQI_HTTP_UTILITIES_HPP\n#define DAQI_HTTP_UTILITIES_HPP\n\n#include <string>\n#include <map>\n\nnamespace da4qi4\n{\nnamespace Utilities\n{\n\nbool IsUrlEncoded(const std::string& value);\nstd::string UrlEncode(const std::string& value);\nstd::string UrlDecode(const std::string& value);\nstd::string UrlDecodeIfEncoded(std::string const& value);\n\nstd::map<std::string, std::string> ParseQueryParameters(std::string const& query);\nstd::map<std::string, std::string> ParsePlainTextFormData(std::string const& body); \n\n} //Utilities\n} //da4qi4\n\n#endif // DAQI_HTTP_UTILITIES_HPP\n"
  },
  {
    "path": "include/daqi/utilities/md5_utilities.hpp",
    "content": "#ifndef DAQI_MD5_UTILITIES_HPP\n#define DAQI_MD5_UTILITIES_HPP\n\n#include <string>\n\nnamespace da4qi4\n{\nnamespace Utilities\n{\n\nenum class MD5ResultEncoding\n{\n    raw, hex\n};\n\nstd::string MD5(const std::string& src, MD5ResultEncoding encoding = MD5ResultEncoding::hex);\n\n} //namespace Utilities\n} //namespace da4qi4\n#endif // DAQI_MD5_UTILITIES_HPP\n"
  },
  {
    "path": "include/daqi/utilities/string_utilities.hpp",
    "content": "#ifndef DAQI_STRING_UTILITIES_HPP\n#define DAQI_STRING_UTILITIES_HPP\n\n#include <ctime>\n#include <string>\n#include <vector>\n#include <map>\n\nnamespace da4qi4\n{\nnamespace Utilities\n{\n\nextern std::string const theEmptyString;\n\nextern char const* dt_fmt_gmt;\nextern char const* dt_fmt_yyyy_mm_dd_hh_mm_ss;\nextern char const* dt_fmt_yyyy_mm_dd;\nextern char const* dt_fmt_yyyy_mm_dd_hh_mm_ss_CN;\nextern char const* dt_fmt_yyyy_mm_dd_CN;\n\nstd::string GMTFormatTime(std::time_t t);\nstd::string FormatDateTime(std::time_t t, char const* fmt = dt_fmt_yyyy_mm_dd_hh_mm_ss);\n\nstruct IgnoreCaseCompare\n{\n    bool operator()(std::string const& l, std::string const& r) const;\n};\n\nstruct IgnoreCaseCompareDESC\n{\n    bool operator()(std::string const& l, std::string const& r) const\n    {\n        IgnoreCaseCompare compare;\n        return compare(r, l); /* DESC : swap l, r */\n    }\n};\n\nstruct CompareDESC\n{\n    bool operator()(std::string const& l, std::string const& r) const\n    {\n        return r < l; /* DESC : swap l, r */\n    }\n};\n\nbool iStartsWith(std::string const& m, std::string const& s);\nbool iEquals(std::string const& l, std::string const& r);\nbool iLess(std::string const& l, std::string const& r);\nbool iEndsWith(std::string const& m, std::string const& s);\n\nbool StartsWith(std::string const& m, std::string const& s);\nbool EndsWith(std::string const& m, std::string const& s);\n\nstd::string ReplaceAll(std::string const& m, std::string const& bef, std::string const& aft);\n\nenum class TrimOptions {keep_space, trim_all, trim_left, trim_right};\nstd::vector<std::string> Split(std::string const& m, char c, TrimOptions opt = TrimOptions::keep_space);\nstd::vector<std::string> SplitByLine(std::string const& m, TrimOptions opt = TrimOptions::keep_space);\n\nvoid Trim(std::string& m);\nstd::string TrimCopy(std::string const& m);\n\nvoid TrimLeft(std::string& m);\nstd::string TrimLeftCopy(std::string const& m);\n\nvoid TrimRight(std::string& m);\nstd::string TrimRightCopy(std::string const& m);\n\nvoid TrimOnOptions(std::string& m, TrimOptions opt);\nstd::string TrimOnOptionsCopy(std::string const& m, TrimOptions opt);\n\nstd::string GetUUID(std::string const& prefix = theEmptyString);\n\nstd::string DecIntToHexStr(std::size_t num);\n\n} //namespace Utilities\n} //namespace da4qi4\n\n#endif // DAQI_STRING_UTILITIES_HPP\n"
  },
  {
    "path": "include/daqi/websocket/connection_websocket.hpp",
    "content": "#ifndef DAQI_CONNECTION_WEBSOCKET_HPP\n#define DAQI_CONNECTION_WEBSOCKET_HPP\n\n#include <memory>\n#include <string>\n#include <mutex>\n#include <list>\n\n#include \"daqi/url.hpp\"\n#include \"daqi/net-detail/net_detail_server.hpp\"\n\n#include \"daqi/websocket/frame_websocket.hpp\"\n#include \"daqi/websocket/handler_websocket.hpp\"\n\nnamespace da4qi4\n{\nnamespace Websocket\n{\n\nenum class WriteDataType {continuation = 0, text = 1, binary = 2};\n\nclass Connection final : public std::enable_shared_from_this<Connection>\n{\n    Connection(size_t _ioc_index, net_detail::SocketInterface* socket\n               , UrlUnderApp&& url, ICHeaders&& headers, ICCookies&& cookies\n               , EventsHandler* handler);\n\npublic:\n    using Ptr = std::shared_ptr<Connection>;\n\n    static Ptr Create(size_t ioc_index, net_detail::SocketInterface* socket\n                      , UrlUnderApp&& url, ICHeaders&& headers, ICCookies&& cookies\n                      , EventsHandler* handler);\n\n    Connection(const Connection&) = delete;\n    Connection& operator=(const Connection&) = delete;\n\npublic:\n    bool IsWithSSL() const\n    {\n        return (_socket_ptr ? _socket_ptr->IsWithSSL() : false);\n    }\n\n    size_t GetIOContextIndex() const\n    {\n        return _ioc_index;\n    }\n\n    Tcp::socket& GetSocket()\n    {\n        return _socket_ptr->get_socket();\n    }\n\npublic:\n    std::string GetURLPath() const;\n\n    std::string const& GetID() const\n    {\n        return _id;\n    }\n\n    void SetID(std::string const& id)\n    {\n        _id = id;\n    }\n\n    Url const* GetURLDataPtr() const\n    {\n        return _url.get();\n    }\n\n    void ClearURLData()\n    {\n        if (_url)\n        {\n            makesure_url_path_storaged();\n            _url->Clear();\n        }\n    }\n\n    void ReleaseURLData()\n    {\n        if (_url)\n        {\n            makesure_url_path_storaged();\n            _url.reset();\n        }\n    }\n\n    ICHeaders const& GetHeaders() const\n    {\n        return _headers;\n    }\n\n    ICHeaders& GetHeaders()\n    {\n        return _headers;\n    }\n\n    void ClearHeaders()\n    {\n        _headers.clear();\n    }\n\n    ICCookies const& GetCookies() const\n    {\n        return _cookies;\n    }\n\n    ICCookies& GetCookies()\n    {\n        return _cookies;\n    }\n\n    void ClearCookies()\n    {\n        _cookies.clear();\n    }\n\n    void RemoveHttpInfo()\n    {\n        ReleaseURLData();\n        ClearHeaders();\n        ClearCookies();\n    }\n\n    EventsHandler* GetEventHandler()\n    {\n        return _evt_handler.get();\n    }\n\n    EventsHandler const* GetEventHandler() const\n    {\n        return _evt_handler.get();\n    }\n\npublic:\n    void Start(Context ctx, std::string const& key);\n    void Write(Context ctx, std::string const& data, WriteDataType type, bool finished);\n    void Stop(Context ctx);\nprivate:\n    void start_handshake(Context ctx, std::string const& key);\n\n    void start_write(Context ctx);\n    void start_read(Context ctx);\nprivate:\n    void append_write_data(Context ctx, std::string data);\n\nprivate:\n    void on_read_frame(std::string&& data, FrameType ft, bool is_finished_frame);\n\nprivate:\n    void pong(Context ctx);\n\nprivate:\n    void makesure_url_path_storaged()\n    {\n        if (_full_url_path.empty() && _url)\n        {\n            _full_url_path = _url->full;\n        }\n    }\nprivate:\n    std::string _id;\n    std::string _full_url_path;\n    std::unique_ptr<net_detail::SocketInterface> _socket_ptr;\n    std::unique_ptr<Url> _url;\n    ICHeaders _headers;\n    ICCookies _cookies;\nprivate:\n    std::mutex _m_4_write;\n    std::list<std::string> _data_4_write;\n\nprivate:\n    net_detail::ReadBuffer _buffer_4_read;\n\nprivate:\n    FrameParser _parser;\n    Context _ctx_4_parser_callback;\nprivate:\n    std::unique_ptr<EventsHandler> _evt_handler;\n\nprivate:\n    std::uint8_t _last_data_type;\n    std::uint8_t _error_on_parse;\n    std::uint8_t _stop_by_self;\n\nprivate:\n    size_t _ioc_index;\n};\n\nclass Connections\n{\npublic:\n    Connections()\n        : _m_ptr(new std::mutex)\n    {\n    }\n\n    Connections(Connections const&) = delete;\n    Connections& operator = (Connections const&) = delete;\n\n    Connections(Connections&& o) = default;\n\n    Connections(Connection::Ptr cnt)\n        : _m_ptr(new std::mutex)\n    {\n        assert(!cnt->GetID().empty());\n        _storage.insert(std::make_pair(cnt->GetID(), cnt));\n    }\n\n    void Add(Connection::Ptr cnt);\n\n    bool Remove(std::string const& id);\n    bool RenameID(std::string const& old_id, std::string const& new_id);\n\n    std::shared_ptr<Connection> Get(std::string const& id);\n    std::shared_ptr<Connection> RandOne();\n\n    std::list<Connection::Ptr> All();\n    std::list<std::string> AllID();\n\nprivate:\n    std::unique_ptr<std::mutex> _m_ptr;\n    std::map<std::string /*id*/, std::weak_ptr<Connection>> _storage;\n};\n\n} // namespace Websocket\n} // namespace da4qi4\n\n#endif // DAQI_CONNECTION_WEBSOCKET_HPP\n"
  },
  {
    "path": "include/daqi/websocket/context_websocket.hpp",
    "content": "#ifndef CONTEXT_WEBSOCKET_HPP\n#define CONTEXT_WEBSOCKET_HPP\n\n#include <functional>\n\n#include \"daqi/def/log_def.hpp\"\n#include \"daqi/websocket/connection_websocket.hpp\"\n\nnamespace da4qi4\n{\n\nclass Application;\nusing ApplicationPtr = std::shared_ptr<Application>;\n\nnamespace Websocket\n{\n\nclass ContextIMP final : public std::enable_shared_from_this<ContextIMP>\n{\nprivate:\n    ContextIMP(bool hold_connection_life, Connection::Ptr cnt, ApplicationPtr app);\n\npublic:\n    static Context Create(Connection::Ptr cnt, ApplicationPtr app);\n    static Context CreateUnholdConnectionLife(Connection::Ptr cnt, ApplicationPtr app);\n\n    ~ContextIMP();\n\n    IOC& IOContext();\n    size_t IOContextIndex() const;\n\npublic:\n    Application& App();\n    Application const& App() const;\n\n    ApplicationPtr AppPtr()\n    {\n        return _app;\n    }\n\n    log::LoggerPtr Logger();\n\npublic:\n    void SendText(std::string const& str);\n    void SendText(char const* str, std::size_t len = static_cast<std::size_t>(-1));\n\n    void SendFirstText(std::string const& str);\n    void SendNextText(std::string const& str);\n    void SendLastText(std::string const& str);\n\n    void SendFirstText(char const* str, std::size_t len = static_cast<std::size_t>(-1));\n    void SendNextText(char const* str, std::size_t len = static_cast<std::size_t>(-1));\n    void SendLastText(char const* str, std::size_t len = static_cast<std::size_t>(-1));\n\n    void SendBinary(std::vector<std::int8_t> const& data);\n    void SendBinary(char const* data, std::size_t size);\n    void SendBinary(std::string const& data)\n    {\n        SendBinary(data.c_str(), data.size());\n    }\n\n    void SendFirstBinary(std::vector<std::int8_t> const& data);\n    void SendNextBinary(std::vector<std::int8_t> const& data);\n    void SendLastBinary(std::vector<std::int8_t> const& data);\n\n    void SendFirstBinary(char const* data, std::size_t size);\n    void SendNextBinary(char const* data, std::size_t size);\n    void SendLastBinary(char const* data, std::size_t size);\n\npublic:\n    std::string URLPath() const\n    {\n        return _cnt->GetURLPath();\n    }\n\n    std::string const& ID() const\n    {\n        return _cnt->GetID();\n    }\n\n    bool RenameID(std::string const& new_id);\n\n    Url GetURL() const\n    {\n        auto p = _cnt->GetURLDataPtr();\n        return (p) ? *p : Url();\n    }\n\n    ICHeaders const& Headers() const\n    {\n        return _cnt->GetHeaders();\n    }\n\n    ICCookies const& Cookies() const\n    {\n        return _cnt->GetCookies();\n    }\n\n    void RemoveHTTPInfo()\n    {\n        _cnt->RemoveHttpInfo();\n    }\n\npublic:\n    bool IsHoldConnectionLife() const\n    {\n        return _hold_connection_life;\n    }\n\npublic:\n    Context OtherOne(std::string const& id);\n    Context OtherOne(std::string const& url, UrlFlag url_flag, std::string const& id);\n    Context OtherOne(ApplicationPtr other_app, std::string const& url, UrlFlag url_flag, std::string const& id);\n\nprivate:\n    bool _hold_connection_life;\n    Connection::Ptr _cnt;\n    ApplicationPtr _app;\n\n    friend bool operator == (ContextIMP const& o1, ContextIMP const& o2);\n};\n\nbool operator == (ContextIMP const& o1, ContextIMP const& o2);\nbool operator != (ContextIMP const& o1, ContextIMP const& o2);\n\nclass ContextList\n{\npublic:\n    struct iterator\n    {\n        iterator(std::list<Connection::Ptr>::iterator lst_it, std::weak_ptr<Application> app)\n            : _lst_iterator(lst_it), _app(app)\n        {}\n\n        iterator& operator = (iterator const& o)\n        {\n            _lst_iterator = o._lst_iterator;\n            return *this;\n        }\n\n        bool operator != (iterator const& o)\n        {\n            return _lst_iterator != o._lst_iterator;\n        }\n\n        iterator& operator ++()\n        {\n            ++_lst_iterator;\n            return *this;\n        }\n\n        iterator operator ++(int)\n        {\n            auto tmp = _lst_iterator;\n            _lst_iterator++;\n\n            return iterator(tmp, _app);\n        }\n\n        Context operator * ()\n        {\n            return (!_app.lock()) ? nullptr : ContextIMP::CreateUnholdConnectionLife(*_lst_iterator, _app.lock());\n        }\n\n    private:\n        std::list<Connection::Ptr>::iterator _lst_iterator;\n        std::weak_ptr<Application> _app;\n    };\n\n    struct const_iterator\n    {\n        const_iterator(std::list<Connection::Ptr>::const_iterator lst_it, std::weak_ptr<Application> app)\n            : _lst_iterator(lst_it), _app(app)\n        {}\n\n        const_iterator& operator = (const_iterator const& o)\n        {\n            _lst_iterator = o._lst_iterator;\n            return *this;\n        }\n\n        bool operator != (const_iterator const& o)\n        {\n            return _lst_iterator != o._lst_iterator;\n        }\n\n        const_iterator& operator ++()\n        {\n            ++_lst_iterator;\n            return *this;\n        }\n\n        const_iterator operator ++(int)\n        {\n            auto tmp = _lst_iterator;\n            _lst_iterator++;\n\n            return const_iterator(tmp, _app);\n        }\n\n        const Context operator * ()\n        {\n            return (!_app.lock()) ? nullptr : ContextIMP::CreateUnholdConnectionLife(*_lst_iterator, _app.lock());\n        }\n\n    private:\n        std::list<Connection::Ptr>::const_iterator _lst_iterator;\n        std::weak_ptr<Application> _app;\n    };\n\npublic:\n    ContextList(ApplicationPtr app, std::string const& url, UrlFlag flag);\n    ContextList(Context src_ctx, std::string const& url, UrlFlag flag);\n    ContextList(Context src_ctx);\n\n    iterator begin();\n    iterator end();\n\n    const_iterator cbegin() const;\n    const_iterator cend() const;\n\nprivate:\n    ApplicationPtr _app;\n    std::list<Connection::Ptr> _cnt_list;\n};\n\n} // namespace Websocket\n} // namespace da4qi4\n\n#endif // CONTEXT_WEBSOCKET_HPP\n"
  },
  {
    "path": "include/daqi/websocket/frame_websocket.hpp",
    "content": "//MIT\n//copyright:  https://github.com/akzi/xwebsocket\n//author:     https://github.com/akzi (fuwq, 82018309@qq.com, beijing, China)\n\n#ifndef DAQI_WEBSOCKET_FRAME_HPP\n#define DAQI_WEBSOCKET_FRAME_HPP\n\n#include <cassert>\n#include <cstdint>\n#include <cstring>\n#include <string>\n#include <functional>\n\nnamespace da4qi4\n{\nnamespace Websocket\n{\n\nenum FrameType\n{\n    e_continuation = 0x00,\n    e_text = 0x01,\n    e_binary = 0x02,\n    e_connection_close = 0x08,\n    e_ping = 0x09,\n    e_pong = 0xa\n};\n\nstruct FrameHeader\n{\n    uint8_t FIN = 0; //是否是消息的结束帧(分片) 1位\n\n    uint8_t RSV1 = 0;\n    uint8_t RSV2 = 0;\n    uint8_t RSV3 = 0;\n\n    //   %x0 表示连续消息分片\n    //   %x1 表示文本消息分片\n    //   %x2 表未二进制消息分片\n    //   %x3-7 为将来的非控制消息片断保留的操作码\n    //   %x8 表示连接关闭\n    //   %x9 表示心跳检查的ping\n    //   %xA 表示心跳检查的pong\n    //   %xB-F 为将来的控制消息片断的保留操作码\n\n    FrameType OPCODE = e_continuation;\n\n    uint8_t MASK = 0;\n    uint8_t PAYLOAD_LEN = 0;\n    uint16_t EXT_PAYLOAD_LEN_16 = 0; //extended payload length 16\n    uint64_t EXT_PAYLOAD_LEN_64 = 0; //extended payload length 64\n    uint64_t PAYLOAD_REALY_LEN = 0;\n    uint32_t MASKING_KEY = 0;\n};\n\nclass FrameBuilder\n{\npublic:\n    FrameBuilder() = default;\n\n    FrameBuilder& ResetMaskingKey()\n    {\n        _frame_header.MASK = 0x00;\n        return *this;\n    }\n\n    FrameBuilder& SetMaskingKey(uint32_t masking_key)\n    {\n        _frame_header.MASK = 0x80;\n        _frame_header.MASKING_KEY = masking_key;\n        return *this;\n    }\n    FrameBuilder& SetFIN(bool val)\n    {\n        _frame_header.FIN = val ? 0x80 : 0;\n        return *this;\n    }\n    FrameBuilder& SetFrameType(FrameType type)\n    {\n        _frame_header.OPCODE = type;\n        return *this;\n    }\n\n    std::string Build(std::string const& data)\n    {\n        return Build(data.c_str(), data.length());\n    }\n    std::string Build(const char* data, size_t len);\n    std::string Build(const char* data)\n    {\n        size_t len = (data) ? std::strlen(data) : 0;\n        return Build(data, len);\n    }\n    std::string Build()\n    {\n        return Build(nullptr, 0);\n    }\n\nprivate:\n    FrameHeader _frame_header;\n};\n\n/*\n    0                   1                   2                   3\n    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1\n    +-+-+-+-+-------+-+-------------+-------------------------------+\n    |F|R|R|R| opcode|M| Payload len |    Extended payload length    |\n    |I|S|S|S|  (4)  |A|     (7)     |             (16/64)           |\n    |N|V|V|V|       |S|             |   (if payload len==126/127)   |\n    | |1|2|3|       |K|             |                               |\n    +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +\n    |     Extended payload length continued, if payload len == 127  |\n    + - - - - - - - - - - - - - - - +-------------------------------+\n    |                               |Masking-key, if MASK set to 1  |\n    +-------------------------------+-------------------------------+\n    | Masking-key (continued)       |          Payload Data         |\n    +-------------------------------- - - - - - - - - - - - - - - - +\n    :                     Payload Data continued ...                :\n    + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +\n    |                     Payload Data continued ...                |\n    +---------------------------------------------------------------+\n*/\n\nclass FrameParser\n{\npublic:\n    using MsgCallback = std::function < void (std::string &&, FrameType, bool) >;\n\n    FrameParser()\n    {\n        reset();\n    }\n\n    ~FrameParser() = default;\n\n    FrameParser(FrameParser&& parser)\n    {\n        move_reset(std::move(parser));\n    }\n\n    FrameParser& operator= (FrameParser&& parser)\n    {\n        move_reset(std::move(parser));\n        return *this;\n    }\n\n    FrameParser& RegistMsgCallback(MsgCallback const& handle)\n    {\n        _msb_cb = handle;\n        return *this;\n    }\n\n    std::pair<bool, std::string> Parse(void const* data, uint32_t len);\n\n    void Reset()\n    {\n        reset();\n    }\nprivate:\n    void reset();\n    void move_reset(FrameParser&& parser);\n    uint32_t parse_fixed_header(const char* data);\n    uint32_t parse_payload_len(const char* data);\n    uint32_t parse_extened_payload_len(const char* data, uint32_t len);\n    void decode_extened_payload_len();\n    uint32_t parse_masking_key(const char* data, uint32_t len);\n    uint32_t parse_payload(const char* data, uint32_t len);\n\nprivate:\n    enum parser_step\n    {\n        e_fixed_header,\n        e_payload_len,\n        e_extened_payload_len,\n        e_masking_key,\n        e_payload_data,\n    };\n\n    parser_step _parser_step;\n\n    //extended payload length write pos\n    uint32_t _payload_len_offset;\n\n    //masking key buffer pos\n    uint32_t _masking_key_pos;\n\n    std::string _payload;\n\n    FrameHeader _frame_header;\n    MsgCallback _msb_cb;\n};\n\n} // namespace Websocket\n} // namespace da4qi4\n\n#endif // DAQI_WEBSOCKET_FRAME_HPP\n"
  },
  {
    "path": "include/daqi/websocket/handler_websocket.hpp",
    "content": "#ifndef HANDLER_WEBSOCKET_HPP\n#define HANDLER_WEBSOCKET_HPP\n\n#include <functional>\n#include <memory>\n\nnamespace da4qi4\n{\nnamespace Websocket\n{\n\nclass ContextIMP;\ntypedef std::shared_ptr<ContextIMP> Context;\n\nenum class EventOn\n{\n    read_event, write_event,\n};\n\nclass EventsHandler\n{\npublic:\n    virtual ~EventsHandler() = default;\n\n    virtual bool OnOpen(Context ctx) = 0;\n\n    virtual void OnText(Context ctx, std::string&& data, bool finished) = 0;\n    virtual void OnBinary(Context ctx, std::string&& data, bool finished) = 0;\n\n    virtual void OnError(Context ctx, EventOn evt, int code, std::string const& error) = 0;\n    virtual void OnClose(Context ctx, EventOn evt) = 0;\n};\n\nusing EventHandlersFactory = std::function<EventsHandler * (void)>;\n\nclass EmptyEventsHandler : public EventsHandler\n{\npublic:\n    EmptyEventsHandler() = default;\n    ~EmptyEventsHandler() override = default;\n\n    bool OnOpen(Context) override\n    {\n        return true;\n    }\n\n    void OnText(Context, std::string&&, bool) override {}\n    void OnBinary(Context, std::string&&, bool) override {}\n    void OnError(Context, EventOn, int, std::string const&) override {}\n    void OnClose(Context, EventOn) override {}\n};\n\nstruct EventHandleFunctor : public EventsHandler\n{\n    std::function < bool (Context) > DoOnOpen;\n    std::function < void (Context, std::string&&, bool) > DoOnText;\n    std::function < void (Context, std::string&&, bool) > DoOnBinary;\n    std::function < void (Context, EventOn, int, std::string const&) > DoOnError;\n    std::function < void (Context, EventOn) > DoOnClose;\n\n    bool OnOpen(Context ctx) override;\n    void OnText(Context ctx, std::string&& data, bool is_finished) override;\n    void OnBinary(Context ctx, std::string&& data, bool is_finished) override;\n    void OnError(Context ctx, EventOn evt, int code, std::string const& msg) override;\n    void OnClose(Context ctx, EventOn evt) override;\n\n    EventsHandler* operator()(void);\n};\n\n} //namespace Websocket\n} //namespace da4qi4\n\n#endif // HANDLER_WEBSOCKET_HPP\n"
  },
  {
    "path": "include/daqi/websocket/websocket.hpp",
    "content": "#ifndef WEBSOCKET_HPP\n#define WEBSOCKET_HPP\n\n#include \"daqi/websocket/handler_websocket.hpp\"\n#include \"daqi/websocket/context_websocket.hpp\"\n\n#endif // WEBSOCKET_HPP\n"
  },
  {
    "path": "inja/bytecode.hpp",
    "content": "// Copyright (c) 2019 Pantor. All rights reserved.\n\n#ifndef INCLUDE_INJA_BYTECODE_HPP_\n#define INCLUDE_INJA_BYTECODE_HPP_\n\n#include <string>\n#include <utility>\n\n#include <nlohmann/json.hpp>\n\n#include \"string_view.hpp\"\n\n\nnamespace inja {\n\nusing json = nlohmann::json;\n\n\nstruct Bytecode {\n  enum class Op : uint8_t {\n    Nop,\n    // print StringRef (always immediate)\n    PrintText,\n    // print value\n    PrintValue,\n    // push value onto stack (always immediate)\n    Push,\n\n    // builtin functions\n    // result is pushed to stack\n    // args specify number of arguments\n    // all functions can take their \"last\" argument either immediate\n    // or popped off stack (e.g. if immediate, it's like the immediate was\n    // just pushed to the stack)\n    Not,\n    And,\n    Or,\n    In,\n    Equal,\n    Greater,\n    GreaterEqual,\n    Less,\n    LessEqual,\n    At,\n    Different,\n    DivisibleBy,\n    Even,\n    First,\n    Float,\n    Int,\n    Last,\n    Length,\n    Lower,\n    Max,\n    Min,\n    Odd,\n    Range,\n    Result,\n    Round,\n    Sort,\n    Upper,\n    Exists,\n    ExistsInObject,\n    IsBoolean,\n    IsNumber,\n    IsInteger,\n    IsFloat,\n    IsObject,\n    IsArray,\n    IsString,\n    Default,\n\n    // include another template\n    // value is the template name\n    Include,\n\n    // callback function\n    // str is the function name (this means it cannot be a lookup)\n    // args specify number of arguments\n    // as with builtin functions, \"last\" argument can be immediate\n    Callback,\n\n    // unconditional jump\n    // args is the index of the bytecode to jump to.\n    Jump,\n\n    // conditional jump\n    // value popped off stack is checked for truthyness\n    // if false, args is the index of the bytecode to jump to.\n    // if true, no action is taken (falls through)\n    ConditionalJump,\n\n    // start loop\n    // value popped off stack is what is iterated over\n    // args is index of bytecode after end loop (jumped to if iterable is\n    // empty)\n    // immediate value is key name (for maps)\n    // str is value name\n    StartLoop,\n\n    // end a loop\n    // args is index of the first bytecode in the loop body\n    EndLoop,\n  };\n\n  enum Flag {\n    // location of value for value-taking ops (mask)\n    ValueMask = 0x03,\n    // pop value off stack\n    ValuePop = 0x00,\n    // value is immediate rather than on stack\n    ValueImmediate = 0x01,\n    // lookup immediate str (dot notation)\n    ValueLookupDot = 0x02,\n    // lookup immediate str (json pointer notation)\n    ValueLookupPointer = 0x03,\n  };\n\n  Op op {Op::Nop};\n  uint32_t args: 30;\n  uint32_t flags: 2;\n\n  json value;\n  std::string str;\n\n  Bytecode(): args(0), flags(0) {}\n  explicit Bytecode(Op op, unsigned int args = 0): op(op), args(args), flags(0) {}\n  explicit Bytecode(Op op, nonstd::string_view str, unsigned int flags): op(op), args(0), flags(flags), str(str) {}\n  explicit Bytecode(Op op, json&& value, unsigned int flags): op(op), args(0), flags(flags), value(std::move(value)) {}\n};\n\n}  // namespace inja\n\n#endif  // INCLUDE_INJA_BYTECODE_HPP_\n"
  },
  {
    "path": "inja/config.hpp",
    "content": "// Copyright (c) 2019 Pantor. All rights reserved.\n\n#ifndef INCLUDE_INJA_CONFIG_HPP_\n#define INCLUDE_INJA_CONFIG_HPP_\n\n#include <functional>\n#include <string>\n\n#include \"string_view.hpp\"\n\n\nnamespace inja {\n\nenum class ElementNotation {\n  Dot,\n  Pointer\n};\n\n/*!\n * \\brief Class for lexer configuration.\n */\nstruct LexerConfig {\n  std::string statement_open {\"{%\"};\n  std::string statement_close {\"%}\"};\n  std::string line_statement {\"##\"};\n  std::string expression_open {\"{{\"};\n  std::string expression_close {\"}}\"};\n  std::string comment_open {\"{#\"};\n  std::string comment_close {\"#}\"};\n  std::string open_chars {\"#{\"};\n\n  bool trim_blocks {false};\n  bool lstrip_blocks {false};\n\n  void update_open_chars() {\n    open_chars = \"\";\n    if (open_chars.find(line_statement[0]) == std::string::npos) {\n      open_chars += line_statement[0];\n    }\n    if (open_chars.find(statement_open[0]) == std::string::npos) {\n      open_chars += statement_open[0];\n    }\n    if (open_chars.find(expression_open[0]) == std::string::npos) {\n      open_chars += expression_open[0];\n    }\n    if (open_chars.find(comment_open[0]) == std::string::npos) {\n      open_chars += comment_open[0];\n    }\n  }\n};\n\n/*!\n * \\brief Class for parser configuration.\n */\nstruct ParserConfig {\n  ElementNotation notation {ElementNotation::Dot};\n};\n\n}  // namespace inja\n\n#endif  // INCLUDE_INJA_CONFIG_HPP_\n"
  },
  {
    "path": "inja/environment.hpp",
    "content": "// Copyright (c) 2019 Pantor. All rights reserved.\n\n#ifndef INCLUDE_INJA_ENVIRONMENT_HPP_\n#define INCLUDE_INJA_ENVIRONMENT_HPP_\n\n#include <memory>\n#include <fstream>\n#include <sstream>\n#include <string>\n\n#include <nlohmann/json.hpp>\n\n#include \"config.hpp\"\n#include \"function_storage.hpp\"\n#include \"parser.hpp\"\n#include \"polyfill.hpp\"\n#include \"renderer.hpp\"\n#include \"string_view.hpp\"\n#include \"template.hpp\"\n#include \"utils.hpp\"\n\n\nnamespace inja {\n\nusing json = nlohmann::json;\n\n/*!\n * \\brief Class for changing the configuration.\n */\nclass Environment {\n  class Impl {\n   public:\n    std::string input_path;\n    std::string output_path;\n\n    LexerConfig lexer_config;\n    ParserConfig parser_config;\n\n    FunctionStorage callbacks;\n    TemplateStorage included_templates;\n  };\n\n  std::unique_ptr<Impl> m_impl;\n\n public:\n  Environment(): Environment(\"\") { }\n\n  explicit Environment(const std::string& global_path): m_impl(stdinja::make_unique<Impl>()) {\n    m_impl->input_path = global_path;\n    m_impl->output_path = global_path;\n  }\n\n  explicit Environment(const std::string& input_path, const std::string& output_path): m_impl(stdinja::make_unique<Impl>()) {\n    m_impl->input_path = input_path;\n    m_impl->output_path = output_path;\n  }\n\n  /// Sets the opener and closer for template statements\n  void set_statement(const std::string& open, const std::string& close) {\n    m_impl->lexer_config.statement_open = open;\n    m_impl->lexer_config.statement_close = close;\n    m_impl->lexer_config.update_open_chars();\n  }\n\n  /// Sets the opener for template line statements\n  void set_line_statement(const std::string& open) {\n    m_impl->lexer_config.line_statement = open;\n    m_impl->lexer_config.update_open_chars();\n  }\n\n  /// Sets the opener and closer for template expressions\n  void set_expression(const std::string& open, const std::string& close) {\n    m_impl->lexer_config.expression_open = open;\n    m_impl->lexer_config.expression_close = close;\n    m_impl->lexer_config.update_open_chars();\n  }\n\n  /// Sets the opener and closer for template comments\n  void set_comment(const std::string& open, const std::string& close) {\n    m_impl->lexer_config.comment_open = open;\n    m_impl->lexer_config.comment_close = close;\n    m_impl->lexer_config.update_open_chars();\n  }\n\n  /// Sets whether to remove the first newline after a block\n  void set_trim_blocks(bool trim_blocks) {\n    m_impl->lexer_config.trim_blocks = trim_blocks;\n  }\n\n  /// Sets whether to strip the spaces and tabs from the start of a line to a block\n  void set_lstrip_blocks(bool lstrip_blocks) {\n    m_impl->lexer_config.lstrip_blocks = lstrip_blocks;\n  }\n\n  /// Sets the element notation syntax\n  void set_element_notation(ElementNotation notation) {\n    m_impl->parser_config.notation = notation;\n  }\n\n\n  Template parse(nonstd::string_view input) {\n    Parser parser(m_impl->parser_config, m_impl->lexer_config, m_impl->included_templates);\n    return parser.parse(input);\n  }\n\n  Template parse_template(const std::string& filename) {\n    Parser parser(m_impl->parser_config, m_impl->lexer_config, m_impl->included_templates);\n    return parser.parse_template(m_impl->input_path + static_cast<std::string>(filename));\n  }\n\n  std::string render(nonstd::string_view input, const json& data) {\n    return render(parse(input), data);\n  }\n\n  std::string render(const Template& tmpl, const json& data) {\n    std::stringstream os;\n    render_to(os, tmpl, data);\n    return os.str();\n  }\n\n  std::string render_file(const std::string& filename, const json& data) {\n    return render(parse_template(filename), data);\n  }\n\n  std::string render_file_with_json_file(const std::string& filename, const std::string& filename_data) {\n    const json data = load_json(filename_data);\n    return render_file(filename, data);\n  }\n\n  void write(const std::string& filename, const json& data, const std::string& filename_out) {\n    std::ofstream file(m_impl->output_path + filename_out);\n    file << render_file(filename, data);\n    file.close();\n  }\n\n  void write(const Template& temp, const json& data, const std::string& filename_out) {\n    std::ofstream file(m_impl->output_path + filename_out);\n    file << render(temp, data);\n    file.close();\n  }\n\n  void write_with_json_file(const std::string& filename, const std::string& filename_data, const std::string& filename_out) {\n    const json data = load_json(filename_data);\n    write(filename, data, filename_out);\n  }\n\n  void write_with_json_file(const Template& temp, const std::string& filename_data, const std::string& filename_out) {\n    const json data = load_json(filename_data);\n    write(temp, data, filename_out);\n  }\n\n  std::ostream& render_to(std::ostream& os, const Template& tmpl, const json& data) {\n    Renderer(m_impl->included_templates, m_impl->callbacks).render_to(os, tmpl, data);\n    return os;\n  }\n\n  std::string load_file(const std::string& filename) {\n    Parser parser(m_impl->parser_config, m_impl->lexer_config, m_impl->included_templates);\n    return parser.load_file(m_impl->input_path + filename);\n  }\n\n  json load_json(const std::string& filename) {\n    std::ifstream file = open_file_or_throw(m_impl->input_path + filename);\n    json j;\n    file >> j;\n    return j;\n  }\n\n  void add_callback(const std::string& name, unsigned int numArgs, const CallbackFunction& callback) {\n    m_impl->callbacks.add_callback(name, numArgs, callback);\n  }\n\n  /** Includes a template with a given name into the environment.\n   * Then, a template can be rendered in another template using the\n   * include \"<name>\" syntax.\n   */\n  void include_template(const std::string& name, const Template& tmpl) {\n    m_impl->included_templates[name] = tmpl;\n  }\n};\n\n/*!\n@brief render with default settings to a string\n*/\ninline std::string render(nonstd::string_view input, const json& data) {\n  return Environment().render(input, data);\n}\n\n/*!\n@brief render with default settings to the given output stream\n*/\ninline void render_to(std::ostream& os, nonstd::string_view input, const json& data) {\n  Environment env;\n  env.render_to(os, env.parse(input), data);\n}\n\n}\n\n#endif  // INCLUDE_INJA_ENVIRONMENT_HPP_\n"
  },
  {
    "path": "inja/function_storage.hpp",
    "content": "// Copyright (c) 2019 Pantor. All rights reserved.\n\n#ifndef INCLUDE_INJA_FUNCTION_STORAGE_HPP_\n#define INCLUDE_INJA_FUNCTION_STORAGE_HPP_\n\n#include <vector>\n\n#include \"bytecode.hpp\"\n#include \"string_view.hpp\"\n\n\nnamespace inja {\n\nusing json = nlohmann::json;\n\nusing Arguments = std::vector<const json*>;\nusing CallbackFunction = std::function<json(Arguments& args)>;\n\n/*!\n * \\brief Class for builtin functions and user-defined callbacks.\n */\nclass FunctionStorage {\n public:\n  void add_builtin(nonstd::string_view name, unsigned int num_args, Bytecode::Op op) {\n    auto& data = get_or_new(name, num_args);\n    data.op = op;\n  }\n\n  void add_callback(nonstd::string_view name, unsigned int num_args, const CallbackFunction& function) {\n    auto& data = get_or_new(name, num_args);\n    data.function = function;\n  }\n\n  Bytecode::Op find_builtin(nonstd::string_view name, unsigned int num_args) const {\n    if (auto ptr = get(name, num_args)) {\n      return ptr->op;\n    }\n    return Bytecode::Op::Nop;\n  }\n\n  CallbackFunction find_callback(nonstd::string_view name, unsigned int num_args) const {\n    if (auto ptr = get(name, num_args)) {\n      return ptr->function;\n    }\n    return nullptr;\n  }\n\n private:\n  struct FunctionData {\n    unsigned int num_args {0};\n    Bytecode::Op op {Bytecode::Op::Nop}; // for builtins\n    CallbackFunction function; // for callbacks\n  };\n\n  FunctionData& get_or_new(nonstd::string_view name, unsigned int num_args) {\n    auto &vec = m_map[static_cast<std::string>(name)];\n    for (auto &i: vec) {\n      if (i.num_args == num_args) return i;\n    }\n    vec.emplace_back();\n    vec.back().num_args = num_args;\n    return vec.back();\n  }\n\n  const FunctionData* get(nonstd::string_view name, unsigned int num_args) const {\n    auto it = m_map.find(static_cast<std::string>(name));\n    if (it == m_map.end()) return nullptr;\n    for (auto &&i: it->second) {\n      if (i.num_args == num_args) return &i;\n    }\n    return nullptr;\n  }\n\n  std::map<std::string, std::vector<FunctionData>> m_map;\n};\n\n}\n\n#endif  // INCLUDE_INJA_FUNCTION_STORAGE_HPP_\n"
  },
  {
    "path": "inja/inja.hpp",
    "content": "// Copyright (c) 2019 Pantor. All rights reserved.\n\n#ifndef INCLUDE_INJA_INJA_HPP_\n#define INCLUDE_INJA_INJA_HPP_\n\n#include <functional>\n#include <iostream>\n#include <map>\n#include <memory>\n#include <sstream>\n#include <string>\n#include <vector>\n\n#include <nlohmann/json.hpp>\n\n#include \"environment.hpp\"\n#include \"string_view.hpp\"\n#include \"template.hpp\"\n#include \"parser.hpp\"\n#include \"renderer.hpp\"\n\n\n#endif  // INCLUDE_INJA_INJA_HPP_\n"
  },
  {
    "path": "inja/lexer.hpp",
    "content": "// Copyright (c) 2019 Pantor. All rights reserved.\n\n#ifndef INCLUDE_INJA_LEXER_HPP_\n#define INCLUDE_INJA_LEXER_HPP_\n\n#include <cctype>\n#include <locale>\n\n#include \"config.hpp\"\n#include \"token.hpp\"\n#include \"utils.hpp\"\n\n\nnamespace inja {\n\n/*!\n * \\brief Class for lexing an inja Template.\n */\nclass Lexer {\n  enum class State {\n    Text,\n    ExpressionStart,\n    ExpressionBody,\n    LineStart,\n    LineBody,\n    StatementStart,\n    StatementBody,\n    CommentStart,\n    CommentBody\n  } m_state;\n\n  const LexerConfig& m_config;\n  nonstd::string_view m_in;\n  size_t m_tok_start;\n  size_t m_pos;\n\n public:\n  explicit Lexer(const LexerConfig& config) : m_config(config) {}\n\n  void start(nonstd::string_view in) {\n    m_in = in;\n    m_tok_start = 0;\n    m_pos = 0;\n    m_state = State::Text;\n  }\n\n  Token scan() {\n    m_tok_start = m_pos;\n\n  again:\n    if (m_tok_start >= m_in.size()) return make_token(Token::Kind::Eof);\n\n    switch (m_state) {\n      default:\n      case State::Text: {\n        // fast-scan to first open character\n        size_t open_start = m_in.substr(m_pos).find_first_of(m_config.open_chars);\n        if (open_start == nonstd::string_view::npos) {\n          // didn't find open, return remaining text as text token\n          m_pos = m_in.size();\n          return make_token(Token::Kind::Text);\n        }\n        m_pos += open_start;\n\n        // try to match one of the opening sequences, and get the close\n        nonstd::string_view open_str = m_in.substr(m_pos);\n        bool must_lstrip = false;\n        if (inja::string_view::starts_with(open_str, m_config.expression_open)) {\n          m_state = State::ExpressionStart;\n        } else if (inja::string_view::starts_with(open_str, m_config.statement_open)) {\n          m_state = State::StatementStart;\n          must_lstrip = m_config.lstrip_blocks;\n        } else if (inja::string_view::starts_with(open_str, m_config.comment_open)) {\n          m_state = State::CommentStart;\n          must_lstrip = m_config.lstrip_blocks;\n        } else if ((m_pos == 0 || m_in[m_pos - 1] == '\\n') &&\n                   inja::string_view::starts_with(open_str, m_config.line_statement)) {\n          m_state = State::LineStart;\n        } else {\n          m_pos += 1;  // wasn't actually an opening sequence\n          goto again;\n        }\n\n        nonstd::string_view text = string_view::slice(m_in, m_tok_start, m_pos);\n        if (must_lstrip)\n          text = clear_final_line_if_whitespace(text);\n\n        if (text.empty()) goto again;  // don't generate empty token\n        return Token(Token::Kind::Text, text);\n      }\n      case State::ExpressionStart: {\n        m_state = State::ExpressionBody;\n        m_pos += m_config.expression_open.size();\n        return make_token(Token::Kind::ExpressionOpen);\n      }\n      case State::LineStart: {\n        m_state = State::LineBody;\n        m_pos += m_config.line_statement.size();\n        return make_token(Token::Kind::LineStatementOpen);\n      }\n      case State::StatementStart: {\n        m_state = State::StatementBody;\n        m_pos += m_config.statement_open.size();\n        return make_token(Token::Kind::StatementOpen);\n      }\n      case State::CommentStart: {\n        m_state = State::CommentBody;\n        m_pos += m_config.comment_open.size();\n        return make_token(Token::Kind::CommentOpen);\n      }\n      case State::ExpressionBody:\n        return scan_body(m_config.expression_close, Token::Kind::ExpressionClose);\n      case State::LineBody:\n        return scan_body(\"\\n\", Token::Kind::LineStatementClose);\n      case State::StatementBody:\n        return scan_body(m_config.statement_close, Token::Kind::StatementClose, m_config.trim_blocks);\n      case State::CommentBody: {\n        // fast-scan to comment close\n        size_t end = m_in.substr(m_pos).find(m_config.comment_close);\n        if (end == nonstd::string_view::npos) {\n          m_pos = m_in.size();\n          return make_token(Token::Kind::Eof);\n        }\n        // return the entire comment in the close token\n        m_state = State::Text;\n        m_pos += end + m_config.comment_close.size();\n        Token tok = make_token(Token::Kind::CommentClose);\n        if (m_config.trim_blocks)\n          skip_newline();\n        return tok;\n      }\n    }\n  }\n\n  const LexerConfig& get_config() const { return m_config; }\n\n private:\n  Token scan_body(nonstd::string_view close, Token::Kind closeKind, bool trim = false) {\n  again:\n    // skip whitespace (except for \\n as it might be a close)\n    if (m_tok_start >= m_in.size()) return make_token(Token::Kind::Eof);\n    char ch = m_in[m_tok_start];\n    if (ch == ' ' || ch == '\\t' || ch == '\\r') {\n      m_tok_start += 1;\n      goto again;\n    }\n\n    // check for close\n    if (inja::string_view::starts_with(m_in.substr(m_tok_start), close)) {\n      m_state = State::Text;\n      m_pos = m_tok_start + close.size();\n      Token tok = make_token(closeKind);\n      if (trim)\n        skip_newline();\n      return tok;\n    }\n\n    // skip \\n\n    if (ch == '\\n') {\n      m_tok_start += 1;\n      goto again;\n    }\n\n    m_pos = m_tok_start + 1;\n    if (std::isalpha(ch)) return scan_id();\n    switch (ch) {\n      case ',':\n        return make_token(Token::Kind::Comma);\n      case ':':\n        return make_token(Token::Kind::Colon);\n      case '(':\n        return make_token(Token::Kind::LeftParen);\n      case ')':\n        return make_token(Token::Kind::RightParen);\n      case '[':\n        return make_token(Token::Kind::LeftBracket);\n      case ']':\n        return make_token(Token::Kind::RightBracket);\n      case '{':\n        return make_token(Token::Kind::LeftBrace);\n      case '}':\n        return make_token(Token::Kind::RightBrace);\n      case '>':\n        if (m_pos < m_in.size() && m_in[m_pos] == '=') {\n          m_pos += 1;\n          return make_token(Token::Kind::GreaterEqual);\n        }\n        return make_token(Token::Kind::GreaterThan);\n      case '<':\n        if (m_pos < m_in.size() && m_in[m_pos] == '=') {\n          m_pos += 1;\n          return make_token(Token::Kind::LessEqual);\n        }\n        return make_token(Token::Kind::LessThan);\n      case '=':\n        if (m_pos < m_in.size() && m_in[m_pos] == '=') {\n          m_pos += 1;\n          return make_token(Token::Kind::Equal);\n        }\n        return make_token(Token::Kind::Unknown);\n      case '!':\n        if (m_pos < m_in.size() && m_in[m_pos] == '=') {\n          m_pos += 1;\n          return make_token(Token::Kind::NotEqual);\n        }\n        return make_token(Token::Kind::Unknown);\n      case '\\\"':\n        return scan_string();\n      case '0':\n      case '1':\n      case '2':\n      case '3':\n      case '4':\n      case '5':\n      case '6':\n      case '7':\n      case '8':\n      case '9':\n      case '-':\n        return scan_number();\n      case '_':\n        return scan_id();\n      default:\n        return make_token(Token::Kind::Unknown);\n    }\n  }\n\n  Token scan_id() {\n    for (;;) {\n      if (m_pos >= m_in.size()) {\n        break;\n      }\n      char ch = m_in[m_pos];\n      if (!std::isalnum(ch) && ch != '.' && ch != '/' && ch != '_' && ch != '-') {\n        break;\n      }\n      m_pos += 1;\n    }\n    return make_token(Token::Kind::Id);\n  }\n\n  Token scan_number() {\n    for (;;) {\n      if (m_pos >= m_in.size()) {\n        break;\n      }\n      char ch = m_in[m_pos];\n      // be very permissive in lexer (we'll catch errors when conversion happens)\n      if (!std::isdigit(ch) && ch != '.' && ch != 'e' && ch != 'E' && ch != '+' && ch != '-') {\n        break;\n      }\n      m_pos += 1;\n    }\n    return make_token(Token::Kind::Number);\n  }\n\n  Token scan_string() {\n    bool escape {false};\n    for (;;) {\n      if (m_pos >= m_in.size()) break;\n      char ch = m_in[m_pos++];\n      if (ch == '\\\\') {\n        escape = true;\n      } else if (!escape && ch == m_in[m_tok_start]) {\n        break;\n      } else {\n        escape = false;\n      }\n    }\n    return make_token(Token::Kind::String);\n  }\n\n  Token make_token(Token::Kind kind) const {\n    return Token(kind, string_view::slice(m_in, m_tok_start, m_pos));\n  }\n\n  void skip_newline() {\n    if (m_pos < m_in.size()) {\n      char ch = m_in[m_pos];\n      if (ch == '\\n')\n        m_pos += 1;\n      else if (ch == '\\r') {\n        m_pos += 1;\n        if (m_pos < m_in.size() && m_in[m_pos] == '\\n')\n          m_pos += 1;\n      }\n    }\n  }\n\n  static nonstd::string_view clear_final_line_if_whitespace(nonstd::string_view text)\n  {\n    nonstd::string_view result = text;\n    while (!result.empty()) {\n      char ch = result.back();\n      if (ch == ' ' || ch == '\\t')\n       result.remove_suffix(1);\n      else if (ch == '\\n' || ch == '\\r')\n        break;\n      else\n        return text;\n    }\n    return result;\n  }\n};\n\n}\n\n#endif  // INCLUDE_INJA_LEXER_HPP_\n"
  },
  {
    "path": "inja/parser.hpp",
    "content": "// Copyright (c) 2019 Pantor. All rights reserved.\n\n#ifndef INCLUDE_INJA_PARSER_HPP_\n#define INCLUDE_INJA_PARSER_HPP_\n\n#include <limits>\n#include <string>\n#include <utility> \n#include <vector>\n\n#include \"bytecode.hpp\"\n#include \"config.hpp\"\n#include \"function_storage.hpp\"\n#include \"lexer.hpp\"\n#include \"template.hpp\"\n#include \"token.hpp\"\n#include \"utils.hpp\"\n\n#include <nlohmann/json.hpp>\n\n\nnamespace inja {\n\nclass ParserStatic {\n  ParserStatic() {\n    functions.add_builtin(\"at\", 2, Bytecode::Op::At);\n    functions.add_builtin(\"default\", 2, Bytecode::Op::Default);\n    functions.add_builtin(\"divisibleBy\", 2, Bytecode::Op::DivisibleBy);\n    functions.add_builtin(\"even\", 1, Bytecode::Op::Even);\n    functions.add_builtin(\"first\", 1, Bytecode::Op::First);\n    functions.add_builtin(\"float\", 1, Bytecode::Op::Float);\n    functions.add_builtin(\"int\", 1, Bytecode::Op::Int);\n    functions.add_builtin(\"last\", 1, Bytecode::Op::Last);\n    functions.add_builtin(\"length\", 1, Bytecode::Op::Length);\n    functions.add_builtin(\"lower\", 1, Bytecode::Op::Lower);\n    functions.add_builtin(\"max\", 1, Bytecode::Op::Max);\n    functions.add_builtin(\"min\", 1, Bytecode::Op::Min);\n    functions.add_builtin(\"odd\", 1, Bytecode::Op::Odd);\n    functions.add_builtin(\"range\", 1, Bytecode::Op::Range);\n    functions.add_builtin(\"round\", 2, Bytecode::Op::Round);\n    functions.add_builtin(\"sort\", 1, Bytecode::Op::Sort);\n    functions.add_builtin(\"upper\", 1, Bytecode::Op::Upper);\n    functions.add_builtin(\"exists\", 1, Bytecode::Op::Exists);\n    functions.add_builtin(\"existsIn\", 2, Bytecode::Op::ExistsInObject);\n    functions.add_builtin(\"isBoolean\", 1, Bytecode::Op::IsBoolean);\n    functions.add_builtin(\"isNumber\", 1, Bytecode::Op::IsNumber);\n    functions.add_builtin(\"isInteger\", 1, Bytecode::Op::IsInteger);\n    functions.add_builtin(\"isFloat\", 1, Bytecode::Op::IsFloat);\n    functions.add_builtin(\"isObject\", 1, Bytecode::Op::IsObject);\n    functions.add_builtin(\"isArray\", 1, Bytecode::Op::IsArray);\n    functions.add_builtin(\"isString\", 1, Bytecode::Op::IsString);\n  }\n\n public:\n  ParserStatic(const ParserStatic&) = delete;\n  ParserStatic& operator=(const ParserStatic&) = delete;\n\n  static const ParserStatic& get_instance() {\n    static ParserStatic inst;\n    return inst;\n  }\n\n  FunctionStorage functions;\n};\n\n/*!\n * \\brief Class for parsing an inja Template.\n */\nclass Parser {\n public:\n  explicit Parser(const ParserConfig& parser_config, const LexerConfig& lexer_config, TemplateStorage& included_templates): m_config(parser_config), m_lexer(lexer_config), m_included_templates(included_templates), m_static(ParserStatic::get_instance()) { }\n\n  bool parse_expression(Template& tmpl) {\n    if (!parse_expression_and(tmpl)) return false;\n    if (m_tok.kind != Token::Kind::Id || m_tok.text != static_cast<decltype(m_tok.text)>(\"or\")) return true;\n    get_next_token();\n    if (!parse_expression_and(tmpl)) return false;\n    append_function(tmpl, Bytecode::Op::Or, 2);\n    return true;\n  }\n\n  bool parse_expression_and(Template& tmpl) {\n    if (!parse_expression_not(tmpl)) return false;\n    if (m_tok.kind != Token::Kind::Id || m_tok.text != static_cast<decltype(m_tok.text)>(\"and\")) return true;\n    get_next_token();\n    if (!parse_expression_not(tmpl)) return false;\n    append_function(tmpl, Bytecode::Op::And, 2);\n    return true;\n  }\n\n  bool parse_expression_not(Template& tmpl) {\n    if (m_tok.kind == Token::Kind::Id && m_tok.text == static_cast<decltype(m_tok.text)>(\"not\")) {\n      get_next_token();\n      if (!parse_expression_not(tmpl)) return false;\n      append_function(tmpl, Bytecode::Op::Not, 1);\n      return true;\n    } else {\n      return parse_expression_comparison(tmpl);\n    }\n  }\n\n  bool parse_expression_comparison(Template& tmpl) {\n    if (!parse_expression_datum(tmpl)) return false;\n    Bytecode::Op op;\n    switch (m_tok.kind) {\n      case Token::Kind::Id:\n        if (m_tok.text == static_cast<decltype(m_tok.text)>(\"in\"))\n          op = Bytecode::Op::In;\n        else\n          return true;\n        break;\n      case Token::Kind::Equal:\n        op = Bytecode::Op::Equal;\n        break;\n      case Token::Kind::GreaterThan:\n        op = Bytecode::Op::Greater;\n        break;\n      case Token::Kind::LessThan:\n        op = Bytecode::Op::Less;\n        break;\n      case Token::Kind::LessEqual:\n        op = Bytecode::Op::LessEqual;\n        break;\n      case Token::Kind::GreaterEqual:\n        op = Bytecode::Op::GreaterEqual;\n        break;\n      case Token::Kind::NotEqual:\n        op = Bytecode::Op::Different;\n        break;\n      default:\n        return true;\n    }\n    get_next_token();\n    if (!parse_expression_datum(tmpl)) return false;\n    append_function(tmpl, op, 2);\n    return true;\n  }\n\n  bool parse_expression_datum(Template& tmpl) {\n    nonstd::string_view json_first;\n    size_t bracket_level = 0;\n    size_t brace_level = 0;\n\n    for (;;) {\n      switch (m_tok.kind) {\n        case Token::Kind::LeftParen: {\n          get_next_token();\n          if (!parse_expression(tmpl)) return false;\n          if (m_tok.kind != Token::Kind::RightParen) {\n            inja_throw(\"parser_error\", \"unmatched '('\");\n          }\n          get_next_token();\n          return true;\n        }\n        case Token::Kind::Id:\n          get_peek_token();\n          if (m_peek_tok.kind == Token::Kind::LeftParen) {\n            // function call, parse arguments\n            Token func_token = m_tok;\n            get_next_token();  // id\n            get_next_token();  // leftParen\n            unsigned int num_args = 0;\n            if (m_tok.kind == Token::Kind::RightParen) {\n              // no args\n              get_next_token();\n            } else {\n              for (;;) {\n                if (!parse_expression(tmpl)) {\n                  inja_throw(\"parser_error\", \"expected expression, got '\" + m_tok.describe() + \"'\");\n                }\n                num_args += 1;\n                if (m_tok.kind == Token::Kind::RightParen) {\n                  get_next_token();\n                  break;\n                }\n                if (m_tok.kind != Token::Kind::Comma) {\n                  inja_throw(\"parser_error\", \"expected ')' or ',', got '\" + m_tok.describe() + \"'\");\n                }\n                get_next_token();\n              }\n            }\n\n            auto op = m_static.functions.find_builtin(func_token.text, num_args);\n\n            if (op != Bytecode::Op::Nop) {\n              // swap arguments for default(); see comment in RenderTo()\n              if (op == Bytecode::Op::Default)\n                std::swap(tmpl.bytecodes.back(), *(tmpl.bytecodes.rbegin() + 1));\n              append_function(tmpl, op, num_args);\n              return true;\n            } else {\n              append_callback(tmpl, func_token.text, num_args);\n              return true;\n            }\n          } else if (m_tok.text == static_cast<decltype(m_tok.text)>(\"true\") ||\n              m_tok.text == static_cast<decltype(m_tok.text)>(\"false\") ||\n              m_tok.text == static_cast<decltype(m_tok.text)>(\"null\")) {\n            // true, false, null are json literals\n            if (brace_level == 0 && bracket_level == 0) {\n              json_first = m_tok.text;\n              goto returnJson;\n            }\n            break;\n          } else {\n            // normal literal (json read)\n            tmpl.bytecodes.emplace_back(\n                Bytecode::Op::Push, m_tok.text,\n                m_config.notation == ElementNotation::Pointer ? Bytecode::Flag::ValueLookupPointer : Bytecode::Flag::ValueLookupDot);\n            get_next_token();\n            return true;\n          }\n        // json passthrough\n        case Token::Kind::Number:\n        case Token::Kind::String:\n          if (brace_level == 0 && bracket_level == 0) {\n            json_first = m_tok.text;\n            goto returnJson;\n          }\n          break;\n        case Token::Kind::Comma:\n        case Token::Kind::Colon:\n          if (brace_level == 0 && bracket_level == 0) {\n            inja_throw(\"parser_error\", \"unexpected token '\" + m_tok.describe() + \"'\");\n          }\n          break;\n        case Token::Kind::LeftBracket:\n          if (brace_level == 0 && bracket_level == 0) {\n            json_first = m_tok.text;\n          }\n          bracket_level += 1;\n          break;\n        case Token::Kind::LeftBrace:\n          if (brace_level == 0 && bracket_level == 0) {\n            json_first = m_tok.text;\n          }\n          brace_level += 1;\n          break;\n        case Token::Kind::RightBracket:\n          if (bracket_level == 0) {\n            inja_throw(\"parser_error\", \"unexpected ']'\");\n          }\n          --bracket_level;\n          if (brace_level == 0 && bracket_level == 0) goto returnJson;\n          break;\n        case Token::Kind::RightBrace:\n          if (brace_level == 0) {\n            inja_throw(\"parser_error\", \"unexpected '}'\");\n          }\n          --brace_level;\n          if (brace_level == 0 && bracket_level == 0) goto returnJson;\n          break;\n        default:\n          if (brace_level != 0) {\n            inja_throw(\"parser_error\", \"unmatched '{'\");\n          }\n          if (bracket_level != 0) {\n            inja_throw(\"parser_error\", \"unmatched '['\");\n          }\n          return false;\n      }\n\n      get_next_token();\n    }\n\n  returnJson:\n    // bridge across all intermediate tokens\n    nonstd::string_view json_text(json_first.data(), m_tok.text.data() - json_first.data() + m_tok.text.size());\n    tmpl.bytecodes.emplace_back(Bytecode::Op::Push, json::parse(json_text), Bytecode::Flag::ValueImmediate);\n    get_next_token();\n    return true;\n  }\n\n  bool parse_statement(Template& tmpl, nonstd::string_view path) {\n    if (m_tok.kind != Token::Kind::Id) return false;\n\n    if (m_tok.text == static_cast<decltype(m_tok.text)>(\"if\")) {\n      get_next_token();\n\n      // evaluate expression\n      if (!parse_expression(tmpl)) return false;\n\n      // start a new if block on if stack\n      m_if_stack.emplace_back(tmpl.bytecodes.size());\n\n      // conditional jump; destination will be filled in by else or endif\n      tmpl.bytecodes.emplace_back(Bytecode::Op::ConditionalJump);\n    } else if (m_tok.text == static_cast<decltype(m_tok.text)>(\"endif\")) {\n      if (m_if_stack.empty()) {\n        inja_throw(\"parser_error\", \"endif without matching if\");\n      }\n      auto& if_data = m_if_stack.back();\n      get_next_token();\n\n      // previous conditional jump jumps here\n      if (if_data.prev_cond_jump != std::numeric_limits<unsigned int>::max()) {\n        tmpl.bytecodes[if_data.prev_cond_jump].args = tmpl.bytecodes.size();\n      }\n\n      // update all previous unconditional jumps to here\n      for (unsigned int i: if_data.uncond_jumps) {\n        tmpl.bytecodes[i].args = tmpl.bytecodes.size();\n      }\n\n      // pop if stack\n      m_if_stack.pop_back();\n    } else if (m_tok.text == static_cast<decltype(m_tok.text)>(\"else\")) {\n      if (m_if_stack.empty())\n        inja_throw(\"parser_error\", \"else without matching if\");\n      auto& if_data = m_if_stack.back();\n      get_next_token();\n\n      // end previous block with unconditional jump to endif; destination will be\n      // filled in by endif\n      if_data.uncond_jumps.push_back(tmpl.bytecodes.size());\n      tmpl.bytecodes.emplace_back(Bytecode::Op::Jump);\n\n      // previous conditional jump jumps here\n      tmpl.bytecodes[if_data.prev_cond_jump].args = tmpl.bytecodes.size();\n      if_data.prev_cond_jump = std::numeric_limits<unsigned int>::max();\n\n      // chained else if\n      if (m_tok.kind == Token::Kind::Id && m_tok.text == static_cast<decltype(m_tok.text)>(\"if\")) {\n        get_next_token();\n\n        // evaluate expression\n        if (!parse_expression(tmpl)) return false;\n\n        // update \"previous jump\"\n        if_data.prev_cond_jump = tmpl.bytecodes.size();\n\n        // conditional jump; destination will be filled in by else or endif\n        tmpl.bytecodes.emplace_back(Bytecode::Op::ConditionalJump);\n      }\n    } else if (m_tok.text == static_cast<decltype(m_tok.text)>(\"for\")) {\n      get_next_token();\n\n      // options: for a in arr; for a, b in obj\n      if (m_tok.kind != Token::Kind::Id)\n        inja_throw(\"parser_error\", \"expected id, got '\" + m_tok.describe() + \"'\");\n      Token value_token = m_tok;\n      get_next_token();\n\n      Token key_token;\n      if (m_tok.kind == Token::Kind::Comma) {\n        get_next_token();\n        if (m_tok.kind != Token::Kind::Id)\n          inja_throw(\"parser_error\", \"expected id, got '\" + m_tok.describe() + \"'\");\n        key_token = std::move(value_token);\n        value_token = m_tok;\n        get_next_token();\n      }\n\n      if (m_tok.kind != Token::Kind::Id || m_tok.text != static_cast<decltype(m_tok.text)>(\"in\"))\n        inja_throw(\"parser_error\",\n                   \"expected 'in', got '\" + m_tok.describe() + \"'\");\n      get_next_token();\n\n      if (!parse_expression(tmpl)) return false;\n\n      m_loop_stack.push_back(tmpl.bytecodes.size());\n\n      tmpl.bytecodes.emplace_back(Bytecode::Op::StartLoop);\n      if (!key_token.text.empty()) {\n        tmpl.bytecodes.back().value = key_token.text;\n      }\n      tmpl.bytecodes.back().str = static_cast<std::string>(value_token.text);\n    } else if (m_tok.text == static_cast<decltype(m_tok.text)>(\"endfor\")) {\n      get_next_token();\n      if (m_loop_stack.empty()) {\n        inja_throw(\"parser_error\", \"endfor without matching for\");\n      }\n\n      // update loop with EndLoop index (for empty case)\n      tmpl.bytecodes[m_loop_stack.back()].args = tmpl.bytecodes.size();\n\n      tmpl.bytecodes.emplace_back(Bytecode::Op::EndLoop);\n      tmpl.bytecodes.back().args = m_loop_stack.back() + 1;  // loop body\n      m_loop_stack.pop_back();\n    } else if (m_tok.text == static_cast<decltype(m_tok.text)>(\"include\")) {\n      get_next_token();\n\n      if (m_tok.kind != Token::Kind::String) {\n        inja_throw(\"parser_error\", \"expected string, got '\" + m_tok.describe() + \"'\");\n      }\n\n      // build the relative path\n      json json_name = json::parse(m_tok.text);\n      std::string pathname = static_cast<std::string>(path);\n      pathname += json_name.get_ref<const std::string&>();\n      if (pathname.compare(0, 2, \"./\") == 0) {\n        pathname.erase(0, 2);\n      }\n      // sys::path::remove_dots(pathname, true, sys::path::Style::posix);\n\n      if (m_included_templates.find(pathname) == m_included_templates.end()) {\n        Template include_template = parse_template(pathname);\n        m_included_templates.emplace(pathname, include_template);\n      }\n\n      // generate a reference bytecode\n      tmpl.bytecodes.emplace_back(Bytecode::Op::Include, json(pathname), Bytecode::Flag::ValueImmediate);\n\n      get_next_token();\n    } else {\n      return false;\n    }\n    return true;\n  }\n\n  void append_function(Template& tmpl, Bytecode::Op op, unsigned int num_args) {\n    // we can merge with back-to-back push\n    if (!tmpl.bytecodes.empty()) {\n      Bytecode& last = tmpl.bytecodes.back();\n      if (last.op == Bytecode::Op::Push) {\n        last.op = op;\n        last.args = num_args;\n        return;\n      }\n    }\n\n    // otherwise just add it to the end\n    tmpl.bytecodes.emplace_back(op, num_args);\n  }\n\n  void append_callback(Template& tmpl, nonstd::string_view name, unsigned int num_args) {\n    // we can merge with back-to-back push value (not lookup)\n    if (!tmpl.bytecodes.empty()) {\n      Bytecode& last = tmpl.bytecodes.back();\n      if (last.op == Bytecode::Op::Push &&\n          (last.flags & Bytecode::Flag::ValueMask) == Bytecode::Flag::ValueImmediate) {\n        last.op = Bytecode::Op::Callback;\n        last.args = num_args;\n        last.str = static_cast<std::string>(name);\n        return;\n      }\n    }\n\n    // otherwise just add it to the end\n    tmpl.bytecodes.emplace_back(Bytecode::Op::Callback, num_args);\n    tmpl.bytecodes.back().str = static_cast<std::string>(name);\n  }\n\n  void parse_into(Template& tmpl, nonstd::string_view path) {\n    m_lexer.start(tmpl.content);\n\n    for (;;) {\n      get_next_token();\n      switch (m_tok.kind) {\n        case Token::Kind::Eof:\n          if (!m_if_stack.empty()) inja_throw(\"parser_error\", \"unmatched if\");\n          if (!m_loop_stack.empty()) inja_throw(\"parser_error\", \"unmatched for\");\n          return;\n        case Token::Kind::Text:\n          tmpl.bytecodes.emplace_back(Bytecode::Op::PrintText, m_tok.text, 0u);\n          break;\n        case Token::Kind::StatementOpen:\n          get_next_token();\n          if (!parse_statement(tmpl, path)) {\n            inja_throw(\"parser_error\", \"expected statement, got '\" + m_tok.describe() + \"'\");\n          }\n          if (m_tok.kind != Token::Kind::StatementClose) {\n            inja_throw(\"parser_error\", \"expected statement close, got '\" + m_tok.describe() + \"'\");\n          }\n          break;\n        case Token::Kind::LineStatementOpen:\n          get_next_token();\n          parse_statement(tmpl, path);\n          if (m_tok.kind != Token::Kind::LineStatementClose &&\n              m_tok.kind != Token::Kind::Eof) {\n            inja_throw(\"parser_error\", \"expected line statement close, got '\" + m_tok.describe() + \"'\");\n          }\n          break;\n        case Token::Kind::ExpressionOpen:\n          get_next_token();\n          if (!parse_expression(tmpl)) {\n            inja_throw(\"parser_error\", \"expected expression, got '\" + m_tok.describe() + \"'\");\n          }\n          append_function(tmpl, Bytecode::Op::PrintValue, 1);\n          if (m_tok.kind != Token::Kind::ExpressionClose) {\n            inja_throw(\"parser_error\", \"expected expression close, got '\" + m_tok.describe() + \"'\");\n          }\n          break;\n        case Token::Kind::CommentOpen:\n          get_next_token();\n          if (m_tok.kind != Token::Kind::CommentClose) {\n            inja_throw(\"parser_error\", \"expected comment close, got '\" + m_tok.describe() + \"'\");\n          }\n          break;\n        default:\n          inja_throw(\"parser_error\", \"unexpected token '\" + m_tok.describe() + \"'\");\n          break;\n      }\n    }\n  }\n\n  Template parse(nonstd::string_view input, nonstd::string_view path) {\n    Template result;\n    result.content = static_cast<std::string>(input);\n    parse_into(result, path);\n    return result;\n  }\n\n  Template parse(nonstd::string_view input) {\n    return parse(input, \"./\");\n  }\n\n  Template parse_template(nonstd::string_view filename) {\n    Template result;\n    result.content = load_file(filename);\n\n    nonstd::string_view path = filename.substr(0, filename.find_last_of(\"/\\\\\") + 1);\n      // StringRef path = sys::path::parent_path(filename);\n    Parser(m_config, m_lexer.get_config(), m_included_templates).parse_into(result, path);\n    return result;\n  }\n\n  std::string load_file(nonstd::string_view filename) {\n    std::ifstream file = open_file_or_throw(static_cast<std::string>(filename));\n    std::string text((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());\n    return text;\n  }\n\n private:\n  const ParserConfig& m_config;\n  Lexer m_lexer;\n  Token m_tok;\n  Token m_peek_tok;\n  bool m_have_peek_tok {false};\n  TemplateStorage& m_included_templates;\n  const ParserStatic& m_static;\n\n  struct IfData {\n    unsigned int prev_cond_jump;\n    std::vector<unsigned int> uncond_jumps;\n\n    explicit IfData(unsigned int condJump): prev_cond_jump(condJump) {}\n  };\n\n  std::vector<IfData> m_if_stack;\n  std::vector<unsigned int> m_loop_stack;\n\n  void get_next_token() {\n    if (m_have_peek_tok) {\n      m_tok = m_peek_tok;\n      m_have_peek_tok = false;\n    } else {\n      m_tok = m_lexer.scan();\n    }\n  }\n\n  void get_peek_token() {\n    if (!m_have_peek_tok) {\n      m_peek_tok = m_lexer.scan();\n      m_have_peek_tok = true;\n    }\n  }\n};\n\n}  // namespace inja\n\n#endif  // INCLUDE_INJA_PARSER_HPP_\n"
  },
  {
    "path": "inja/polyfill.hpp",
    "content": "// Copyright (c) 2019 Pantor. All rights reserved.\n\n#ifndef INCLUDE_INJA_POLYFILL_HPP_\n#define INCLUDE_INJA_POLYFILL_HPP_\n\n\n#if __cplusplus < 201402L\n\n#include <cstddef>\n#include <memory>\n#include <type_traits>\n#include <utility>\n\n\nnamespace stdinja {\n\ntemplate<class T> struct _Unique_if {\n  typedef std::unique_ptr<T> _Single_object;\n};\n\ntemplate<class T> struct _Unique_if<T[]> {\n  typedef std::unique_ptr<T[]> _Unknown_bound;\n};\n\ntemplate<class T, size_t N> struct _Unique_if<T[N]> {\n  typedef void _Known_bound;\n};\n\ntemplate<class T, class... Args>\ntypename _Unique_if<T>::_Single_object\nmake_unique(Args&&... args) {\n  return std::unique_ptr<T>(new T(std::forward<Args>(args)...));\n}\n\ntemplate<class T>\ntypename _Unique_if<T>::_Unknown_bound\nmake_unique(size_t n) {\n  typedef typename std::remove_extent<T>::type U;\n  return std::unique_ptr<T>(new U[n]());\n}\n\ntemplate<class T, class... Args>\ntypename _Unique_if<T>::_Known_bound\nmake_unique(Args&&...) = delete;\n\n}  // namespace stdinja\n\n#else\n\nnamespace stdinja = std;\n\n#endif  // memory */\n\n#endif  // INCLUDE_INJA_POLYFILL_HPP_\n"
  },
  {
    "path": "inja/renderer.hpp",
    "content": "// Copyright (c) 2019 Pantor. All rights reserved.\n\n#ifndef INCLUDE_INJA_RENDERER_HPP_\n#define INCLUDE_INJA_RENDERER_HPP_\n\n#include <algorithm>\n#include <numeric>\n#include <string>\n#include <utility>\n#include <vector>\n\n#include <nlohmann/json.hpp>\n\n#include \"bytecode.hpp\"\n#include \"template.hpp\"\n#include \"utils.hpp\"\n\n\nnamespace inja {\n\ninline nonstd::string_view convert_dot_to_json_pointer(nonstd::string_view dot, std::string& out) {\n  out.clear();\n  do {\n    nonstd::string_view part;\n    std::tie(part, dot) = string_view::split(dot, '.');\n    out.push_back('/');\n    out.append(part.begin(), part.end());\n  } while (!dot.empty());\n  return nonstd::string_view(out.data(), out.size());\n}\n\n/*!\n * \\brief Class for rendering a Template with data.\n */\nclass Renderer {\n  std::vector<const json*>& get_args(const Bytecode& bc) {\n    m_tmp_args.clear();\n\n    bool has_imm = ((bc.flags & Bytecode::Flag::ValueMask) != Bytecode::Flag::ValuePop);\n\n    // get args from stack\n    unsigned int pop_args = bc.args;\n    if (has_imm) {\n      pop_args -= 1;\n    }\n\n    for (auto i = std::prev(m_stack.end(), pop_args); i != m_stack.end(); i++) {\n      m_tmp_args.push_back(&(*i));\n    }\n\n    // get immediate arg\n    if (has_imm) {\n      m_tmp_args.push_back(get_imm(bc));\n    }\n\n    return m_tmp_args;\n  }\n\n  void pop_args(const Bytecode& bc) {\n    unsigned int popArgs = bc.args;\n    if ((bc.flags & Bytecode::Flag::ValueMask) != Bytecode::Flag::ValuePop) {\n      popArgs -= 1;\n    }\n    for (unsigned int i = 0; i < popArgs; ++i) {\n      m_stack.pop_back();\n    }\n  }\n\n  const json* get_imm(const Bytecode& bc) {\n    std::string ptr_buffer;\n    nonstd::string_view ptr;\n    switch (bc.flags & Bytecode::Flag::ValueMask) {\n      case Bytecode::Flag::ValuePop:\n        return nullptr;\n      case Bytecode::Flag::ValueImmediate:\n        return &bc.value;\n      case Bytecode::Flag::ValueLookupDot:\n        ptr = convert_dot_to_json_pointer(bc.str, ptr_buffer);\n        break;\n      case Bytecode::Flag::ValueLookupPointer:\n        ptr_buffer += '/';\n        ptr_buffer += bc.str;\n        ptr = ptr_buffer;\n        break;\n    }\n    try {\n      return &m_data->at(json::json_pointer(ptr.data()));\n    } catch (std::exception&) {\n      // try to evaluate as a no-argument callback\n      if (auto callback = m_callbacks.find_callback(bc.str, 0)) {\n        std::vector<const json*> arguments {};\n        m_tmp_val = callback(arguments);\n        return &m_tmp_val;\n      }\n      inja_throw(\"render_error\", \"variable '\" + static_cast<std::string>(bc.str) + \"' not found\");\n      return nullptr;\n    }\n  }\n\n  bool truthy(const json& var) const {\n    if (var.empty()) {\n      return false;\n    } else if (var.is_number()) {\n      return (var != 0);\n    } else if (var.is_string()) {\n      return !var.empty();\n    }\n\n    try {\n      return var.get<bool>();\n    } catch (json::type_error& e) {\n      inja_throw(\"json_error\", e.what());\n      throw;\n    }\n  }\n\n  void update_loop_data()  {\n    LoopLevel& level = m_loop_stack.back();\n\n    if (level.loop_type == LoopLevel::Type::Array) {\n      level.data[static_cast<std::string>(level.value_name)] = level.values.at(level.index);  // *level.it;\n      auto& loopData = level.data[\"loop\"];\n      loopData[\"index\"] = level.index;\n      loopData[\"index1\"] = level.index + 1;\n      loopData[\"is_first\"] = (level.index == 0);\n      loopData[\"is_last\"] = (level.index == level.size - 1);\n    } else {\n      level.data[static_cast<std::string>(level.key_name)] = level.map_it->first;\n      level.data[static_cast<std::string>(level.value_name)] = *level.map_it->second;\n    }\n  }\n\n  const TemplateStorage& m_included_templates;\n  const FunctionStorage& m_callbacks;\n\n  std::vector<json> m_stack;\n\n\n  struct LoopLevel {\n    enum class Type { Map, Array };\n\n    Type loop_type;\n    nonstd::string_view key_name;    // variable name for keys\n    nonstd::string_view value_name;  // variable name for values\n    json data;                       // data with loop info added\n\n    json values;                     // values to iterate over\n\n    // loop over list\n    size_t index;                    // current list index\n    size_t size;                     // length of list\n\n    // loop over map\n    using KeyValue = std::pair<nonstd::string_view, json*>;\n    using MapValues = std::vector<KeyValue>;\n    MapValues map_values;            // values to iterate over\n    MapValues::iterator map_it;      // iterator over values\n  };\n\n  std::vector<LoopLevel> m_loop_stack;\n  const json* m_data;\n\n  std::vector<const json*> m_tmp_args;\n  json m_tmp_val;\n\n\n public:\n  Renderer(const TemplateStorage& included_templates, const FunctionStorage& callbacks): m_included_templates(included_templates), m_callbacks(callbacks) {\n    m_stack.reserve(16);\n    m_tmp_args.reserve(4);\n    m_loop_stack.reserve(16);\n  }\n\n  void render_to(std::ostream& os, const Template& tmpl, const json& data) {\n    m_data = &data;\n\n    for (size_t i = 0; i < tmpl.bytecodes.size(); ++i) {\n      const auto& bc = tmpl.bytecodes[i];\n\n      switch (bc.op) {\n        case Bytecode::Op::Nop: {\n          break;\n        }\n        case Bytecode::Op::PrintText: {\n          os << bc.str;\n          break;\n        }\n        case Bytecode::Op::PrintValue: {\n          const json& val = *get_args(bc)[0];\n          if (val.is_string()) {\n            os << val.get_ref<const std::string&>();\n          } else {\n            os << val.dump();\n          }\n          pop_args(bc);\n          break;\n        }\n        case Bytecode::Op::Push: {\n          m_stack.emplace_back(*get_imm(bc));\n          break;\n        }\n        case Bytecode::Op::Upper: {\n          auto result = get_args(bc)[0]->get<std::string>();\n          std::transform(result.begin(), result.end(), result.begin(), ::toupper);\n          pop_args(bc);\n          m_stack.emplace_back(std::move(result));\n          break;\n        }\n        case Bytecode::Op::Lower: {\n          auto result = get_args(bc)[0]->get<std::string>();\n          std::transform(result.begin(), result.end(), result.begin(), ::tolower);\n          pop_args(bc);\n          m_stack.emplace_back(std::move(result));\n          break;\n        }\n        case Bytecode::Op::Range: {\n          int number = get_args(bc)[0]->get<int>();\n          std::vector<int> result(number);\n          std::iota(std::begin(result), std::end(result), 0);\n          pop_args(bc);\n          m_stack.emplace_back(std::move(result));\n          break;\n        }\n        case Bytecode::Op::Length: {\n          const json& val = *get_args(bc)[0];\n\n          int result;\n          if (val.is_string()) {\n            result = val.get_ref<const std::string&>().length();\n          } else {\n            result = val.size();\n          }\n\n          pop_args(bc);\n          m_stack.emplace_back(result);\n          break;\n        }\n        case Bytecode::Op::Sort: {\n          auto result = get_args(bc)[0]->get<std::vector<json>>();\n          std::sort(result.begin(), result.end());\n          pop_args(bc);\n          m_stack.emplace_back(std::move(result));\n          break;\n        }\n        case Bytecode::Op::At: {\n          auto args = get_args(bc);\n          auto result = args[0]->at(args[1]->get<int>());\n          pop_args(bc);\n          m_stack.emplace_back(result);\n          break;\n        }\n        case Bytecode::Op::First: {\n          auto result = get_args(bc)[0]->front();\n          pop_args(bc);\n          m_stack.emplace_back(result);\n          break;\n        }\n        case Bytecode::Op::Last: {\n          auto result = get_args(bc)[0]->back();\n          pop_args(bc);\n          m_stack.emplace_back(result);\n          break;\n        }\n        case Bytecode::Op::Round: {\n          auto args = get_args(bc);\n          double number = args[0]->get<double>();\n          int precision = args[1]->get<int>();\n          pop_args(bc);\n          m_stack.emplace_back(std::round(number * std::pow(10.0, precision)) / std::pow(10.0, precision));\n          break;\n        }\n        case Bytecode::Op::DivisibleBy: {\n          auto args = get_args(bc);\n          int number = args[0]->get<int>();\n          int divisor = args[1]->get<int>();\n          pop_args(bc);\n          m_stack.emplace_back((divisor != 0) && (number % divisor == 0));\n          break;\n        }\n        case Bytecode::Op::Odd: {\n          int number = get_args(bc)[0]->get<int>();\n          pop_args(bc);\n          m_stack.emplace_back(number % 2 != 0);\n          break;\n        }\n        case Bytecode::Op::Even: {\n          int number = get_args(bc)[0]->get<int>();\n          pop_args(bc);\n          m_stack.emplace_back(number % 2 == 0);\n          break;\n        }\n        case Bytecode::Op::Max: {\n          auto args = get_args(bc);\n          auto result = *std::max_element(args[0]->begin(), args[0]->end());\n          pop_args(bc);\n          m_stack.emplace_back(std::move(result));\n          break;\n        }\n        case Bytecode::Op::Min: {\n          auto args = get_args(bc);\n          auto result = *std::min_element(args[0]->begin(), args[0]->end());\n          pop_args(bc);\n          m_stack.emplace_back(std::move(result));\n          break;\n        }\n        case Bytecode::Op::Not: {\n          bool result = !truthy(*get_args(bc)[0]);\n          pop_args(bc);\n          m_stack.emplace_back(result);\n          break;\n        }\n        case Bytecode::Op::And: {\n          auto args = get_args(bc);\n          bool result = truthy(*args[0]) && truthy(*args[1]);\n          pop_args(bc);\n          m_stack.emplace_back(result);\n          break;\n        }\n        case Bytecode::Op::Or: {\n          auto args = get_args(bc);\n          bool result = truthy(*args[0]) || truthy(*args[1]);\n          pop_args(bc);\n          m_stack.emplace_back(result);\n          break;\n        }\n        case Bytecode::Op::In: {\n          auto args = get_args(bc);\n          bool result = std::find(args[1]->begin(), args[1]->end(), *args[0]) !=\n                        args[1]->end();\n          pop_args(bc);\n          m_stack.emplace_back(result);\n          break;\n        }\n        case Bytecode::Op::Equal: {\n          auto args = get_args(bc);\n          bool result = (*args[0] == *args[1]);\n          pop_args(bc);\n          m_stack.emplace_back(result);\n          break;\n        }\n        case Bytecode::Op::Greater: {\n          auto args = get_args(bc);\n          bool result = (*args[0] > *args[1]);\n          pop_args(bc);\n          m_stack.emplace_back(result);\n          break;\n        }\n        case Bytecode::Op::Less: {\n          auto args = get_args(bc);\n          bool result = (*args[0] < *args[1]);\n          pop_args(bc);\n          m_stack.emplace_back(result);\n          break;\n        }\n        case Bytecode::Op::GreaterEqual: {\n          auto args = get_args(bc);\n          bool result = (*args[0] >= *args[1]);\n          pop_args(bc);\n          m_stack.emplace_back(result);\n          break;\n        }\n        case Bytecode::Op::LessEqual: {\n          auto args = get_args(bc);\n          bool result = (*args[0] <= *args[1]);\n          pop_args(bc);\n          m_stack.emplace_back(result);\n          break;\n        }\n        case Bytecode::Op::Different: {\n          auto args = get_args(bc);\n          bool result = (*args[0] != *args[1]);\n          pop_args(bc);\n          m_stack.emplace_back(result);\n          break;\n        }\n        case Bytecode::Op::Float: {\n          double result =\n              std::stod(get_args(bc)[0]->get_ref<const std::string&>());\n          pop_args(bc);\n          m_stack.emplace_back(result);\n          break;\n        }\n        case Bytecode::Op::Int: {\n          int result = std::stoi(get_args(bc)[0]->get_ref<const std::string&>());\n          pop_args(bc);\n          m_stack.emplace_back(result);\n          break;\n        }\n        case Bytecode::Op::Exists: {\n          auto&& name = get_args(bc)[0]->get_ref<const std::string&>();\n          bool result = (data.find(name) != data.end());\n          pop_args(bc);\n          m_stack.emplace_back(result);\n          break;\n        }\n        case Bytecode::Op::ExistsInObject: {\n          auto args = get_args(bc);\n          auto&& name = args[1]->get_ref<const std::string&>();\n          bool result = (args[0]->find(name) != args[0]->end());\n          pop_args(bc);\n          m_stack.emplace_back(result);\n          break;\n        }\n        case Bytecode::Op::IsBoolean: {\n          bool result = get_args(bc)[0]->is_boolean();\n          pop_args(bc);\n          m_stack.emplace_back(result);\n          break;\n        }\n        case Bytecode::Op::IsNumber: {\n          bool result = get_args(bc)[0]->is_number();\n          pop_args(bc);\n          m_stack.emplace_back(result);\n          break;\n        }\n        case Bytecode::Op::IsInteger: {\n          bool result = get_args(bc)[0]->is_number_integer();\n          pop_args(bc);\n          m_stack.emplace_back(result);\n          break;\n        }\n        case Bytecode::Op::IsFloat: {\n          bool result = get_args(bc)[0]->is_number_float();\n          pop_args(bc);\n          m_stack.emplace_back(result);\n          break;\n        }\n        case Bytecode::Op::IsObject: {\n          bool result = get_args(bc)[0]->is_object();\n          pop_args(bc);\n          m_stack.emplace_back(result);\n          break;\n        }\n        case Bytecode::Op::IsArray: {\n          bool result = get_args(bc)[0]->is_array();\n          pop_args(bc);\n          m_stack.emplace_back(result);\n          break;\n        }\n        case Bytecode::Op::IsString: {\n          bool result = get_args(bc)[0]->is_string();\n          pop_args(bc);\n          m_stack.emplace_back(result);\n          break;\n        }\n        case Bytecode::Op::Default: {\n          // default needs to be a bit \"magic\"; we can't evaluate the first\n          // argument during the push operation, so we swap the arguments during\n          // the parse phase so the second argument is pushed on the stack and\n          // the first argument is in the immediate\n          try {\n            const json* imm = get_imm(bc);\n            // if no exception was raised, replace the stack value with it\n            m_stack.back() = *imm;\n          } catch (std::exception&) {\n            // couldn't read immediate, just leave the stack as is\n          }\n          break;\n        }\n        case Bytecode::Op::Include:\n          Renderer(m_included_templates, m_callbacks).render_to(os, m_included_templates.find(get_imm(bc)->get_ref<const std::string&>())->second, *m_data);\n          break;\n        case Bytecode::Op::Callback: {\n          auto callback = m_callbacks.find_callback(bc.str, bc.args);\n          if (!callback) {\n            inja_throw(\"render_error\", \"function '\" + static_cast<std::string>(bc.str) + \"' (\" + std::to_string(static_cast<unsigned int>(bc.args)) + \") not found\");\n          }\n          json result = callback(get_args(bc));\n          pop_args(bc);\n          m_stack.emplace_back(std::move(result));\n          break;\n        }\n        case Bytecode::Op::Jump: {\n          i = bc.args - 1;  // -1 due to ++i in loop\n          break;\n        }\n        case Bytecode::Op::ConditionalJump: {\n          if (!truthy(m_stack.back())) {\n            i = bc.args - 1;  // -1 due to ++i in loop\n          }\n          m_stack.pop_back();\n          break;\n        }\n        case Bytecode::Op::StartLoop: {\n          // jump past loop body if empty\n          if (m_stack.back().empty()) {\n            m_stack.pop_back();\n            i = bc.args;  // ++i in loop will take it past EndLoop\n            break;\n          }\n\n          m_loop_stack.emplace_back();\n          LoopLevel& level = m_loop_stack.back();\n          level.value_name = bc.str;\n          level.values = std::move(m_stack.back());\n          level.data = (*m_data);\n          m_stack.pop_back();\n\n          if (bc.value.is_string()) {\n            // map iterator\n            if (!level.values.is_object()) {\n              m_loop_stack.pop_back();\n              inja_throw(\"render_error\", \"for key, value requires object\");\n            }\n            level.loop_type = LoopLevel::Type::Map;\n            level.key_name = bc.value.get_ref<const std::string&>();\n\n            // sort by key\n            for (auto it = level.values.begin(), end = level.values.end(); it != end; ++it) {\n              level.map_values.emplace_back(it.key(), &it.value());\n            }\n            auto sort_lambda = [](const LoopLevel::KeyValue& a, const LoopLevel::KeyValue& b) { return a.first < b.first; };\n            std::sort(level.map_values.begin(), level.map_values.end(), sort_lambda);\n            level.map_it = level.map_values.begin();\n          } else {\n            if (!level.values.is_array()) {\n              m_loop_stack.pop_back();\n              inja_throw(\"render_error\", \"type must be array\");\n            }\n\n            // list iterator\n            level.loop_type = LoopLevel::Type::Array;\n            level.index = 0;\n            level.size = level.values.size();\n          }\n\n          // provide parent access in nested loop\n          auto parent_loop_it = level.data.find(\"loop\");\n          if (parent_loop_it != level.data.end()) {\n            json loop_copy = *parent_loop_it;\n            (*parent_loop_it)[\"parent\"] = std::move(loop_copy);\n          }\n\n          // set \"current\" data to loop data\n          m_data = &level.data;\n          update_loop_data();\n          break;\n        }\n        case Bytecode::Op::EndLoop: {\n          if (m_loop_stack.empty()) {\n            inja_throw(\"render_error\", \"unexpected state in renderer\");\n          }\n          LoopLevel& level = m_loop_stack.back();\n\n          bool done;\n          if (level.loop_type == LoopLevel::Type::Array) {\n            level.index += 1;\n            done = (level.index == level.values.size());\n          } else {\n            level.map_it += 1;\n            done = (level.map_it == level.map_values.end());\n          }\n\n          if (done) {\n            m_loop_stack.pop_back();\n            // set \"current\" data to outer loop data or main data as appropriate\n            if (!m_loop_stack.empty()) {\n              m_data = &m_loop_stack.back().data;\n            } else {\n              m_data = &data;\n            }\n            break;\n          }\n\n          update_loop_data();\n\n          // jump back to start of loop\n          i = bc.args - 1;  // -1 due to ++i in loop\n          break;\n        }\n        default: {\n          inja_throw(\"render_error\", \"unknown op in renderer: \" + std::to_string(static_cast<unsigned int>(bc.op)));\n        }\n      }\n    }\n  }\n};\n\n}  // namespace inja\n\n#endif  // INCLUDE_INJA_RENDERER_HPP_\n"
  },
  {
    "path": "inja/string_view.hpp",
    "content": "// Copyright 2017-2019 by Martin Moene\n//\n// string-view lite, a C++17-like string_view for C++98 and later.\n// For more information see https://github.com/martinmoene/string-view-lite\n//\n// Distributed under the Boost Software License, Version 1.0.\n// (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n\n#pragma once\n\n#ifndef NONSTD_SV_LITE_H_INCLUDED\n#define NONSTD_SV_LITE_H_INCLUDED\n\n#define string_view_lite_MAJOR  1\n#define string_view_lite_MINOR  1\n#define string_view_lite_PATCH  0\n\n#define string_view_lite_VERSION  nssv_STRINGIFY(string_view_lite_MAJOR) \".\" nssv_STRINGIFY(string_view_lite_MINOR) \".\" nssv_STRINGIFY(string_view_lite_PATCH)\n\n#define nssv_STRINGIFY(  x )  nssv_STRINGIFY_( x )\n#define nssv_STRINGIFY_( x )  #x\n\n// string-view lite configuration:\n\n#define nssv_STRING_VIEW_DEFAULT  0\n#define nssv_STRING_VIEW_NONSTD   1\n#define nssv_STRING_VIEW_STD      2\n\n#if !defined( nssv_CONFIG_SELECT_STRING_VIEW )\n# define nssv_CONFIG_SELECT_STRING_VIEW  ( nssv_HAVE_STD_STRING_VIEW ? nssv_STRING_VIEW_STD : nssv_STRING_VIEW_NONSTD )\n#endif\n\n#if defined( nssv_CONFIG_SELECT_STD_STRING_VIEW ) || defined( nssv_CONFIG_SELECT_NONSTD_STRING_VIEW )\n# error nssv_CONFIG_SELECT_STD_STRING_VIEW and nssv_CONFIG_SELECT_NONSTD_STRING_VIEW are deprecated and removed, please use nssv_CONFIG_SELECT_STRING_VIEW=nssv_STRING_VIEW_...\n#endif\n\n#ifndef  nssv_CONFIG_STD_SV_OPERATOR\n# define nssv_CONFIG_STD_SV_OPERATOR  0\n#endif\n\n#ifndef  nssv_CONFIG_USR_SV_OPERATOR\n# define nssv_CONFIG_USR_SV_OPERATOR  1\n#endif\n\n#ifdef   nssv_CONFIG_CONVERSION_STD_STRING\n# define nssv_CONFIG_CONVERSION_STD_STRING_CLASS_METHODS   nssv_CONFIG_CONVERSION_STD_STRING\n# define nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS  nssv_CONFIG_CONVERSION_STD_STRING\n#endif\n\n#ifndef  nssv_CONFIG_CONVERSION_STD_STRING_CLASS_METHODS\n# define nssv_CONFIG_CONVERSION_STD_STRING_CLASS_METHODS  1\n#endif\n\n#ifndef  nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS\n# define nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS  1\n#endif\n\n// Control presence of exception handling (try and auto discover):\n\n#ifndef nssv_CONFIG_NO_EXCEPTIONS\n# if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)\n#  define nssv_CONFIG_NO_EXCEPTIONS  0\n# else\n#  define nssv_CONFIG_NO_EXCEPTIONS  1\n# endif\n#endif\n\n// C++ language version detection (C++20 is speculative):\n// Note: VC14.0/1900 (VS2015) lacks too much from C++14.\n\n#ifndef   nssv_CPLUSPLUS\n# if defined(_MSVC_LANG ) && !defined(__clang__)\n#  define nssv_CPLUSPLUS  (_MSC_VER == 1900 ? 201103L : _MSVC_LANG )\n# else\n#  define nssv_CPLUSPLUS  __cplusplus\n# endif\n#endif\n\n#define nssv_CPP98_OR_GREATER  ( nssv_CPLUSPLUS >= 199711L )\n#define nssv_CPP11_OR_GREATER  ( nssv_CPLUSPLUS >= 201103L )\n#define nssv_CPP11_OR_GREATER_ ( nssv_CPLUSPLUS >= 201103L )\n#define nssv_CPP14_OR_GREATER  ( nssv_CPLUSPLUS >= 201402L )\n#define nssv_CPP17_OR_GREATER  ( nssv_CPLUSPLUS >= 201703L )\n#define nssv_CPP20_OR_GREATER  ( nssv_CPLUSPLUS >= 202000L )\n\n// use C++17 std::string_view if available and requested:\n\n#if nssv_CPP17_OR_GREATER && defined(__has_include )\n# if __has_include( <string_view> )\n#  define nssv_HAVE_STD_STRING_VIEW  1\n# else\n#  define nssv_HAVE_STD_STRING_VIEW  0\n# endif\n#else\n# define  nssv_HAVE_STD_STRING_VIEW  0\n#endif\n\n#define  nssv_USES_STD_STRING_VIEW  ( (nssv_CONFIG_SELECT_STRING_VIEW == nssv_STRING_VIEW_STD) || ((nssv_CONFIG_SELECT_STRING_VIEW == nssv_STRING_VIEW_DEFAULT) && nssv_HAVE_STD_STRING_VIEW) )\n\n#define nssv_HAVE_STARTS_WITH ( nssv_CPP20_OR_GREATER || !nssv_USES_STD_STRING_VIEW )\n#define nssv_HAVE_ENDS_WITH     nssv_HAVE_STARTS_WITH\n\n//\n// Use C++17 std::string_view:\n//\n\n#if nssv_USES_STD_STRING_VIEW\n\n#include <string_view>\n\n// Extensions for std::string:\n\n#if nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS\n\nnamespace nonstd {\n\ntemplate< class CharT, class Traits, class Allocator = std::allocator<CharT> >\nstd::basic_string<CharT, Traits, Allocator>\nto_string( std::basic_string_view<CharT, Traits> v, Allocator const & a = Allocator() )\n{\n    return std::basic_string<CharT,Traits, Allocator>( v.begin(), v.end(), a );\n}\n\ntemplate< class CharT, class Traits, class Allocator >\nstd::basic_string_view<CharT, Traits>\nto_string_view( std::basic_string<CharT, Traits, Allocator> const & s )\n{\n    return std::basic_string_view<CharT, Traits>( s.data(), s.size() );\n}\n\n// Literal operators sv and _sv:\n\n#if nssv_CONFIG_STD_SV_OPERATOR\n\nusing namespace std::literals::string_view_literals;\n\n#endif\n\n#if nssv_CONFIG_USR_SV_OPERATOR\n\ninline namespace literals {\ninline namespace string_view_literals {\n\n\nconstexpr std::string_view operator \"\" _sv( const char* str, size_t len ) noexcept  // (1)\n{\n    return std::string_view{ str, len };\n}\n\nconstexpr std::u16string_view operator \"\" _sv( const char16_t* str, size_t len ) noexcept  // (2)\n{\n    return std::u16string_view{ str, len };\n}\n\nconstexpr std::u32string_view operator \"\" _sv( const char32_t* str, size_t len ) noexcept  // (3)\n{\n    return std::u32string_view{ str, len };\n}\n\nconstexpr std::wstring_view operator \"\" _sv( const wchar_t* str, size_t len ) noexcept  // (4)\n{\n    return std::wstring_view{ str, len };\n}\n\n}} // namespace literals::string_view_literals\n\n#endif // nssv_CONFIG_USR_SV_OPERATOR\n\n} // namespace nonstd\n\n#endif // nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS\n\nnamespace nonstd {\n\nusing std::string_view;\nusing std::wstring_view;\nusing std::u16string_view;\nusing std::u32string_view;\nusing std::basic_string_view;\n\n// literal \"sv\" and \"_sv\", see above\n\nusing std::operator==;\nusing std::operator!=;\nusing std::operator<;\nusing std::operator<=;\nusing std::operator>;\nusing std::operator>=;\n\nusing std::operator<<;\n\n} // namespace nonstd\n\n#else // nssv_HAVE_STD_STRING_VIEW\n\n//\n// Before C++17: use string_view lite:\n//\n\n// Compiler versions:\n//\n// MSVC++ 6.0  _MSC_VER == 1200 (Visual Studio 6.0)\n// MSVC++ 7.0  _MSC_VER == 1300 (Visual Studio .NET 2002)\n// MSVC++ 7.1  _MSC_VER == 1310 (Visual Studio .NET 2003)\n// MSVC++ 8.0  _MSC_VER == 1400 (Visual Studio 2005)\n// MSVC++ 9.0  _MSC_VER == 1500 (Visual Studio 2008)\n// MSVC++ 10.0 _MSC_VER == 1600 (Visual Studio 2010)\n// MSVC++ 11.0 _MSC_VER == 1700 (Visual Studio 2012)\n// MSVC++ 12.0 _MSC_VER == 1800 (Visual Studio 2013)\n// MSVC++ 14.0 _MSC_VER == 1900 (Visual Studio 2015)\n// MSVC++ 14.1 _MSC_VER >= 1910 (Visual Studio 2017)\n\n#if defined(_MSC_VER ) && !defined(__clang__)\n# define nssv_COMPILER_MSVC_VER      (_MSC_VER )\n# define nssv_COMPILER_MSVC_VERSION  (_MSC_VER / 10 - 10 * ( 5 + (_MSC_VER < 1900 ) ) )\n#else\n# define nssv_COMPILER_MSVC_VER      0\n# define nssv_COMPILER_MSVC_VERSION  0\n#endif\n\n#define nssv_COMPILER_VERSION( major, minor, patch )  (10 * ( 10 * major + minor) + patch)\n\n#if defined(__clang__)\n# define nssv_COMPILER_CLANG_VERSION  nssv_COMPILER_VERSION(__clang_major__, __clang_minor__, __clang_patchlevel__)\n#else\n# define nssv_COMPILER_CLANG_VERSION    0\n#endif\n\n#if defined(__GNUC__) && !defined(__clang__)\n# define nssv_COMPILER_GNUC_VERSION  nssv_COMPILER_VERSION(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)\n#else\n# define nssv_COMPILER_GNUC_VERSION    0\n#endif\n\n// half-open range [lo..hi):\n#define nssv_BETWEEN( v, lo, hi ) ( (lo) <= (v) && (v) < (hi) )\n\n// Presence of language and library features:\n\n#ifdef _HAS_CPP0X\n# define nssv_HAS_CPP0X  _HAS_CPP0X\n#else\n# define nssv_HAS_CPP0X  0\n#endif\n\n// Unless defined otherwise below, consider VC14 as C++11 for variant-lite:\n\n#if nssv_COMPILER_MSVC_VER >= 1900\n# undef  nssv_CPP11_OR_GREATER\n# define nssv_CPP11_OR_GREATER  1\n#endif\n\n#define nssv_CPP11_90   (nssv_CPP11_OR_GREATER_ || nssv_COMPILER_MSVC_VER >= 1500)\n#define nssv_CPP11_100  (nssv_CPP11_OR_GREATER_ || nssv_COMPILER_MSVC_VER >= 1600)\n#define nssv_CPP11_110  (nssv_CPP11_OR_GREATER_ || nssv_COMPILER_MSVC_VER >= 1700)\n#define nssv_CPP11_120  (nssv_CPP11_OR_GREATER_ || nssv_COMPILER_MSVC_VER >= 1800)\n#define nssv_CPP11_140  (nssv_CPP11_OR_GREATER_ || nssv_COMPILER_MSVC_VER >= 1900)\n#define nssv_CPP11_141  (nssv_CPP11_OR_GREATER_ || nssv_COMPILER_MSVC_VER >= 1910)\n\n#define nssv_CPP14_000  (nssv_CPP14_OR_GREATER)\n#define nssv_CPP17_000  (nssv_CPP17_OR_GREATER)\n\n// Presence of C++11 language features:\n\n#define nssv_HAVE_CONSTEXPR_11          nssv_CPP11_140\n#define nssv_HAVE_EXPLICIT_CONVERSION   nssv_CPP11_140\n#define nssv_HAVE_INLINE_NAMESPACE      nssv_CPP11_140\n#define nssv_HAVE_NOEXCEPT              nssv_CPP11_140\n#define nssv_HAVE_NULLPTR               nssv_CPP11_100\n#define nssv_HAVE_REF_QUALIFIER         nssv_CPP11_140\n#define nssv_HAVE_UNICODE_LITERALS      nssv_CPP11_140\n#define nssv_HAVE_USER_DEFINED_LITERALS nssv_CPP11_140\n#define nssv_HAVE_WCHAR16_T             nssv_CPP11_100\n#define nssv_HAVE_WCHAR32_T             nssv_CPP11_100\n\n#if ! ( ( nssv_CPP11 && nssv_COMPILER_CLANG_VERSION ) || nssv_BETWEEN( nssv_COMPILER_CLANG_VERSION, 300, 400 ) )\n# define nssv_HAVE_STD_DEFINED_LITERALS  nssv_CPP11_140\n#endif\n\n// Presence of C++14 language features:\n\n#define nssv_HAVE_CONSTEXPR_14          nssv_CPP14_000\n\n// Presence of C++17 language features:\n\n#define nssv_HAVE_NODISCARD             nssv_CPP17_000\n\n// Presence of C++ library features:\n\n#define nssv_HAVE_STD_HASH              nssv_CPP11_120\n\n// C++ feature usage:\n\n#if nssv_HAVE_CONSTEXPR_11\n# define nssv_constexpr  constexpr\n#else\n# define nssv_constexpr  /*constexpr*/\n#endif\n\n#if  nssv_HAVE_CONSTEXPR_14\n# define nssv_constexpr14  constexpr\n#else\n# define nssv_constexpr14  /*constexpr*/\n#endif\n\n#if nssv_HAVE_EXPLICIT_CONVERSION\n# define nssv_explicit  explicit\n#else\n# define nssv_explicit  /*explicit*/\n#endif\n\n#if nssv_HAVE_INLINE_NAMESPACE\n# define nssv_inline_ns  inline\n#else\n# define nssv_inline_ns  /*inline*/\n#endif\n\n#if nssv_HAVE_NOEXCEPT\n# define nssv_noexcept  noexcept\n#else\n# define nssv_noexcept  /*noexcept*/\n#endif\n\n//#if nssv_HAVE_REF_QUALIFIER\n//# define nssv_ref_qual  &\n//# define nssv_refref_qual  &&\n//#else\n//# define nssv_ref_qual  /*&*/\n//# define nssv_refref_qual  /*&&*/\n//#endif\n\n#if nssv_HAVE_NULLPTR\n# define nssv_nullptr  nullptr\n#else\n# define nssv_nullptr  NULL\n#endif\n\n#if nssv_HAVE_NODISCARD\n# define nssv_nodiscard  [[nodiscard]]\n#else\n# define nssv_nodiscard  /*[[nodiscard]]*/\n#endif\n\n// Additional includes:\n\n#include <algorithm>\n#include <cassert>\n#include <iterator>\n#include <limits>\n#include <ostream>\n#include <string>   // std::char_traits<>\n\n#if ! nssv_CONFIG_NO_EXCEPTIONS\n# include <stdexcept>\n#endif\n\n#if nssv_CPP11_OR_GREATER\n# include <type_traits>\n#endif\n\n// Clang, GNUC, MSVC warning suppression macros:\n\n#if defined(__clang__)\n# pragma clang diagnostic ignored \"-Wreserved-user-defined-literal\"\n# pragma clang diagnostic push\n# pragma clang diagnostic ignored \"-Wuser-defined-literals\"\n#elif defined(__GNUC__)\n# pragma  GCC  diagnostic push\n# pragma  GCC  diagnostic ignored \"-Wliteral-suffix\"\n#endif // __clang__\n\n#if nssv_COMPILER_MSVC_VERSION >= 140\n# define nssv_SUPPRESS_MSGSL_WARNING(expr)        [[gsl::suppress(expr)]]\n# define nssv_SUPPRESS_MSVC_WARNING(code, descr)  __pragma(warning(suppress: code) )\n# define nssv_DISABLE_MSVC_WARNINGS(codes)        __pragma(warning(push))  __pragma(warning(disable: codes))\n#else\n# define nssv_SUPPRESS_MSGSL_WARNING(expr)\n# define nssv_SUPPRESS_MSVC_WARNING(code, descr)\n# define nssv_DISABLE_MSVC_WARNINGS(codes)\n#endif\n\n#if defined(__clang__)\n# define nssv_RESTORE_WARNINGS()  _Pragma(\"clang diagnostic pop\")\n#elif defined(__GNUC__)\n# define nssv_RESTORE_WARNINGS()  _Pragma(\"GCC diagnostic pop\")\n#elif nssv_COMPILER_MSVC_VERSION >= 140\n# define nssv_RESTORE_WARNINGS()  __pragma(warning(pop ))\n#else\n# define nssv_RESTORE_WARNINGS()\n#endif\n\n// Suppress the following MSVC (GSL) warnings:\n// - C4455, non-gsl   : 'operator \"\"sv': literal suffix identifiers that do not\n//                      start with an underscore are reserved\n// - C26472, gsl::t.1 : don't use a static_cast for arithmetic conversions;\n//                      use brace initialization, gsl::narrow_cast or gsl::narow\n// - C26481: gsl::b.1 : don't use pointer arithmetic. Use span instead\n\nnssv_DISABLE_MSVC_WARNINGS( 4455 26481 26472 )\n//nssv_DISABLE_CLANG_WARNINGS( \"-Wuser-defined-literals\" )\n//nssv_DISABLE_GNUC_WARNINGS( -Wliteral-suffix )\n\nnamespace nonstd { namespace sv_lite {\n\ntemplate\n<\n    class CharT,\n    class Traits = std::char_traits<CharT>\n>\nclass basic_string_view;\n\n//\n// basic_string_view:\n//\n\ntemplate\n<\n    class CharT,\n    class Traits /* = std::char_traits<CharT> */\n>\nclass basic_string_view\n{\npublic:\n    // Member types:\n\n    typedef Traits traits_type;\n    typedef CharT  value_type;\n\n    typedef CharT       * pointer;\n    typedef CharT const * const_pointer;\n    typedef CharT       & reference;\n    typedef CharT const & const_reference;\n\n    typedef const_pointer iterator;\n    typedef const_pointer const_iterator;\n    typedef std::reverse_iterator< const_iterator > reverse_iterator;\n    typedef\tstd::reverse_iterator< const_iterator > const_reverse_iterator;\n\n    typedef std::size_t     size_type;\n    typedef std::ptrdiff_t  difference_type;\n\n    // 24.4.2.1 Construction and assignment:\n\n    nssv_constexpr basic_string_view() nssv_noexcept\n        : data_( nssv_nullptr )\n        , size_( 0 )\n    {}\n\n#if nssv_CPP11_OR_GREATER\n    nssv_constexpr basic_string_view( basic_string_view const & other ) nssv_noexcept = default;\n#else\n    nssv_constexpr basic_string_view( basic_string_view const & other ) nssv_noexcept\n        : data_( other.data_)\n        , size_( other.size_)\n    {}\n#endif\n\n    nssv_constexpr basic_string_view( CharT const * s, size_type count )\n        : data_( s )\n        , size_( count )\n    {}\n\n    nssv_constexpr basic_string_view( CharT const * s)\n        : data_( s )\n        , size_( Traits::length(s) )\n    {}\n\n    // Assignment:\n\n#if nssv_CPP11_OR_GREATER\n    nssv_constexpr14 basic_string_view & operator=( basic_string_view const & other ) nssv_noexcept = default;\n#else\n    nssv_constexpr14 basic_string_view & operator=( basic_string_view const & other ) nssv_noexcept\n    {\n        data_ = other.data_;\n        size_ = other.size_;\n        return *this;\n    }\n#endif\n\n    // 24.4.2.2 Iterator support:\n\n    nssv_constexpr const_iterator begin()  const nssv_noexcept { return data_;         }\n    nssv_constexpr const_iterator end()    const nssv_noexcept { return data_ + size_; }\n\n    nssv_constexpr const_iterator cbegin() const nssv_noexcept { return begin(); }\n    nssv_constexpr const_iterator cend()   const nssv_noexcept { return end();   }\n\n    nssv_constexpr const_reverse_iterator rbegin()  const nssv_noexcept { return const_reverse_iterator( end() );   }\n    nssv_constexpr const_reverse_iterator rend()    const nssv_noexcept { return const_reverse_iterator( begin() ); }\n\n    nssv_constexpr const_reverse_iterator crbegin() const nssv_noexcept { return rbegin(); }\n    nssv_constexpr const_reverse_iterator crend()   const nssv_noexcept { return rend();   }\n\n    // 24.4.2.3 Capacity:\n\n    nssv_constexpr size_type size()     const nssv_noexcept { return size_; }\n    nssv_constexpr size_type length()   const nssv_noexcept { return size_; }\n    nssv_constexpr size_type max_size() const nssv_noexcept { return (std::numeric_limits< size_type >::max)(); }\n\n    // since C++20\n    nssv_nodiscard nssv_constexpr bool empty() const nssv_noexcept\n    {\n        return 0 == size_;\n    }\n\n    // 24.4.2.4 Element access:\n\n    nssv_constexpr const_reference operator[]( size_type pos ) const\n    {\n        return data_at( pos );\n    }\n\n    nssv_constexpr14 const_reference at( size_type pos ) const\n    {\n#if nssv_CONFIG_NO_EXCEPTIONS\n        assert( pos < size() );\n#else\n        if ( pos >= size() )\n        {\n            throw std::out_of_range(\"nonst::string_view::at()\");\n        }\n#endif\n        return data_at( pos );\n    }\n\n    nssv_constexpr const_reference front() const { return data_at( 0 );          }\n    nssv_constexpr const_reference back()  const { return data_at( size() - 1 ); }\n\n    nssv_constexpr const_pointer   data()  const nssv_noexcept { return data_; }\n\n    // 24.4.2.5 Modifiers:\n\n    nssv_constexpr14 void remove_prefix( size_type n )\n    {\n        assert( n <= size() );\n        data_ += n;\n        size_ -= n;\n    }\n\n    nssv_constexpr14 void remove_suffix( size_type n )\n    {\n        assert( n <= size() );\n        size_ -= n;\n    }\n\n    nssv_constexpr14 void swap( basic_string_view & other ) nssv_noexcept\n    {\n        using std::swap;\n        swap( data_, other.data_ );\n        swap( size_, other.size_ );\n    }\n\n    // 24.4.2.6 String operations:\n\n    size_type copy( CharT * dest, size_type n, size_type pos = 0 ) const\n    {\n#if nssv_CONFIG_NO_EXCEPTIONS\n        assert( pos <= size() );\n#else\n        if ( pos > size() )\n        {\n            throw std::out_of_range(\"nonst::string_view::copy()\");\n        }\n#endif\n        const size_type rlen = (std::min)( n, size() - pos );\n\n        (void) Traits::copy( dest, data() + pos, rlen );\n\n        return rlen;\n    }\n\n    nssv_constexpr14 basic_string_view substr( size_type pos = 0, size_type n = npos ) const\n    {\n#if nssv_CONFIG_NO_EXCEPTIONS\n        assert( pos <= size() );\n#else\n        if ( pos > size() )\n        {\n            throw std::out_of_range(\"nonst::string_view::substr()\");\n        }\n#endif\n        return basic_string_view( data() + pos, (std::min)( n, size() - pos ) );\n    }\n\n    // compare(), 6x:\n\n    nssv_constexpr14 int compare( basic_string_view other ) const nssv_noexcept // (1)\n    {\n        if ( const int result = Traits::compare( data(), other.data(), (std::min)( size(), other.size() ) ) )\n            return result;\n\n        return size() == other.size() ? 0 : size() < other.size() ? -1 : 1;\n    }\n\n    nssv_constexpr int compare( size_type pos1, size_type n1, basic_string_view other ) const // (2)\n    {\n        return substr( pos1, n1 ).compare( other );\n    }\n\n    nssv_constexpr int compare( size_type pos1, size_type n1, basic_string_view other, size_type pos2, size_type n2 ) const // (3)\n    {\n        return substr( pos1, n1 ).compare( other.substr( pos2, n2 ) );\n    }\n\n    nssv_constexpr int compare( CharT const * s ) const // (4)\n    {\n        return compare( basic_string_view( s ) );\n    }\n\n    nssv_constexpr int compare( size_type pos1, size_type n1, CharT const * s ) const // (5)\n    {\n        return substr( pos1, n1 ).compare( basic_string_view( s ) );\n    }\n\n    nssv_constexpr int compare( size_type pos1, size_type n1, CharT const * s, size_type n2 ) const // (6)\n    {\n        return substr( pos1, n1 ).compare( basic_string_view( s, n2 ) );\n    }\n\n    // 24.4.2.7 Searching:\n\n    // starts_with(), 3x, since C++20:\n\n    nssv_constexpr bool starts_with( basic_string_view v ) const nssv_noexcept  // (1)\n    {\n        return size() >= v.size() && compare( 0, v.size(), v ) == 0;\n    }\n\n    nssv_constexpr bool starts_with( CharT c ) const nssv_noexcept  // (2)\n    {\n        return starts_with( basic_string_view( &c, 1 ) );\n    }\n\n    nssv_constexpr bool starts_with( CharT const * s ) const  // (3)\n    {\n        return starts_with( basic_string_view( s ) );\n    }\n\n    // ends_with(), 3x, since C++20:\n\n    nssv_constexpr bool ends_with( basic_string_view v ) const nssv_noexcept  // (1)\n    {\n        return size() >= v.size() && compare( size() - v.size(), npos, v ) == 0;\n    }\n\n    nssv_constexpr bool ends_with( CharT c ) const nssv_noexcept  // (2)\n    {\n        return ends_with( basic_string_view( &c, 1 ) );\n    }\n\n    nssv_constexpr bool ends_with( CharT const * s ) const  // (3)\n    {\n        return ends_with( basic_string_view( s ) );\n    }\n\n    // find(), 4x:\n\n    nssv_constexpr14 size_type find( basic_string_view v, size_type pos = 0 ) const nssv_noexcept  // (1)\n    {\n        return assert( v.size() == 0 || v.data() != nssv_nullptr )\n            , pos >= size()\n            ? npos\n            : to_pos( std::search( cbegin() + pos, cend(), v.cbegin(), v.cend(), Traits::eq ) );\n    }\n\n    nssv_constexpr14 size_type find( CharT c, size_type pos = 0 ) const nssv_noexcept  // (2)\n    {\n        return find( basic_string_view( &c, 1 ), pos );\n    }\n\n    nssv_constexpr14 size_type find( CharT const * s, size_type pos, size_type n ) const  // (3)\n    {\n        return find( basic_string_view( s, n ), pos );\n    }\n\n    nssv_constexpr14 size_type find( CharT const * s, size_type pos = 0 ) const  // (4)\n    {\n        return find( basic_string_view( s ), pos );\n    }\n\n    // rfind(), 4x:\n\n    nssv_constexpr14 size_type rfind( basic_string_view v, size_type pos = npos ) const nssv_noexcept  // (1)\n    {\n        if ( size() < v.size() )\n            return npos;\n\n        if ( v.empty() )\n            return (std::min)( size(), pos );\n\n        const_iterator last   = cbegin() + (std::min)( size() - v.size(), pos ) + v.size();\n        const_iterator result = std::find_end( cbegin(), last, v.cbegin(), v.cend(), Traits::eq );\n\n        return result != last ? size_type( result - cbegin() ) : npos;\n    }\n\n    nssv_constexpr14 size_type rfind( CharT c, size_type pos = npos ) const nssv_noexcept  // (2)\n    {\n        return rfind( basic_string_view( &c, 1 ), pos );\n    }\n\n    nssv_constexpr14 size_type rfind( CharT const * s, size_type pos, size_type n ) const  // (3)\n    {\n        return rfind( basic_string_view( s, n ), pos );\n    }\n\n    nssv_constexpr14 size_type rfind( CharT const * s, size_type pos = npos ) const  // (4)\n    {\n        return rfind( basic_string_view( s ), pos );\n    }\n\n    // find_first_of(), 4x:\n\n    nssv_constexpr size_type find_first_of( basic_string_view v, size_type pos = 0 ) const nssv_noexcept  // (1)\n    {\n        return pos >= size()\n            ? npos\n            : to_pos( std::find_first_of( cbegin() + pos, cend(), v.cbegin(), v.cend(), Traits::eq ) );\n    }\n\n    nssv_constexpr size_type find_first_of( CharT c, size_type pos = 0 ) const nssv_noexcept  // (2)\n    {\n        return find_first_of( basic_string_view( &c, 1 ), pos );\n    }\n\n    nssv_constexpr size_type find_first_of( CharT const * s, size_type pos, size_type n ) const  // (3)\n    {\n        return find_first_of( basic_string_view( s, n ), pos );\n    }\n\n    nssv_constexpr size_type find_first_of(  CharT const * s, size_type pos = 0 ) const  // (4)\n    {\n        return find_first_of( basic_string_view( s ), pos );\n    }\n\n    // find_last_of(), 4x:\n\n    nssv_constexpr size_type find_last_of( basic_string_view v, size_type pos = npos ) const nssv_noexcept  // (1)\n    {\n        return empty()\n            ? npos\n            : pos >= size()\n            ? find_last_of( v, size() - 1 )\n            : to_pos( std::find_first_of( const_reverse_iterator( cbegin() + pos + 1 ), crend(), v.cbegin(), v.cend(), Traits::eq ) );\n    }\n\n    nssv_constexpr size_type find_last_of( CharT c, size_type pos = npos ) const nssv_noexcept  // (2)\n    {\n        return find_last_of( basic_string_view( &c, 1 ), pos );\n    }\n\n    nssv_constexpr size_type find_last_of( CharT const * s, size_type pos, size_type count ) const  // (3)\n    {\n        return find_last_of( basic_string_view( s, count ), pos );\n    }\n\n    nssv_constexpr size_type find_last_of( CharT const * s, size_type pos = npos ) const  // (4)\n    {\n        return find_last_of( basic_string_view( s ), pos );\n    }\n\n    // find_first_not_of(), 4x:\n\n    nssv_constexpr size_type find_first_not_of( basic_string_view v, size_type pos = 0 ) const nssv_noexcept  // (1)\n    {\n        return pos >= size()\n            ? npos\n            : to_pos( std::find_if( cbegin() + pos, cend(), not_in_view( v ) ) );\n    }\n\n    nssv_constexpr size_type find_first_not_of( CharT c, size_type pos = 0 ) const nssv_noexcept  // (2)\n    {\n        return find_first_not_of( basic_string_view( &c, 1 ), pos );\n    }\n\n    nssv_constexpr size_type find_first_not_of( CharT const * s, size_type pos, size_type count ) const  // (3)\n    {\n        return find_first_not_of( basic_string_view( s, count ), pos );\n    }\n\n    nssv_constexpr size_type find_first_not_of( CharT const * s, size_type pos = 0 ) const  // (4)\n    {\n        return find_first_not_of( basic_string_view( s ), pos );\n    }\n\n    // find_last_not_of(), 4x:\n\n    nssv_constexpr size_type find_last_not_of( basic_string_view v, size_type pos = npos ) const nssv_noexcept  // (1)\n    {\n        return empty()\n            ? npos\n            : pos >= size()\n            ? find_last_not_of( v, size() - 1 )\n            : to_pos( std::find_if( const_reverse_iterator( cbegin() + pos + 1 ), crend(), not_in_view( v ) ) );\n    }\n\n    nssv_constexpr size_type find_last_not_of( CharT c, size_type pos = npos ) const nssv_noexcept  // (2)\n    {\n        return find_last_not_of( basic_string_view( &c, 1 ), pos );\n    }\n\n    nssv_constexpr size_type find_last_not_of( CharT const * s, size_type pos, size_type count ) const  // (3)\n    {\n        return find_last_not_of( basic_string_view( s, count ), pos );\n    }\n\n    nssv_constexpr size_type find_last_not_of( CharT const * s, size_type pos = npos ) const  // (4)\n    {\n        return find_last_not_of( basic_string_view( s ), pos );\n    }\n\n    // Constants:\n\n#if nssv_CPP17_OR_GREATER\n    static nssv_constexpr size_type npos = size_type(-1);\n#elif nssv_CPP11_OR_GREATER\n    enum : size_type { npos = size_type(-1) };\n#else\n    enum { npos = size_type(-1) };\n#endif\n\nprivate:\n    struct not_in_view\n    {\n        const basic_string_view v;\n\n        nssv_constexpr not_in_view( basic_string_view v ) : v( v ) {}\n\n        nssv_constexpr bool operator()( CharT c ) const\n        {\n            return npos == v.find_first_of( c );\n        }\n    };\n\n    nssv_constexpr size_type to_pos( const_iterator it ) const\n    {\n        return it == cend() ? npos : size_type( it - cbegin() );\n    }\n\n    nssv_constexpr size_type to_pos( const_reverse_iterator it ) const\n    {\n        return it == crend() ? npos : size_type( crend() - it - 1 );\n    }\n\n    nssv_constexpr const_reference data_at( size_type pos ) const\n    {\n#if nssv_BETWEEN( nssv_COMPILER_GNUC_VERSION, 1, 500 )\n        return data_[pos];\n#else\n        return assert( pos < size() ), data_[pos];\n#endif\n    }\n\nprivate:\n    const_pointer data_;\n    size_type     size_;\n\npublic:\n#if nssv_CONFIG_CONVERSION_STD_STRING_CLASS_METHODS\n\n    template< class Allocator >\n    basic_string_view( std::basic_string<CharT, Traits, Allocator> const & s ) nssv_noexcept\n        : data_( s.data() )\n        , size_( s.size() )\n    {}\n\n#if nssv_HAVE_EXPLICIT_CONVERSION\n\n    template< class Allocator >\n    explicit operator std::basic_string<CharT, Traits, Allocator>() const\n    {\n        return to_string( Allocator() );\n    }\n\n#endif // nssv_HAVE_EXPLICIT_CONVERSION\n\n#if nssv_CPP11_OR_GREATER\n\n    template< class Allocator = std::allocator<CharT> >\n    std::basic_string<CharT, Traits, Allocator>\n    to_string( Allocator const & a = Allocator() ) const\n    {\n        return std::basic_string<CharT, Traits, Allocator>( begin(), end(), a );\n    }\n\n#else\n\n    std::basic_string<CharT, Traits>\n    to_string() const\n    {\n        return std::basic_string<CharT, Traits>( begin(), end() );\n    }\n\n    template< class Allocator >\n    std::basic_string<CharT, Traits, Allocator>\n    to_string( Allocator const & a ) const\n    {\n        return std::basic_string<CharT, Traits, Allocator>( begin(), end(), a );\n    }\n\n#endif // nssv_CPP11_OR_GREATER\n\n#endif // nssv_CONFIG_CONVERSION_STD_STRING_CLASS_METHODS\n};\n\n//\n// Non-member functions:\n//\n\n// 24.4.3 Non-member comparison functions:\n// lexicographically compare two string views (function template):\n\ntemplate< class CharT, class Traits >\nnssv_constexpr bool operator== (\n    basic_string_view <CharT, Traits> lhs,\n    basic_string_view <CharT, Traits> rhs ) nssv_noexcept\n{ return lhs.compare( rhs ) == 0 ; }\n\ntemplate< class CharT, class Traits >\nnssv_constexpr bool operator!= (\n    basic_string_view <CharT, Traits> lhs,\n    basic_string_view <CharT, Traits> rhs ) nssv_noexcept\n{ return lhs.compare( rhs ) != 0 ; }\n\ntemplate< class CharT, class Traits >\nnssv_constexpr bool operator< (\n    basic_string_view <CharT, Traits> lhs,\n    basic_string_view <CharT, Traits> rhs ) nssv_noexcept\n{ return lhs.compare( rhs ) < 0 ; }\n\ntemplate< class CharT, class Traits >\nnssv_constexpr bool operator<= (\n    basic_string_view <CharT, Traits> lhs,\n    basic_string_view <CharT, Traits> rhs ) nssv_noexcept\n{ return lhs.compare( rhs ) <= 0 ; }\n\ntemplate< class CharT, class Traits >\nnssv_constexpr bool operator> (\n    basic_string_view <CharT, Traits> lhs,\n    basic_string_view <CharT, Traits> rhs ) nssv_noexcept\n{ return lhs.compare( rhs ) > 0 ; }\n\ntemplate< class CharT, class Traits >\nnssv_constexpr bool operator>= (\n    basic_string_view <CharT, Traits> lhs,\n    basic_string_view <CharT, Traits> rhs ) nssv_noexcept\n{ return lhs.compare( rhs ) >= 0 ; }\n\n// Let S be basic_string_view<CharT, Traits>, and sv be an instance of S.\n// Implementations shall provide sufficient additional overloads marked\n// constexpr and noexcept so that an object t with an implicit conversion\n// to S can be compared according to Table 67.\n\n#if nssv_CPP11_OR_GREATER && ! nssv_BETWEEN( nssv_COMPILER_MSVC_VERSION, 100, 141 )\n\n#define nssv_BASIC_STRING_VIEW_I(T,U)  typename std::decay< basic_string_view<T,U> >::type\n\n#if nssv_BETWEEN( nssv_COMPILER_MSVC_VERSION, 140, 150 )\n# define nssv_MSVC_ORDER(x)  , int=x\n#else\n# define nssv_MSVC_ORDER(x)  /*, int=x*/\n#endif\n\n// ==\n\ntemplate< class CharT, class Traits  nssv_MSVC_ORDER(1) >\nnssv_constexpr bool operator==(\n         basic_string_view  <CharT, Traits> lhs,\n    nssv_BASIC_STRING_VIEW_I(CharT, Traits) rhs ) nssv_noexcept\n{ return lhs.compare( rhs ) == 0; }\n\ntemplate< class CharT, class Traits  nssv_MSVC_ORDER(2) >\nnssv_constexpr bool operator==(\n    nssv_BASIC_STRING_VIEW_I(CharT, Traits) lhs,\n         basic_string_view  <CharT, Traits> rhs ) nssv_noexcept\n{ return lhs.size() == rhs.size() && lhs.compare( rhs ) == 0; }\n\n// !=\n\ntemplate< class CharT, class Traits  nssv_MSVC_ORDER(1) >\nnssv_constexpr bool operator!= (\n         basic_string_view  < CharT, Traits > lhs,\n    nssv_BASIC_STRING_VIEW_I( CharT, Traits ) rhs ) nssv_noexcept\n{ return lhs.size() != rhs.size() || lhs.compare( rhs ) != 0 ; }\n\ntemplate< class CharT, class Traits  nssv_MSVC_ORDER(2) >\nnssv_constexpr bool operator!= (\n    nssv_BASIC_STRING_VIEW_I( CharT, Traits ) lhs,\n         basic_string_view  < CharT, Traits > rhs ) nssv_noexcept\n{ return lhs.compare( rhs ) != 0 ; }\n\n// <\n\ntemplate< class CharT, class Traits  nssv_MSVC_ORDER(1) >\nnssv_constexpr bool operator< (\n         basic_string_view  < CharT, Traits > lhs,\n    nssv_BASIC_STRING_VIEW_I( CharT, Traits ) rhs ) nssv_noexcept\n{ return lhs.compare( rhs ) < 0 ; }\n\ntemplate< class CharT, class Traits  nssv_MSVC_ORDER(2) >\nnssv_constexpr bool operator< (\n    nssv_BASIC_STRING_VIEW_I( CharT, Traits ) lhs,\n         basic_string_view  < CharT, Traits > rhs ) nssv_noexcept\n{ return lhs.compare( rhs ) < 0 ; }\n\n// <=\n\ntemplate< class CharT, class Traits  nssv_MSVC_ORDER(1) >\nnssv_constexpr bool operator<= (\n         basic_string_view  < CharT, Traits > lhs,\n    nssv_BASIC_STRING_VIEW_I( CharT, Traits ) rhs ) nssv_noexcept\n{ return lhs.compare( rhs ) <= 0 ; }\n\ntemplate< class CharT, class Traits  nssv_MSVC_ORDER(2) >\nnssv_constexpr bool operator<= (\n    nssv_BASIC_STRING_VIEW_I( CharT, Traits ) lhs,\n         basic_string_view  < CharT, Traits > rhs ) nssv_noexcept\n{ return lhs.compare( rhs ) <= 0 ; }\n\n// >\n\ntemplate< class CharT, class Traits  nssv_MSVC_ORDER(1) >\nnssv_constexpr bool operator> (\n         basic_string_view  < CharT, Traits > lhs,\n    nssv_BASIC_STRING_VIEW_I( CharT, Traits ) rhs ) nssv_noexcept\n{ return lhs.compare( rhs ) > 0 ; }\n\ntemplate< class CharT, class Traits  nssv_MSVC_ORDER(2) >\nnssv_constexpr bool operator> (\n    nssv_BASIC_STRING_VIEW_I( CharT, Traits ) lhs,\n         basic_string_view  < CharT, Traits > rhs ) nssv_noexcept\n{ return lhs.compare( rhs ) > 0 ; }\n\n// >=\n\ntemplate< class CharT, class Traits  nssv_MSVC_ORDER(1) >\nnssv_constexpr bool operator>= (\n         basic_string_view  < CharT, Traits > lhs,\n    nssv_BASIC_STRING_VIEW_I( CharT, Traits ) rhs ) nssv_noexcept\n{ return lhs.compare( rhs ) >= 0 ; }\n\ntemplate< class CharT, class Traits  nssv_MSVC_ORDER(2) >\nnssv_constexpr bool operator>= (\n    nssv_BASIC_STRING_VIEW_I( CharT, Traits ) lhs,\n         basic_string_view  < CharT, Traits > rhs ) nssv_noexcept\n{ return lhs.compare( rhs ) >= 0 ; }\n\n#undef nssv_MSVC_ORDER\n#undef nssv_BASIC_STRING_VIEW_I\n\n#endif // nssv_CPP11_OR_GREATER\n\n// 24.4.4 Inserters and extractors:\n\nnamespace detail {\n\ntemplate< class Stream >\nvoid write_padding( Stream & os, std::streamsize n )\n{\n    for ( std::streamsize i = 0; i < n; ++i )\n        os.rdbuf()->sputc( os.fill() );\n}\n\ntemplate< class Stream, class View >\nStream & write_to_stream( Stream & os, View const & sv )\n{\n    typename Stream::sentry sentry( os );\n\n    if ( !os )\n        return os;\n\n    const std::streamsize length = static_cast<std::streamsize>( sv.length() );\n\n    // Whether, and how, to pad:\n    const bool      pad = ( length < os.width() );\n    const bool left_pad = pad && ( os.flags() & std::ios_base::adjustfield ) == std::ios_base::right;\n\n    if ( left_pad )\n        write_padding( os, os.width() - length );\n\n    // Write span characters:\n    os.rdbuf()->sputn( sv.begin(), length );\n\n    if ( pad && !left_pad )\n        write_padding( os, os.width() - length );\n\n    // Reset output stream width:\n    os.width( 0 );\n\n    return os;\n}\n\n} // namespace detail\n\ntemplate< class CharT, class Traits >\nstd::basic_ostream<CharT, Traits> &\noperator<<(\n    std::basic_ostream<CharT, Traits>& os,\n    basic_string_view <CharT, Traits> sv )\n{\n    return detail::write_to_stream( os, sv );\n}\n\n// Several typedefs for common character types are provided:\n\ntypedef basic_string_view<char>      string_view;\ntypedef basic_string_view<wchar_t>   wstring_view;\n#if nssv_HAVE_WCHAR16_T\ntypedef basic_string_view<char16_t>  u16string_view;\ntypedef basic_string_view<char32_t>  u32string_view;\n#endif\n\n}} // namespace nonstd::sv_lite\n\n//\n// 24.4.6 Suffix for basic_string_view literals:\n//\n\n#if nssv_HAVE_USER_DEFINED_LITERALS\n\nnamespace nonstd {\nnssv_inline_ns namespace literals {\nnssv_inline_ns namespace string_view_literals {\n\n#if nssv_CONFIG_STD_SV_OPERATOR && nssv_HAVE_STD_DEFINED_LITERALS\n\nnssv_constexpr nonstd::sv_lite::string_view operator \"\" sv( const char* str, size_t len ) nssv_noexcept  // (1)\n{\n    return nonstd::sv_lite::string_view{ str, len };\n}\n\nnssv_constexpr nonstd::sv_lite::u16string_view operator \"\" sv( const char16_t* str, size_t len ) nssv_noexcept  // (2)\n{\n    return nonstd::sv_lite::u16string_view{ str, len };\n}\n\nnssv_constexpr nonstd::sv_lite::u32string_view operator \"\" sv( const char32_t* str, size_t len ) nssv_noexcept  // (3)\n{\n    return nonstd::sv_lite::u32string_view{ str, len };\n}\n\nnssv_constexpr nonstd::sv_lite::wstring_view operator \"\" sv( const wchar_t* str, size_t len ) nssv_noexcept  // (4)\n{\n    return nonstd::sv_lite::wstring_view{ str, len };\n}\n\n#endif // nssv_CONFIG_STD_SV_OPERATOR && nssv_HAVE_STD_DEFINED_LITERALS\n\n#if nssv_CONFIG_USR_SV_OPERATOR\n\nnssv_constexpr nonstd::sv_lite::string_view operator \"\" _sv( const char* str, size_t len ) nssv_noexcept  // (1)\n{\n    return nonstd::sv_lite::string_view{ str, len };\n}\n\nnssv_constexpr nonstd::sv_lite::u16string_view operator \"\" _sv( const char16_t* str, size_t len ) nssv_noexcept  // (2)\n{\n    return nonstd::sv_lite::u16string_view{ str, len };\n}\n\nnssv_constexpr nonstd::sv_lite::u32string_view operator \"\" _sv( const char32_t* str, size_t len ) nssv_noexcept  // (3)\n{\n    return nonstd::sv_lite::u32string_view{ str, len };\n}\n\nnssv_constexpr nonstd::sv_lite::wstring_view operator \"\" _sv( const wchar_t* str, size_t len ) nssv_noexcept  // (4)\n{\n    return nonstd::sv_lite::wstring_view{ str, len };\n}\n\n#endif // nssv_CONFIG_USR_SV_OPERATOR\n\n}}} // namespace nonstd::literals::string_view_literals\n\n#endif\n\n//\n// Extensions for std::string:\n//\n\n#if nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS\n\nnamespace nonstd {\nnamespace sv_lite {\n\n// Exclude MSVC 14 (19.00): it yields ambiguous to_string():\n\n#if nssv_CPP11_OR_GREATER && nssv_COMPILER_MSVC_VERSION != 140\n\ntemplate< class CharT, class Traits, class Allocator = std::allocator<CharT> >\nstd::basic_string<CharT, Traits, Allocator>\nto_string( basic_string_view<CharT, Traits> v, Allocator const & a = Allocator() )\n{\n    return std::basic_string<CharT,Traits, Allocator>( v.begin(), v.end(), a );\n}\n\n#else\n\ntemplate< class CharT, class Traits >\nstd::basic_string<CharT, Traits>\nto_string( basic_string_view<CharT, Traits> v )\n{\n    return std::basic_string<CharT, Traits>( v.begin(), v.end() );\n}\n\ntemplate< class CharT, class Traits, class Allocator >\nstd::basic_string<CharT, Traits, Allocator>\nto_string( basic_string_view<CharT, Traits> v, Allocator const & a )\n{\n    return std::basic_string<CharT, Traits, Allocator>( v.begin(), v.end(), a );\n}\n\n#endif // nssv_CPP11_OR_GREATER\n\ntemplate< class CharT, class Traits, class Allocator >\nbasic_string_view<CharT, Traits>\nto_string_view( std::basic_string<CharT, Traits, Allocator> const & s )\n{\n    return basic_string_view<CharT, Traits>( s.data(), s.size() );\n}\n\n}} // namespace nonstd::sv_lite\n\n#endif // nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS\n\n//\n// make types and algorithms available in namespace nonstd:\n//\n\nnamespace nonstd {\n\nusing sv_lite::basic_string_view;\nusing sv_lite::string_view;\nusing sv_lite::wstring_view;\n\n#if nssv_HAVE_WCHAR16_T\nusing sv_lite::u16string_view;\n#endif\n#if nssv_HAVE_WCHAR32_T\nusing sv_lite::u32string_view;\n#endif\n\n// literal \"sv\"\n\nusing sv_lite::operator==;\nusing sv_lite::operator!=;\nusing sv_lite::operator<;\nusing sv_lite::operator<=;\nusing sv_lite::operator>;\nusing sv_lite::operator>=;\n\nusing sv_lite::operator<<;\n\n#if nssv_CONFIG_CONVERSION_STD_STRING_FREE_FUNCTIONS\nusing sv_lite::to_string;\nusing sv_lite::to_string_view;\n#endif\n\n} // namespace nonstd\n\n// 24.4.5 Hash support (C++11):\n\n// Note: The hash value of a string view object is equal to the hash value of\n// the corresponding string object.\n\n#if nssv_HAVE_STD_HASH\n\n#include <functional>\n\nnamespace std {\n\ntemplate<>\nstruct hash< nonstd::string_view >\n{\npublic:\n    std::size_t operator()( nonstd::string_view v ) const nssv_noexcept\n    {\n        return std::hash<std::string>()( std::string( v.data(), v.size() ) );\n    }\n};\n\ntemplate<>\nstruct hash< nonstd::wstring_view >\n{\npublic:\n    std::size_t operator()( nonstd::wstring_view v ) const nssv_noexcept\n    {\n        return std::hash<std::wstring>()( std::wstring( v.data(), v.size() ) );\n    }\n};\n\ntemplate<>\nstruct hash< nonstd::u16string_view >\n{\npublic:\n    std::size_t operator()( nonstd::u16string_view v ) const nssv_noexcept\n    {\n        return std::hash<std::u16string>()( std::u16string( v.data(), v.size() ) );\n    }\n};\n\ntemplate<>\nstruct hash< nonstd::u32string_view >\n{\npublic:\n    std::size_t operator()( nonstd::u32string_view v ) const nssv_noexcept\n    {\n        return std::hash<std::u32string>()( std::u32string( v.data(), v.size() ) );\n    }\n};\n\n} // namespace std\n\n#endif // nssv_HAVE_STD_HASH\n\nnssv_RESTORE_WARNINGS()\n\n#endif // nssv_HAVE_STD_STRING_VIEW\n#endif // NONSTD_SV_LITE_H_INCLUDED\n"
  },
  {
    "path": "inja/template.hpp",
    "content": "// Copyright (c) 2019 Pantor. All rights reserved.\n\n#ifndef INCLUDE_INJA_TEMPLATE_HPP_\n#define INCLUDE_INJA_TEMPLATE_HPP_\n\n#include <map>\n#include <string>\n#include <vector>\n\n#include \"bytecode.hpp\"\n\n\nnamespace inja {\n\n/*!\n * \\brief The main inja Template.\n */\nstruct Template {\n  std::vector<Bytecode> bytecodes;\n  std::string content;\n};\n\nusing TemplateStorage = std::map<std::string, Template>;\n\n}  // namespace inja\n\n#endif  // INCLUDE_INJA_TEMPLATE_HPP_\n"
  },
  {
    "path": "inja/token.hpp",
    "content": "// Copyright (c) 2019 Pantor. All rights reserved.\n\n#ifndef INCLUDE_INJA_TOKEN_HPP_\n#define INCLUDE_INJA_TOKEN_HPP_\n\n#include <string>\n\n#include \"string_view.hpp\"\n\n\nnamespace inja {\n\n/*!\n * \\brief Helper-class for the inja Parser.\n */\nstruct Token {\n  enum class Kind {\n    Text,\n    ExpressionOpen,      // {{\n    ExpressionClose,     // }}\n    LineStatementOpen,   // ##\n    LineStatementClose,  // \\n\n    StatementOpen,       // {%\n    StatementClose,      // %}\n    CommentOpen,         // {#\n    CommentClose,        // #}\n    Id,                  // this, this.foo\n    Number,              // 1, 2, -1, 5.2, -5.3\n    String,              // \"this\"\n    Comma,               // ,\n    Colon,               // :\n    LeftParen,           // (\n    RightParen,          // )\n    LeftBracket,         // [\n    RightBracket,        // ]\n    LeftBrace,           // {\n    RightBrace,          // }\n    Equal,               // ==\n    GreaterThan,         // >\n    GreaterEqual,        // >=\n    LessThan,            // <\n    LessEqual,           // <=\n    NotEqual,            // !=\n    Unknown,\n    Eof\n  } kind {Kind::Unknown};\n\n  nonstd::string_view text;\n\n  constexpr Token() = default;\n  constexpr Token(Kind kind, nonstd::string_view text): kind(kind), text(text) {}\n\n  std::string describe() const {\n    switch (kind) {\n      case Kind::Text:\n        return \"<text>\";\n      case Kind::LineStatementClose:\n        return \"<eol>\";\n      case Kind::Eof:\n        return \"<eof>\";\n      default:\n        return static_cast<std::string>(text);\n    }\n  }\n};\n\n}\n\n#endif  // INCLUDE_INJA_TOKEN_HPP_\n"
  },
  {
    "path": "inja/utils.hpp",
    "content": "// Copyright (c) 2019 Pantor. All rights reserved.\n\n#ifndef INCLUDE_INJA_UTILS_HPP_\n#define INCLUDE_INJA_UTILS_HPP_\n\n#include <algorithm>\n#include <fstream>\n#include <stdexcept>\n#include <string>\n#include <utility>\n\n#include \"string_view.hpp\"\n\n\nnamespace inja {\n\ninline void inja_throw(const std::string& type, const std::string& message) {\n  throw std::runtime_error(\"[inja.exception.\" + type + \"] \" + message);\n}\n\ninline std::ifstream open_file_or_throw(const std::string& path) {\n  std::ifstream file;\n  file.exceptions(std::ifstream::failbit | std::ifstream::badbit);\n  try {\n    file.open(path);\n  } catch(const std::ios_base::failure& e) {\n    inja_throw(\"file_error\", \"failed accessing file at '\" + path + \"'\");\n  }\n  return file;\n}\n\nnamespace string_view {\n  inline nonstd::string_view slice(nonstd::string_view view, size_t start, size_t end) {\n    start = std::min(start, view.size());\n    end = std::min(std::max(start, end), view.size());\n    return view.substr(start, end - start);  // StringRef(Data + Start, End - Start);\n  }\n\n  inline std::pair<nonstd::string_view, nonstd::string_view> split(nonstd::string_view view, char Separator) {\n    size_t idx = view.find(Separator);\n    if (idx == nonstd::string_view::npos) {\n      return std::make_pair(view, nonstd::string_view());\n    }\n    return std::make_pair(slice(view, 0, idx), slice(view, idx + 1, nonstd::string_view::npos));\n  }\n\n  inline bool starts_with(nonstd::string_view view, nonstd::string_view prefix) {\n    return (view.size() >= prefix.size() && view.compare(0, prefix.size(), prefix) == 0);\n  }\n}  // namespace string_view\n\n}  // namespace inja\n\n#endif  // INCLUDE_INJA_UTILS_HPP_\n"
  },
  {
    "path": "llhttp/CMakeLists.txt",
    "content": "project(llhttp)\n\naux_source_directory(. LLHTTP_SRC_FILES)\naux_source_directory(helper/ LLHTTP_SRC_FILES)\n\ninclude_directories(.)\ninclude_directories(helper/)\n\nif(_DAQI_TARGET_TYPE_ STREQUAL \"SHARED_LIB\")    \n    add_compile_options(-fPIC)\nendif()\n\nadd_library(${PROJECT_NAME} STATIC ${LLHTTP_SRC_FILES})        \nset_target_properties (${PROJECT_NAME} PROPERTIES DEBUG_POSTFIX _d)\n\n"
  },
  {
    "path": "llhttp/LICENSE-MIT",
    "content": "This software is licensed under the MIT License.\n\nCopyright Fedor Indutny, 2018.\n\nPermission is hereby granted, free of charge, to any person obtaining a\ncopy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to permit\npersons to whom the Software is furnished to do so, subject to the\nfollowing conditions:\n\nThe above copyright notice and this permission notice shall be included\nin all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\nOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\nNO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\nDAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\nOTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\nUSE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "llhttp/README.md",
    "content": "# llhttp\n\n[![Build Status](https://secure.travis-ci.org/nodejs/llhttp.svg)](http://travis-ci.org/nodejs/llhttp)\n\nPort of [http_parser][0] to [llparse][1].\n\n## Why?\n\nLet's face it, [http_parser][0] is practically unmaintainable. Even\nintroduction of a single new method results in a significant code churn.\n\nThis project aims to:\n\n* Make it maintainable\n* Verifiable\n* Improving benchmarks where possible\n\nMore details in [Fedor Indutny's talk at JSConf EU 2019](https://youtu.be/x3k_5Mi66sY)\n\n## How?\n\nOver time, different approaches for improving [http_parser][0]'s code base\nwere tried. However, all of them failed due to resulting significant performance\ndegradation.\n\nThis project is a port of [http_parser][0] to TypeScript. [llparse][1] is used\nto generate the output C and/or bitcode artifacts, which could be compiled and\nlinked with the embedder's program (like [Node.js][7]).\n\n## Performance\n\nSo far llhttp outperforms http_parser:\n\n|                  | input size | bandwidth    | reqs/sec           | time    |\n|:---------------- | ----------:| ------------:| ------------------:| -------:|\n| **llhttp** _(C)_ | 8192.00 mb | 1777.24 mb/s | 3583799.39 ops/sec | 4.61 s  |\n| **http_parser**  | 8192.00 mb | 694.66 mb/s  | 1406180.33 req/sec | 11.79 s |\n\nllhttp is faster by approximately **156%**.\n\n## Maintenance\n\nllhttp project has about 1400 lines of TypeScript code describing the parser\nitself and around 450 lines of C code and headers providing the helper methods.\nThe whole [http_parser][0] is implemented in approximately 2500 lines of C, and\n436 lines of headers.\n\nAll optimizations and multi-character matching in llhttp are generated\nautomatically, and thus doesn't add any extra maintenance cost. On the contrary,\nmost of http_parser's code is hand-optimized and unrolled. Instead describing\n\"how\" it should parse the HTTP requests/responses, a maintainer should\nimplement the new features in [http_parser][0] cautiously, considering\npossible performance degradation and manually optimizing the new code.\n\n## Verification\n\nThe state machine graph is encoded explicitly in llhttp. The [llparse][1]\nautomatically checks the graph for absence of loops and correct reporting of the\ninput ranges (spans) like header names and values. In the future, additional\nchecks could be performed to get even stricter verification of the llhttp.\n\n## Usage\n\n```C\n#include \"llhttp.h\"\n\nllhttp_t parser;\nllhttp_settings_t settings;\n\n/* Initialize user callbacks and settings */\nllhttp_settings_init(&settings);\n\n/* Set user callback */\nsettings.on_message_complete = handle_on_message_complete;\n\n/* Initialize the parser in HTTP_BOTH mode, meaning that it will select between\n * HTTP_REQUEST and HTTP_RESPONSE parsing automatically while reading the first\n * input.\n */\nllhttp_init(&parser, HTTP_BOTH, &settings);\n\n/* Parse request! */\nconst char* request = \"GET / HTTP/1.1\\r\\n\\r\\n\";\nint request_len = strlen(request);\n\nenum llhttp_errno err = llhttp_execute(&parser, request, request_len);\nif (err == HPE_OK) {\n  /* Successfully parsed! */\n} else {\n  fprintf(stderr, \"Parse error: %s %s\\n\", llhttp_errno_name(err),\n          parser.reason);\n}\n```\n\n---\n\n#### LICENSE\n\nThis software is licensed under the MIT License.\n\nCopyright Fedor Indutny, 2018.\n\nPermission is hereby granted, free of charge, to any person obtaining a\ncopy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to permit\npersons to whom the Software is furnished to do so, subject to the\nfollowing conditions:\n\nThe above copyright notice and this permission notice shall be included\nin all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\nOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\nNO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\nDAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\nOTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\nUSE OR OTHER DEALINGS IN THE SOFTWARE.\n\n[0]: https://github.com/nodejs/http-parser\n[1]: https://github.com/nodejs/llparse\n[2]: https://en.wikipedia.org/wiki/Register_allocation#Spilling\n[3]: https://en.wikipedia.org/wiki/Tail_call\n[4]: https://llvm.org/docs/LangRef.html\n[5]: https://llvm.org/docs/LangRef.html#call-instruction\n[6]: https://clang.llvm.org/\n[7]: https://github.com/nodejs/node\n"
  },
  {
    "path": "llhttp/api.c",
    "content": "#include <stdlib.h>\n#include <stdio.h>\n#include <string.h>\n\n#include \"llhttp.h\"\n\n#define CALLBACK_MAYBE(PARSER, NAME, ...)                                     \\\n  do {                                                                        \\\n    llhttp_settings_t* settings;                                              \\\n    settings = (llhttp_settings_t*) (PARSER)->settings;                       \\\n    if (settings == NULL || settings->NAME == NULL) {                         \\\n      err = 0;                                                                \\\n      break;                                                                  \\\n    }                                                                         \\\n    err = settings->NAME(__VA_ARGS__);                                        \\\n  } while (0)\n\nvoid llhttp_init(llhttp_t* parser, llhttp_type_t type,\n                 const llhttp_settings_t* settings) {\n  llhttp__internal_init(parser);\n\n  parser->type = type;\n  parser->settings = (void*) settings;\n}\n\n\nllhttp_errno_t llhttp_execute(llhttp_t* parser, const char* data, size_t len) {\n  return llhttp__internal_execute(parser, data, data + len);\n}\n\n\nvoid llhttp_settings_init(llhttp_settings_t* settings) {\n  memset(settings, 0, sizeof(*settings));\n}\n\n\nllhttp_errno_t llhttp_finish(llhttp_t* parser) {\n  int err;\n\n  /* We're in an error state. Don't bother doing anything. */\n  if (parser->error != 0) {\n    return 0;\n  }\n\n  switch (parser->finish) {\n    case HTTP_FINISH_SAFE_WITH_CB:\n      CALLBACK_MAYBE(parser, on_message_complete, parser);\n      if (err != HPE_OK) return err;\n\n    /* FALLTHROUGH */\n    case HTTP_FINISH_SAFE:\n      return HPE_OK;\n    case HTTP_FINISH_UNSAFE:\n      parser->reason = \"Invalid EOF state\";\n      return HPE_INVALID_EOF_STATE;\n    default:\n      abort();\n  }\n}\n\n\nvoid llhttp_pause(llhttp_t* parser) {\n  if (parser->error != HPE_OK) {\n    return;\n  }\n\n  parser->error = HPE_PAUSED;\n  parser->reason = \"Paused\";\n}\n\n\nvoid llhttp_resume(llhttp_t* parser) {\n  if (parser->error != HPE_PAUSED) {\n    return;\n  }\n\n  parser->error = 0;\n}\n\n\nvoid llhttp_resume_after_upgrade(llhttp_t* parser) {\n  if (parser->error != HPE_PAUSED_UPGRADE) {\n    return;\n  }\n\n  parser->error = 0;\n}\n\n\nllhttp_errno_t llhttp_get_errno(const llhttp_t* parser) {\n  return parser->error;\n}\n\n\nconst char* llhttp_get_error_reason(const llhttp_t* parser) {\n  return parser->reason;\n}\n\n\nvoid llhttp_set_error_reason(llhttp_t* parser, const char* reason) {\n  parser->reason = reason;\n}\n\n\nconst char* llhttp_get_error_pos(const llhttp_t* parser) {\n  return parser->error_pos;\n}\n\n\nconst char* llhttp_errno_name(llhttp_errno_t err) {\n#define HTTP_ERRNO_GEN(CODE, NAME, _) case HPE_##NAME: return \"HPE_\" #NAME;\n  switch (err) {\n    HTTP_ERRNO_MAP(HTTP_ERRNO_GEN)\n    default: abort();\n  }\n#undef HTTP_ERRNO_GEN\n}\n\n\nconst char* llhttp_method_name(llhttp_method_t method) {\n#define HTTP_METHOD_GEN(NUM, NAME, STRING) case HTTP_##NAME: return #STRING;\n  switch (method) {\n    HTTP_METHOD_MAP(HTTP_METHOD_GEN)\n    default: abort();\n  }\n#undef HTTP_METHOD_GEN\n}\n\n\nvoid llhttp_set_lenient(llhttp_t* parser, int enabled) {\n  if (enabled) {\n    parser->flags |= F_LENIENT;\n  } else {\n    parser->flags &= ~F_LENIENT;\n  }\n}\n\n\n/* Callbacks */\n\n\nint llhttp__on_message_begin(llhttp_t* s, const char* p, const char* endp) {\n  int err;\n  CALLBACK_MAYBE(s, on_message_begin, s);\n  return err;\n}\n\n\nint llhttp__on_url(llhttp_t* s, const char* p, const char* endp) {\n  int err;\n  CALLBACK_MAYBE(s, on_url, s, p, endp - p);\n  return err;\n}\n\n\nint llhttp__on_status(llhttp_t* s, const char* p, const char* endp) {\n  int err;\n  CALLBACK_MAYBE(s, on_status, s, p, endp - p);\n  return err;\n}\n\n\nint llhttp__on_header_field(llhttp_t* s, const char* p, const char* endp) {\n  int err;\n  CALLBACK_MAYBE(s, on_header_field, s, p, endp - p);\n  return err;\n}\n\n\nint llhttp__on_header_value(llhttp_t* s, const char* p, const char* endp) {\n  int err;\n  CALLBACK_MAYBE(s, on_header_value, s, p, endp - p);\n  return err;\n}\n\n\nint llhttp__on_headers_complete(llhttp_t* s, const char* p, const char* endp) {\n  int err;\n  CALLBACK_MAYBE(s, on_headers_complete, s);\n  return err;\n}\n\n\nint llhttp__on_message_complete(llhttp_t* s, const char* p, const char* endp) {\n  int err;\n  CALLBACK_MAYBE(s, on_message_complete, s);\n  return err;\n}\n\n\nint llhttp__on_body(llhttp_t* s, const char* p, const char* endp) {\n  int err;\n  CALLBACK_MAYBE(s, on_body, s, p, endp - p);\n  return err;\n}\n\n\nint llhttp__on_chunk_header(llhttp_t* s, const char* p, const char* endp) {\n  int err;\n  CALLBACK_MAYBE(s, on_chunk_header, s);\n  return err;\n}\n\n\nint llhttp__on_chunk_complete(llhttp_t* s, const char* p, const char* endp) {\n  int err;\n  CALLBACK_MAYBE(s, on_chunk_complete, s);\n  return err;\n}\n\n\n/* Private */\n\n\n//void llhttp__debug(llhttp_t* s, const char* p, const char* endp,\n//                   const char* msg) {\n//  if (p == endp) {\n//    fprintf(stderr, \"p=%p type=%d flags=%02x next=null debug=%s\\n\", s, s->type,\n//            s->flags, msg);\n//  } else {\n//    fprintf(stderr, \"p=%p type=%d flags=%02x next=%02x   debug=%s\\n\", s,\n//            s->type, s->flags, *p, msg);\n//  }\n//}\n"
  },
  {
    "path": "llhttp/helper/http_status_def.h",
    "content": "#ifndef HTTP_STATUS_DEF_H\n#define HTTP_STATUS_DEF_H\n\n/* Status Codes */\n#define HTTP_STATUS_MAP(XX)                                                 \\\n    XX(100, CONTINUE,                        Continue)                        \\\n    XX(101, SWITCHING_PROTOCOLS,             Switching Protocols)             \\\n    XX(102, PROCESSING,                      Processing)                      \\\n    XX(200, OK,                              OK)                              \\\n    XX(201, CREATED,                         Created)                         \\\n    XX(202, ACCEPTED,                        Accepted)                        \\\n    XX(203, NON_AUTHORITATIVE_INFORMATION,   Non-Authoritative Information)   \\\n    XX(204, NO_CONTENT,                      No Content)                      \\\n    XX(205, RESET_CONTENT,                   Reset Content)                   \\\n    XX(206, PARTIAL_CONTENT,                 Partial Content)                 \\\n    XX(207, MULTI_STATUS,                    Multi-Status)                    \\\n    XX(208, ALREADY_REPORTED,                Already Reported)                \\\n    XX(226, IM_USED,                         IM Used)                         \\\n    XX(300, MULTIPLE_CHOICES,                Multiple Choices)                \\\n    XX(301, MOVED_PERMANENTLY,               Moved Permanently)               \\\n    XX(302, FOUND,                           Found)                           \\\n    XX(303, SEE_OTHER,                       See Other)                       \\\n    XX(304, NOT_MODIFIED,                    Not Modified)                    \\\n    XX(305, USE_PROXY,                       Use Proxy)                       \\\n    XX(307, TEMPORARY_REDIRECT,              Temporary Redirect)              \\\n    XX(308, PERMANENT_REDIRECT,              Permanent Redirect)              \\\n    XX(400, BAD_REQUEST,                     Bad Request)                     \\\n    XX(401, UNAUTHORIZED,                    Unauthorized)                    \\\n    XX(402, PAYMENT_REQUIRED,                Payment Required)                \\\n    XX(403, FORBIDDEN,                       Forbidden)                       \\\n    XX(404, NOT_FOUND,                       Not Found)                       \\\n    XX(405, METHOD_NOT_ALLOWED,              Method Not Allowed)              \\\n    XX(406, NOT_ACCEPTABLE,                  Not Acceptable)                  \\\n    XX(407, PROXY_AUTHENTICATION_REQUIRED,   Proxy Authentication Required)   \\\n    XX(408, REQUEST_TIMEOUT,                 Request Timeout)                 \\\n    XX(409, CONFLICT,                        Conflict)                        \\\n    XX(410, GONE,                            Gone)                            \\\n    XX(411, LENGTH_REQUIRED,                 Length Required)                 \\\n    XX(412, PRECONDITION_FAILED,             Precondition Failed)             \\\n    XX(413, PAYLOAD_TOO_LARGE,               Payload Too Large)               \\\n    XX(414, URI_TOO_LONG,                    URI Too Long)                    \\\n    XX(415, UNSUPPORTED_MEDIA_TYPE,          Unsupported Media Type)          \\\n    XX(416, RANGE_NOT_SATISFIABLE,           Range Not Satisfiable)           \\\n    XX(417, EXPECTATION_FAILED,              Expectation Failed)              \\\n    XX(421, MISDIRECTED_REQUEST,             Misdirected Request)             \\\n    XX(422, UNPROCESSABLE_ENTITY,            Unprocessable Entity)            \\\n    XX(423, LOCKED,                          Locked)                          \\\n    XX(424, FAILED_DEPENDENCY,               Failed Dependency)               \\\n    XX(426, UPGRADE_REQUIRED,                Upgrade Required)                \\\n    XX(428, PRECONDITION_REQUIRED,           Precondition Required)           \\\n    XX(429, TOO_MANY_REQUESTS,               Too Many Requests)               \\\n    XX(431, REQUEST_HEADER_FIELDS_TOO_LARGE, Request Header Fields Too Large) \\\n    XX(451, UNAVAILABLE_FOR_LEGAL_REASONS,   Unavailable For Legal Reasons)   \\\n    XX(500, INTERNAL_SERVER_ERROR,           Internal Server Error)           \\\n    XX(501, NOT_IMPLEMENTED,                 Not Implemented)                 \\\n    XX(502, BAD_GATEWAY,                     Bad Gateway)                     \\\n    XX(503, SERVICE_UNAVAILABLE,             Service Unavailable)             \\\n    XX(504, GATEWAY_TIMEOUT,                 Gateway Timeout)                 \\\n    XX(505, HTTP_VERSION_NOT_SUPPORTED,      HTTP Version Not Supported)      \\\n    XX(506, VARIANT_ALSO_NEGOTIATES,         Variant Also Negotiates)         \\\n    XX(507, INSUFFICIENT_STORAGE,            Insufficient Storage)            \\\n    XX(508, LOOP_DETECTED,                   Loop Detected)                   \\\n    XX(510, NOT_EXTENDED,                    Not Extended)                    \\\n    XX(511, NETWORK_AUTHENTICATION_REQUIRED, Network Authentication Required) \\\n\nenum http_status\n{\n#define XX(num, name, string) HTTP_STATUS_##name = num,\n    HTTP_STATUS_MAP(XX)\n#undef XX\n};\n\n#endif // HTTP_STATUS_DEF_H\n"
  },
  {
    "path": "llhttp/helper/http_url_def.c",
    "content": "#include \"http_url_def.h\"\n\n#include <assert.h>\n#include <stddef.h>\n#include <ctype.h>\n#include <string.h>\n#include <limits.h>\n#include <inttypes.h>\n\n#define HTTP_PARSER_STRICT 0\n\n#if HTTP_PARSER_STRICT\n# define T(v) 0\n#else\n# define T(v) v\n#endif\n\n\nstatic const uint8_t normal_url_char[32] = {\n    /*   0 nul    1 soh    2 stx    3 etx    4 eot    5 enq    6 ack    7 bel  */\n    0    |   0    |   0    |   0    |   0    |   0    |   0    |   0,\n    /*   8 bs     9 ht    10 nl    11 vt    12 np    13 cr    14 so    15 si   */\n    0    | T(2)   |   0    |   0    | T(16)  |   0    |   0    |   0,\n    /*  16 dle   17 dc1   18 dc2   19 dc3   20 dc4   21 nak   22 syn   23 etb */\n    0    |   0    |   0    |   0    |   0    |   0    |   0    |   0,\n    /*  24 can   25 em    26 sub   27 esc   28 fs    29 gs    30 rs    31 us  */\n    0    |   0    |   0    |   0    |   0    |   0    |   0    |   0,\n    /*  32 sp    33  !    34  \"    35  #    36  $    37  %    38  &    39  '  */\n    0    |   2    |   4    |   0    |   16   |   32   |   64   |  128,\n    /*  40  (    41  )    42  *    43  +    44  ,    45  -    46  .    47  /  */\n    1    |   2    |   4    |   8    |   16   |   32   |   64   |  128,\n    /*  48  0    49  1    50  2    51  3    52  4    53  5    54  6    55  7  */\n    1    |   2    |   4    |   8    |   16   |   32   |   64   |  128,\n    /*  56  8    57  9    58  :    59  ;    60  <    61  =    62  >    63  ?  */\n    1    |   2    |   4    |   8    |   16   |   32   |   64   |   0,\n    /*  64  @    65  A    66  B    67  C    68  D    69  E    70  F    71  G  */\n    1    |   2    |   4    |   8    |   16   |   32   |   64   |  128,\n    /*  72  H    73  I    74  J    75  K    76  L    77  M    78  N    79  O  */\n    1    |   2    |   4    |   8    |   16   |   32   |   64   |  128,\n    /*  80  P    81  Q    82  R    83  S    84  T    85  U    86  V    87  W  */\n    1    |   2    |   4    |   8    |   16   |   32   |   64   |  128,\n    /*  88  X    89  Y    90  Z    91  [    92  \\    93  ]    94  ^    95  _  */\n    1    |   2    |   4    |   8    |   16   |   32   |   64   |  128,\n    /*  96  `    97  a    98  b    99  c   100  d   101  e   102  f   103  g  */\n    1    |   2    |   4    |   8    |   16   |   32   |   64   |  128,\n    /* 104  h   105  i   106  j   107  k   108  l   109  m   110  n   111  o  */\n    1    |   2    |   4    |   8    |   16   |   32   |   64   |  128,\n    /* 112  p   113  q   114  r   115  s   116  t   117  u   118  v   119  w  */\n    1    |   2    |   4    |   8    |   16   |   32   |   64   |  128,\n    /* 120  x   121  y   122  z   123  {   124  |   125  }   126  ~   127 del */\n    1    |   2    |   4    |   8    |   16   |   32   |   64   |   0, };\n\n#undef T\n\n#ifndef BIT_AT\n# define BIT_AT(a, i)                                                \\\n  (!!((unsigned int) (a)[(unsigned int) (i) >> 3] &                  \\\n   (1 << ((unsigned int) (i) & 7))))\n#endif\n\n/* Macros for character classes; depends on strict-mode  */\n#define CR                  '\\r'\n#define LF                  '\\n'\n#define LOWER(c)            (unsigned char)(c | 0x20)\n#define IS_ALPHA(c)         (LOWER(c) >= 'a' && LOWER(c) <= 'z')\n#define IS_NUM(c)           ((c) >= '0' && (c) <= '9')\n#define IS_ALPHANUM(c)      (IS_ALPHA(c) || IS_NUM(c))\n#define IS_HEX(c)           (IS_NUM(c) || (LOWER(c) >= 'a' && LOWER(c) <= 'f'))\n#define IS_MARK(c)          ((c) == '-' || (c) == '_' || (c) == '.' || \\\n  (c) == '!' || (c) == '~' || (c) == '*' || (c) == '\\'' || (c) == '(' || \\\n  (c) == ')')\n#define IS_USERINFO_CHAR(c) (IS_ALPHANUM(c) || IS_MARK(c) || (c) == '%' || \\\n  (c) == ';' || (c) == ':' || (c) == '&' || (c) == '=' || (c) == '+' || \\\n  (c) == '$' || (c) == ',')\n\n#if HTTP_PARSER_STRICT\n#define TOKEN(c)            STRICT_TOKEN(c)\n#define IS_URL_CHAR(c)      (BIT_AT(normal_url_char, (unsigned char)c))\n#define IS_HOST_CHAR(c)     (IS_ALPHANUM(c) || (c) == '.' || (c) == '-')\n#else\n#define TOKEN(c)            tokens[(unsigned char)c]\n#define IS_URL_CHAR(c)                                                         \\\n  (BIT_AT(normal_url_char, (unsigned char)c) || ((c) & 0x80))\n#define IS_HOST_CHAR(c)                                                        \\\n  (IS_ALPHANUM(c) || (c) == '.' || (c) == '-' || (c) == '_')\n#endif\n\n\nenum http_host_state\n{\n    s_http_host_dead = 1\n    , s_http_userinfo_start\n    , s_http_userinfo\n    , s_http_host_start\n    , s_http_host_v6_start\n    , s_http_host\n    , s_http_host_v6\n    , s_http_host_v6_end\n    , s_http_host_v6_zone_start\n    , s_http_host_v6_zone\n    , s_http_host_port_start\n    , s_http_host_port\n};\n\n\nenum state\n{ s_dead = 1 /* important that this is > 0 */\n  \n  , s_start_req_or_res\n  , s_res_or_resp_H\n  , s_start_res\n  , s_res_H\n  , s_res_HT\n  , s_res_HTT\n  , s_res_HTTP\n  , s_res_http_major\n  , s_res_http_dot\n  , s_res_http_minor\n  , s_res_http_end\n  , s_res_first_status_code\n  , s_res_status_code\n  , s_res_status_start\n  , s_res_status\n  , s_res_line_almost_done\n  \n  , s_start_req\n  \n  , s_req_method\n  , s_req_spaces_before_url\n  , s_req_schema\n  , s_req_schema_slash\n  , s_req_schema_slash_slash\n  , s_req_server_start\n  , s_req_server\n  , s_req_server_with_at\n  , s_req_path\n  , s_req_query_string_start\n  , s_req_query_string\n  , s_req_fragment_start\n  , s_req_fragment\n  , s_req_http_start\n  , s_req_http_H\n  , s_req_http_HT\n  , s_req_http_HTT\n  , s_req_http_HTTP\n  , s_req_http_major\n  , s_req_http_dot\n  , s_req_http_minor\n  , s_req_http_end\n  , s_req_line_almost_done\n  \n  , s_header_field_start\n  , s_header_field\n  , s_header_value_discard_ws\n  , s_header_value_discard_ws_almost_done\n  , s_header_value_discard_lws\n  , s_header_value_start\n  , s_header_value\n  , s_header_value_lws\n  \n  , s_header_almost_done\n  \n  , s_chunk_size_start\n  , s_chunk_size\n  , s_chunk_parameters\n  , s_chunk_size_almost_done\n  \n  , s_headers_almost_done\n  , s_headers_done\n  \n  /* Important: 's_headers_done' must be the last 'header' state. All\n   * states beyond this must be 'body' states. It is used for overflow\n   * checking. See the PARSING_HEADER() macro.\n   */\n  \n  , s_chunk_data\n  , s_chunk_data_almost_done\n  , s_chunk_data_done\n  \n  , s_body_identity\n  , s_body_identity_eof\n  \n  , s_message_done\n};\n\n#define PARSING_HEADER(state) (state <= s_headers_done)\n\nstatic enum http_host_state\nhttp_parse_host_char(enum http_host_state s, const char ch) {\n    switch(s) {\n    case s_http_userinfo:\n    case s_http_userinfo_start:\n        if (ch == '@') {\n            return s_http_host_start;\n        }\n        \n        if (IS_USERINFO_CHAR(ch)) {\n            return s_http_userinfo;\n        }\n        break;\n        \n    case s_http_host_start:\n        if (ch == '[') {\n            return s_http_host_v6_start;\n        }\n        \n        if (IS_HOST_CHAR(ch)) {\n            return s_http_host;\n        }\n        \n        break;\n        \n    case s_http_host:\n        if (IS_HOST_CHAR(ch)) {\n            return s_http_host;\n        }\n        \n    /* fall through */\n    case s_http_host_v6_end:\n        if (ch == ':') {\n            return s_http_host_port_start;\n        }\n        \n        break;\n        \n    case s_http_host_v6:\n        if (ch == ']') {\n            return s_http_host_v6_end;\n        }\n        \n    /* fall through */\n    case s_http_host_v6_start:\n        if (IS_HEX(ch) || ch == ':' || ch == '.') {\n            return s_http_host_v6;\n        }\n        \n        if (s == s_http_host_v6 && ch == '%') {\n            return s_http_host_v6_zone_start;\n        }\n        break;\n        \n    case s_http_host_v6_zone:\n        if (ch == ']') {\n            return s_http_host_v6_end;\n        }\n        \n    /* fall through */\n    case s_http_host_v6_zone_start:\n        /* RFC 6874 Zone ID consists of 1*( unreserved / pct-encoded) */\n        if (IS_ALPHANUM(ch) || ch == '%' || ch == '.' || ch == '-' || ch == '_' ||\n            ch == '~') {\n            return s_http_host_v6_zone;\n        }\n        break;\n        \n    case s_http_host_port:\n    case s_http_host_port_start:\n        if (IS_NUM(ch)) {\n            return s_http_host_port;\n        }\n        \n        break;\n        \n    default:\n        break;\n    }\n    return s_http_host_dead;\n}\n\nstatic int\nhttp_parse_host(const char * buf, struct http_parser_url *u, int found_at) {\n    enum http_host_state s;\n    \n    const char *p;\n    size_t buflen = u->field_data[UF_HOST].off + u->field_data[UF_HOST].len;\n    \n    assert(u->field_set & (1 << UF_HOST));\n    \n    u->field_data[UF_HOST].len = 0;\n    \n    s = found_at ? s_http_userinfo_start : s_http_host_start;\n    \n    for (p = buf + u->field_data[UF_HOST].off; p < buf + buflen; p++) {\n        enum http_host_state new_s = http_parse_host_char(s, *p);\n        \n        if (new_s == s_http_host_dead) {\n            return 1;\n        }\n        \n        switch(new_s) {\n        case s_http_host:\n            if (s != s_http_host) {\n                u->field_data[UF_HOST].off = (uint16_t)(p - buf);\n            }\n            u->field_data[UF_HOST].len++;\n            break;\n            \n        case s_http_host_v6:\n            if (s != s_http_host_v6) {\n                u->field_data[UF_HOST].off = (uint16_t)(p - buf);\n            }\n            u->field_data[UF_HOST].len++;\n            break;\n            \n        case s_http_host_v6_zone_start:\n        case s_http_host_v6_zone:\n            u->field_data[UF_HOST].len++;\n            break;\n            \n        case s_http_host_port:\n            if (s != s_http_host_port) {\n                u->field_data[UF_PORT].off = (uint16_t)(p - buf);\n                u->field_data[UF_PORT].len = 0;\n                u->field_set |= (1 << UF_PORT);\n            }\n            u->field_data[UF_PORT].len++;\n            break;\n            \n        case s_http_userinfo:\n            if (s != s_http_userinfo) {\n                u->field_data[UF_USERINFO].off = (uint16_t)(p - buf);\n                u->field_data[UF_USERINFO].len = 0;\n                u->field_set |= (1 << UF_USERINFO);\n            }\n            u->field_data[UF_USERINFO].len++;\n            break;\n            \n        default:\n            break;\n        }\n        s = new_s;\n    }\n    \n    /* Make sure we don't end somewhere unexpected */\n    switch (s) {\n    case s_http_host_start:\n    case s_http_host_v6_start:\n    case s_http_host_v6:\n    case s_http_host_v6_zone_start:\n    case s_http_host_v6_zone:\n    case s_http_host_port_start:\n    case s_http_userinfo:\n    case s_http_userinfo_start:\n        return 1;\n    default:\n        break;\n    }\n    \n    return 0;\n}\n\n/* Our URL parser.\n *\n * This is designed to be shared by http_parser_execute() for URL validation,\n * hence it has a state transition + byte-for-byte interface. In addition, it\n * is meant to be embedded in http_parser_parse_url(), which does the dirty\n * work of turning state transitions URL components for its API.\n *\n * This function should only be invoked with non-space characters. It is\n * assumed that the caller cares about (and can detect) the transition between\n * URL and non-URL states by looking for these.\n */\nstatic enum state\nparse_url_char(enum state s, const char ch)\n{\n    if (ch == ' ' || ch == '\\r' || ch == '\\n') {\n        return s_dead;\n    }\n\n#if HTTP_PARSER_STRICT\n    if (ch == '\\t' || ch == '\\f') {\n        return s_dead;\n    }\n#endif\n    \n    switch (s) {\n    case s_req_spaces_before_url:\n        /* Proxied requests are followed by scheme of an absolute URI (alpha).\n       * All methods except CONNECT are followed by '/' or '*'.\n       */\n        \n        if (ch == '/' || ch == '*') {\n            return s_req_path;\n        }\n        \n        if (IS_ALPHA(ch)) {\n            return s_req_schema;\n        }\n        \n        break;\n        \n    case s_req_schema:\n        if (IS_ALPHA(ch)) {\n            return s;\n        }\n        \n        if (ch == ':') {\n            return s_req_schema_slash;\n        }\n        \n        break;\n        \n    case s_req_schema_slash:\n        if (ch == '/') {\n            return s_req_schema_slash_slash;\n        }\n        \n        break;\n        \n    case s_req_schema_slash_slash:\n        if (ch == '/') {\n            return s_req_server_start;\n        }\n        \n        break;\n        \n    case s_req_server_with_at:\n        if (ch == '@') {\n            return s_dead;\n        }\n        \n    /* fall through */\n    case s_req_server_start:\n    case s_req_server:\n        if (ch == '/') {\n            return s_req_path;\n        }\n        \n        if (ch == '?') {\n            return s_req_query_string_start;\n        }\n        \n        if (ch == '@') {\n            return s_req_server_with_at;\n        }\n        \n        if (IS_USERINFO_CHAR(ch) || ch == '[' || ch == ']') {\n            return s_req_server;\n        }\n        \n        break;\n        \n    case s_req_path:\n        if (IS_URL_CHAR(ch)) {\n            return s;\n        }\n        \n        switch (ch) {\n        case '?':\n            return s_req_query_string_start;\n            \n        case '#':\n            return s_req_fragment_start;\n        }\n        \n        break;\n        \n    case s_req_query_string_start:\n    case s_req_query_string:\n        if (IS_URL_CHAR(ch)) {\n            return s_req_query_string;\n        }\n        \n        switch (ch) {\n        case '?':\n            /* allow extra '?' in query string */\n            return s_req_query_string;\n            \n        case '#':\n            return s_req_fragment_start;\n        }\n        \n        break;\n        \n    case s_req_fragment_start:\n        if (IS_URL_CHAR(ch)) {\n            return s_req_fragment;\n        }\n        \n        switch (ch) {\n        case '?':\n            return s_req_fragment;\n            \n        case '#':\n            return s;\n        }\n        \n        break;\n        \n    case s_req_fragment:\n        if (IS_URL_CHAR(ch)) {\n            return s;\n        }\n        \n        switch (ch) {\n        case '?':\n        case '#':\n            return s;\n        }\n        \n        break;\n        \n    default:\n        break;\n    }\n    \n    /* We should never fall out of the switch above unless there's an error */\n    return s_dead;\n}\n\nvoid\nhttp_parser_url_init(struct http_parser_url *u) {\n    memset(u, 0, sizeof(*u));\n}\n\n\nint\nhttp_parser_parse_url(const char *buf, size_t buflen, int is_connect,\n                      struct http_parser_url *u)\n{\n    enum state s;\n    const char *p;\n    enum http_parser_url_fields uf, old_uf;\n    int found_at = 0;\n    \n    if (buflen == 0) {\n        return 1;\n    }\n    \n    u->port = u->field_set = 0;\n    s = is_connect ? s_req_server_start : s_req_spaces_before_url;\n    old_uf = UF_MAX;\n    \n    for (p = buf; p < buf + buflen; p++) {\n        s = parse_url_char(s, *p);\n        \n        /* Figure out the next field that we're operating on */\n        switch (s) {\n        case s_dead:\n            return 1;\n            \n        /* Skip delimeters */\n        case s_req_schema_slash:\n        case s_req_schema_slash_slash:\n        case s_req_server_start:\n        case s_req_query_string_start:\n        case s_req_fragment_start:\n            continue;\n            \n        case s_req_schema:\n            uf = UF_SCHEMA;\n            break;\n            \n        case s_req_server_with_at:\n            found_at = 1;\n            \n        /* fall through */\n        case s_req_server:\n            uf = UF_HOST;\n            break;\n            \n        case s_req_path:\n            uf = UF_PATH;\n            break;\n            \n        case s_req_query_string:\n            uf = UF_QUERY;\n            break;\n            \n        case s_req_fragment:\n            uf = UF_FRAGMENT;\n            break;\n            \n        default:\n            assert(0 && \"Unexpected state\");\n            return 1;\n        }\n        \n        /* Nothing's changed; soldier on */\n        if (uf == old_uf) {\n            u->field_data[uf].len++;\n            continue;\n        }\n        \n        u->field_data[uf].off = (uint16_t)(p - buf);\n        u->field_data[uf].len = 1;\n        \n        u->field_set |= (1 << uf);\n        old_uf = uf;\n    }\n    \n    /* host must be present if there is a schema */\n    /* parsing http:///toto will fail */\n    if ((u->field_set & (1 << UF_SCHEMA)) &&\n        (u->field_set & (1 << UF_HOST)) == 0) {\n        return 1;\n    }\n    \n    if (u->field_set & (1 << UF_HOST)) {\n        if (http_parse_host(buf, u, found_at) != 0) {\n            return 1;\n        }\n    }\n    \n    /* CONNECT requests can only contain \"hostname:port\" */\n    if (is_connect && u->field_set != ((1 << UF_HOST)|(1 << UF_PORT))) {\n        return 1;\n    }\n    \n    if (u->field_set & (1 << UF_PORT)) {\n        uint16_t off;\n        uint16_t len;\n        const char* p;\n        const char* end;\n        unsigned long v;\n        \n        off = u->field_data[UF_PORT].off;\n        len = u->field_data[UF_PORT].len;\n        end = buf + off + len;\n        \n        /* NOTE: The characters are already validated and are in the [0-9] range */\n        assert(off + len <= buflen && \"Port number overflow\");\n        v = 0;\n        for (p = buf + off; p < end; p++) {\n            v *= 10;\n            v += (unsigned long)(*p - '0');\n            \n            /* Ports have a max value of 2^16 */\n            if (v > 0xffff) {\n                return 1;\n            }\n        }\n        \n        u->port = (uint16_t) v;\n    }\n    \n    return 0;\n}\n"
  },
  {
    "path": "llhttp/helper/http_url_def.h",
    "content": "#ifndef HTTP_URL_DEF_H\n#define HTTP_URL_DEF_H\n\n#include <stddef.h>\n#include <inttypes.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nenum http_parser_url_fields\n{\n    UF_SCHEMA           = 0\n    , UF_HOST             = 1\n    , UF_PORT             = 2\n    , UF_PATH             = 3\n    , UF_QUERY            = 4\n    , UF_FRAGMENT         = 5\n    , UF_USERINFO         = 6\n    , UF_MAX              = 7\n};\n\n/* Result structure for http_parser_parse_url().\n *\n * Callers should index into field_data[] with UF_* values iff field_set\n * has the relevant (1 << UF_*) bit set. As a courtesy to clients (and\n * because we probably have padding left over), we convert any port to\n * a uint16_t.\n */\nstruct http_parser_url\n{\n    uint16_t field_set;           /* Bitmask of (1 << UF_*) values */\n    uint16_t port;                /* Converted UF_PORT string */\n\n    struct\n    {\n        uint16_t off;               /* Offset into buffer in which field starts */\n        uint16_t len;               /* Length of run in buffer */\n    } field_data[UF_MAX];\n};\n\n/* Initialize all http_parser_url members to 0 */\nvoid http_parser_url_init(struct http_parser_url* u);\n\n/* Parse a URL; return nonzero on failure */\nint http_parser_parse_url(const char* buf, size_t buflen,\n                          int is_connect,\n                          struct http_parser_url* u);\n#ifdef __cplusplus\n}  /* extern \"C\" */\n#endif\n\n#endif // HTTP_URL_DEF_H\n"
  },
  {
    "path": "llhttp/http.c",
    "content": "#include <stdio.h>\n#ifndef LLHTTP__TEST\n# include \"llhttp.h\"\n#else\n# define llhttp_t llparse_t\n#endif  /* */\n\nint llhttp_message_needs_eof(const llhttp_t* parser);\nint llhttp_should_keep_alive(const llhttp_t* parser);\n\nint llhttp__before_headers_complete(llhttp_t* parser, const char* p,\n                                    const char* endp) {\n  /* Set this here so that on_headers_complete() callbacks can see it */\n  if ((parser->flags & F_UPGRADE) &&\n      (parser->flags & F_CONNECTION_UPGRADE)) {\n    /* For responses, \"Upgrade: foo\" and \"Connection: upgrade\" are\n     * mandatory only when it is a 101 Switching Protocols response,\n     * otherwise it is purely informational, to announce support.\n     */\n    parser->upgrade =\n        (parser->type == HTTP_REQUEST || parser->status_code == 101);\n  } else {\n    parser->upgrade = (parser->method == HTTP_CONNECT);\n  }\n  return 0;\n}\n\n\n/* Return values:\n * 0 - No body, `restart`, message_complete\n * 1 - CONNECT request, `restart`, message_complete, and pause\n * 2 - chunk_size_start\n * 3 - body_identity\n * 4 - body_identity_eof\n */\nint llhttp__after_headers_complete(llhttp_t* parser, const char* p,\n                                   const char* endp) {\n  int hasBody;\n\n  hasBody = parser->flags & F_CHUNKED || parser->content_length > 0;\n  if (parser->upgrade && (parser->method == HTTP_CONNECT ||\n                          (parser->flags & F_SKIPBODY) || !hasBody)) {\n    /* Exit, the rest of the message is in a different protocol. */\n    return 1;\n  }\n\n  if (parser->flags & F_SKIPBODY) {\n    return 0;\n  } else if (parser->flags & F_CHUNKED) {\n    /* chunked encoding - ignore Content-Length header */\n    return 2;\n  } else {\n    if (!(parser->flags & F_CONTENT_LENGTH)) {\n      if (!llhttp_message_needs_eof(parser)) {\n        /* Assume content-length 0 - read the next */\n        return 0;\n      } else {\n        /* Read body until EOF */\n        return 4;\n      }\n    } else if (parser->content_length == 0) {\n      /* Content-Length header given but zero: Content-Length: 0\\r\\n */\n      return 0;\n    } else {\n      /* Content-Length header given and non-zero */\n      return 3;\n    }\n  }\n}\n\n\nint llhttp__after_message_complete(llhttp_t* parser, const char* p,\n                                   const char* endp) {\n  int should_keep_alive;\n\n  should_keep_alive = llhttp_should_keep_alive(parser);\n  parser->finish = HTTP_FINISH_SAFE;\n\n  /* Keep `F_LENIENT` flag between messages, but reset every other flag */\n  parser->flags &= F_LENIENT;\n\n  /* NOTE: this is ignored in loose parsing mode */\n  return should_keep_alive;\n}\n\n\nint llhttp_message_needs_eof(const llhttp_t* parser) {\n  if (parser->type == HTTP_REQUEST) {\n    return 0;\n  }\n\n  /* See RFC 2616 section 4.4 */\n  if (parser->status_code / 100 == 1 || /* 1xx e.g. Continue */\n      parser->status_code == 204 ||     /* No Content */\n      parser->status_code == 304 ||     /* Not Modified */\n      (parser->flags & F_SKIPBODY)) {     /* response to a HEAD request */\n    return 0;\n  }\n\n  if (parser->flags & (F_CHUNKED | F_CONTENT_LENGTH)) {\n    return 0;\n  }\n\n  return 1;\n}\n\n\nint llhttp_should_keep_alive(const llhttp_t* parser) {\n  if (parser->http_major > 0 && parser->http_minor > 0) {\n    /* HTTP/1.1 */\n    if (parser->flags & F_CONNECTION_CLOSE) {\n      return 0;\n    }\n  } else {\n    /* HTTP/1.0 or earlier */\n    if (!(parser->flags & F_CONNECTION_KEEP_ALIVE)) {\n      return 0;\n    }\n  }\n\n  return !llhttp_message_needs_eof(parser);\n}\n"
  },
  {
    "path": "llhttp/llhttp.c",
    "content": "#include <stdlib.h>\n#include <stdint.h>\n#include <string.h>\n\n#ifdef __SSE4_2__\n #ifdef _MSC_VER\n  #include <nmmintrin.h>\n #else  /* !_MSC_VER */\n  #include <x86intrin.h>\n #endif  /* _MSC_VER */\n#endif  /* __SSE4_2__ */\n\n#ifdef _MSC_VER\n #define ALIGN(n) _declspec(align(n))\n#else  /* !_MSC_VER */\n #define ALIGN(n) __attribute__((aligned(n)))\n#endif  /* _MSC_VER */\n\n#include \"llhttp.h\"\n\ntypedef int (*llhttp__internal__span_cb)(\n             llhttp__internal_t*, const char*, const char*);\n\nstatic const unsigned char llparse_blob0[] = {\n  'C', 'L'\n};\nstatic const unsigned char ALIGN(16) llparse_blob1[] = {\n  0x9, 0x9, 0xc, 0xc, '!', '\"', '$', '>', '@', '~', 0x80,\n  0xff\n};\nstatic const unsigned char llparse_blob2[] = {\n  'o', 'n'\n};\nstatic const unsigned char llparse_blob3[] = {\n  'e', 'c', 't', 'i', 'o', 'n'\n};\nstatic const unsigned char llparse_blob4[] = {\n  'l', 'o', 's', 'e'\n};\nstatic const unsigned char llparse_blob5[] = {\n  'e', 'e', 'p', '-', 'a', 'l', 'i', 'v', 'e'\n};\nstatic const unsigned char llparse_blob6[] = {\n  'p', 'g', 'r', 'a', 'd', 'e'\n};\nstatic const unsigned char ALIGN(16) llparse_blob7[] = {\n  0x9, 0x9, ' ', '~', 0x80, 0xfe\n};\nstatic const unsigned char llparse_blob8[] = {\n  'h', 'u', 'n', 'k', 'e', 'd'\n};\nstatic const unsigned char ALIGN(16) llparse_blob9[] = {\n  ' ', '!', '#', '\\'', '*', '+', '-', '.', '0', '9', 'A',\n  'Z', '^', 'z', '|', '|'\n};\nstatic const unsigned char ALIGN(16) llparse_blob10[] = {\n  '~', '~'\n};\nstatic const unsigned char llparse_blob11[] = {\n  'e', 'n', 't', '-', 'l', 'e', 'n', 'g', 't', 'h'\n};\nstatic const unsigned char llparse_blob12[] = {\n  'r', 'o', 'x', 'y', '-', 'c', 'o', 'n', 'n', 'e', 'c',\n  't', 'i', 'o', 'n'\n};\nstatic const unsigned char llparse_blob13[] = {\n  'r', 'a', 'n', 's', 'f', 'e', 'r', '-', 'e', 'n', 'c',\n  'o', 'd', 'i', 'n', 'g'\n};\nstatic const unsigned char llparse_blob14[] = {\n  'p', 'g', 'r', 'a', 'd', 'e'\n};\nstatic const unsigned char llparse_blob15[] = {\n  0xd, 0xa\n};\nstatic const unsigned char llparse_blob16[] = {\n  'T', 'T', 'P', '/'\n};\nstatic const unsigned char llparse_blob17[] = {\n  'C', 'E', '/'\n};\nstatic const unsigned char llparse_blob18[] = {\n  'I', 'N', 'D'\n};\nstatic const unsigned char llparse_blob19[] = {\n  'E', 'C', 'K', 'O', 'U', 'T'\n};\nstatic const unsigned char llparse_blob20[] = {\n  'N', 'E', 'C', 'T'\n};\nstatic const unsigned char llparse_blob21[] = {\n  'E', 'L', 'E', 'T', 'E'\n};\nstatic const unsigned char llparse_blob22[] = {\n  'E', 'T'\n};\nstatic const unsigned char llparse_blob23[] = {\n  'E', 'A', 'D'\n};\nstatic const unsigned char llparse_blob24[] = {\n  'N', 'K'\n};\nstatic const unsigned char llparse_blob25[] = {\n  'C', 'K'\n};\nstatic const unsigned char llparse_blob26[] = {\n  'S', 'E', 'A', 'R', 'C', 'H'\n};\nstatic const unsigned char llparse_blob27[] = {\n  'R', 'G', 'E'\n};\nstatic const unsigned char llparse_blob28[] = {\n  'C', 'T', 'I', 'V', 'I', 'T', 'Y'\n};\nstatic const unsigned char llparse_blob29[] = {\n  'L', 'E', 'N', 'D', 'A', 'R'\n};\nstatic const unsigned char llparse_blob30[] = {\n  'V', 'E'\n};\nstatic const unsigned char llparse_blob31[] = {\n  'O', 'T', 'I', 'F', 'Y'\n};\nstatic const unsigned char llparse_blob32[] = {\n  'P', 'T', 'I', 'O', 'N', 'S'\n};\nstatic const unsigned char llparse_blob33[] = {\n  'T', 'C', 'H'\n};\nstatic const unsigned char llparse_blob34[] = {\n  'S', 'T'\n};\nstatic const unsigned char llparse_blob35[] = {\n  'O', 'P'\n};\nstatic const unsigned char llparse_blob36[] = {\n  'I', 'N', 'D'\n};\nstatic const unsigned char llparse_blob37[] = {\n  'A', 'T', 'C', 'H'\n};\nstatic const unsigned char llparse_blob38[] = {\n  'G', 'E'\n};\nstatic const unsigned char llparse_blob39[] = {\n  'I', 'N', 'D'\n};\nstatic const unsigned char llparse_blob40[] = {\n  'O', 'R', 'T'\n};\nstatic const unsigned char llparse_blob41[] = {\n  'A', 'R', 'C', 'H'\n};\nstatic const unsigned char llparse_blob42[] = {\n  'U', 'R', 'C', 'E'\n};\nstatic const unsigned char llparse_blob43[] = {\n  'B', 'S', 'C', 'R', 'I', 'B', 'E'\n};\nstatic const unsigned char llparse_blob44[] = {\n  'R', 'A', 'C', 'E'\n};\nstatic const unsigned char llparse_blob45[] = {\n  'I', 'N', 'D'\n};\nstatic const unsigned char llparse_blob46[] = {\n  'N', 'K'\n};\nstatic const unsigned char llparse_blob47[] = {\n  'C', 'K'\n};\nstatic const unsigned char llparse_blob48[] = {\n  'U', 'B', 'S', 'C', 'R', 'I', 'B', 'E'\n};\nstatic const unsigned char llparse_blob49[] = {\n  'H', 'T', 'T', 'P', '/'\n};\nstatic const unsigned char llparse_blob50[] = {\n  'A', 'D'\n};\nstatic const unsigned char llparse_blob51[] = {\n  'T', 'P', '/'\n};\n\nenum llparse_match_status_e {\n  kMatchComplete,\n  kMatchPause,\n  kMatchMismatch\n};\ntypedef enum llparse_match_status_e llparse_match_status_t;\n\nstruct llparse_match_s {\n  llparse_match_status_t status;\n  const unsigned char* current;\n};\ntypedef struct llparse_match_s llparse_match_t;\n\nstatic llparse_match_t llparse__match_sequence_id(\n    llhttp__internal_t* s, const unsigned char* p,\n    const unsigned char* endp,\n    const unsigned char* seq, uint32_t seq_len) {\n  uint32_t index;\n  llparse_match_t res;\n\n  index = s->_index;\n  for (; p != endp; p++) {\n    unsigned char current;\n\n    current = *p;\n    if (current == seq[index]) {\n      if (++index == seq_len) {\n        res.status = kMatchComplete;\n        goto reset;\n      }\n    } else {\n      res.status = kMatchMismatch;\n      goto reset;\n    }\n  }\n  s->_index = index;\n  res.status = kMatchPause;\n  res.current = p;\n  return res;\nreset:\n  s->_index = 0;\n  res.current = p;\n  return res;\n}\n\nstatic llparse_match_t llparse__match_sequence_to_lower_unsafe(\n    llhttp__internal_t* s, const unsigned char* p,\n    const unsigned char* endp,\n    const unsigned char* seq, uint32_t seq_len) {\n  uint32_t index;\n  llparse_match_t res;\n\n  index = s->_index;\n  for (; p != endp; p++) {\n    unsigned char current;\n\n    current = ((*p) | 0x20);\n    if (current == seq[index]) {\n      if (++index == seq_len) {\n        res.status = kMatchComplete;\n        goto reset;\n      }\n    } else {\n      res.status = kMatchMismatch;\n      goto reset;\n    }\n  }\n  s->_index = index;\n  res.status = kMatchPause;\n  res.current = p;\n  return res;\nreset:\n  s->_index = 0;\n  res.current = p;\n  return res;\n}\n\nenum llparse_state_e {\n  s_error,\n  s_n_llhttp__internal__n_invoke_llhttp__after_message_complete,\n  s_n_llhttp__internal__n_pause_1,\n  s_n_llhttp__internal__n_invoke_is_equal_upgrade,\n  s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2,\n  s_n_llhttp__internal__n_chunk_data_almost_done_skip,\n  s_n_llhttp__internal__n_chunk_data_almost_done,\n  s_n_llhttp__internal__n_consume_content_length,\n  s_n_llhttp__internal__n_span_start_llhttp__on_body,\n  s_n_llhttp__internal__n_invoke_is_equal_content_length,\n  s_n_llhttp__internal__n_chunk_size_almost_done,\n  s_n_llhttp__internal__n_chunk_parameters,\n  s_n_llhttp__internal__n_chunk_size_otherwise,\n  s_n_llhttp__internal__n_chunk_size,\n  s_n_llhttp__internal__n_chunk_size_digit,\n  s_n_llhttp__internal__n_invoke_update_content_length,\n  s_n_llhttp__internal__n_consume_content_length_1,\n  s_n_llhttp__internal__n_span_start_llhttp__on_body_1,\n  s_n_llhttp__internal__n_eof,\n  s_n_llhttp__internal__n_span_start_llhttp__on_body_2,\n  s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete,\n  s_n_llhttp__internal__n_headers_almost_done,\n  s_n_llhttp__internal__n_span_start_llhttp__on_header_value,\n  s_n_llhttp__internal__n_header_value_discard_lws,\n  s_n_llhttp__internal__n_header_value_discard_ws_almost_done,\n  s_n_llhttp__internal__n_header_value_lws,\n  s_n_llhttp__internal__n_header_value_almost_done,\n  s_n_llhttp__internal__n_header_value_lenient,\n  s_n_llhttp__internal__n_header_value_otherwise,\n  s_n_llhttp__internal__n_header_value_connection_token,\n  s_n_llhttp__internal__n_header_value_connection_ws,\n  s_n_llhttp__internal__n_header_value_connection_1,\n  s_n_llhttp__internal__n_header_value_connection_2,\n  s_n_llhttp__internal__n_header_value_connection_3,\n  s_n_llhttp__internal__n_header_value_connection,\n  s_n_llhttp__internal__n_error_15,\n  s_n_llhttp__internal__n_header_value,\n  s_n_llhttp__internal__n_header_value_discard_rws,\n  s_n_llhttp__internal__n_error_16,\n  s_n_llhttp__internal__n_header_value_content_length_ws,\n  s_n_llhttp__internal__n_header_value_content_length,\n  s_n_llhttp__internal__n_header_value_te_chunked_1,\n  s_n_llhttp__internal__n_header_value_te_chunked,\n  s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1,\n  s_n_llhttp__internal__n_header_value_discard_ws,\n  s_n_llhttp__internal__n_header_field_general_otherwise,\n  s_n_llhttp__internal__n_header_field_general,\n  s_n_llhttp__internal__n_header_field_colon,\n  s_n_llhttp__internal__n_header_field_3,\n  s_n_llhttp__internal__n_header_field_4,\n  s_n_llhttp__internal__n_header_field_2,\n  s_n_llhttp__internal__n_header_field_1,\n  s_n_llhttp__internal__n_header_field_5,\n  s_n_llhttp__internal__n_header_field_6,\n  s_n_llhttp__internal__n_header_field_7,\n  s_n_llhttp__internal__n_header_field,\n  s_n_llhttp__internal__n_span_start_llhttp__on_header_field,\n  s_n_llhttp__internal__n_header_field_start,\n  s_n_llhttp__internal__n_url_skip_to_http09,\n  s_n_llhttp__internal__n_url_skip_lf_to_http09,\n  s_n_llhttp__internal__n_req_http_end_1,\n  s_n_llhttp__internal__n_req_http_end,\n  s_n_llhttp__internal__n_req_http_minor,\n  s_n_llhttp__internal__n_req_http_dot,\n  s_n_llhttp__internal__n_req_http_major,\n  s_n_llhttp__internal__n_req_http_start_1,\n  s_n_llhttp__internal__n_req_http_start_2,\n  s_n_llhttp__internal__n_req_http_start,\n  s_n_llhttp__internal__n_url_skip_to_http,\n  s_n_llhttp__internal__n_url_fragment,\n  s_n_llhttp__internal__n_span_end_stub_query_3,\n  s_n_llhttp__internal__n_url_query,\n  s_n_llhttp__internal__n_url_query_or_fragment,\n  s_n_llhttp__internal__n_url_path,\n  s_n_llhttp__internal__n_span_start_stub_path_2,\n  s_n_llhttp__internal__n_span_start_stub_path,\n  s_n_llhttp__internal__n_span_start_stub_path_1,\n  s_n_llhttp__internal__n_url_server_with_at,\n  s_n_llhttp__internal__n_url_server,\n  s_n_llhttp__internal__n_url_schema_delim_1,\n  s_n_llhttp__internal__n_url_schema_delim,\n  s_n_llhttp__internal__n_span_end_stub_schema,\n  s_n_llhttp__internal__n_url_schema,\n  s_n_llhttp__internal__n_url_start,\n  s_n_llhttp__internal__n_span_start_llhttp__on_url_1,\n  s_n_llhttp__internal__n_span_start_llhttp__on_url,\n  s_n_llhttp__internal__n_req_spaces_before_url,\n  s_n_llhttp__internal__n_req_first_space_before_url,\n  s_n_llhttp__internal__n_start_req_1,\n  s_n_llhttp__internal__n_start_req_2,\n  s_n_llhttp__internal__n_start_req_4,\n  s_n_llhttp__internal__n_start_req_6,\n  s_n_llhttp__internal__n_start_req_7,\n  s_n_llhttp__internal__n_start_req_5,\n  s_n_llhttp__internal__n_start_req_3,\n  s_n_llhttp__internal__n_start_req_8,\n  s_n_llhttp__internal__n_start_req_9,\n  s_n_llhttp__internal__n_start_req_10,\n  s_n_llhttp__internal__n_start_req_12,\n  s_n_llhttp__internal__n_start_req_13,\n  s_n_llhttp__internal__n_start_req_11,\n  s_n_llhttp__internal__n_start_req_15,\n  s_n_llhttp__internal__n_start_req_16,\n  s_n_llhttp__internal__n_start_req_18,\n  s_n_llhttp__internal__n_start_req_20,\n  s_n_llhttp__internal__n_start_req_21,\n  s_n_llhttp__internal__n_start_req_19,\n  s_n_llhttp__internal__n_start_req_17,\n  s_n_llhttp__internal__n_start_req_22,\n  s_n_llhttp__internal__n_start_req_14,\n  s_n_llhttp__internal__n_start_req_23,\n  s_n_llhttp__internal__n_start_req_24,\n  s_n_llhttp__internal__n_start_req_26,\n  s_n_llhttp__internal__n_start_req_27,\n  s_n_llhttp__internal__n_start_req_30,\n  s_n_llhttp__internal__n_start_req_31,\n  s_n_llhttp__internal__n_start_req_29,\n  s_n_llhttp__internal__n_start_req_28,\n  s_n_llhttp__internal__n_start_req_33,\n  s_n_llhttp__internal__n_start_req_32,\n  s_n_llhttp__internal__n_start_req_25,\n  s_n_llhttp__internal__n_start_req_36,\n  s_n_llhttp__internal__n_start_req_37,\n  s_n_llhttp__internal__n_start_req_35,\n  s_n_llhttp__internal__n_start_req_34,\n  s_n_llhttp__internal__n_start_req_39,\n  s_n_llhttp__internal__n_start_req_40,\n  s_n_llhttp__internal__n_start_req_41,\n  s_n_llhttp__internal__n_start_req_38,\n  s_n_llhttp__internal__n_start_req_42,\n  s_n_llhttp__internal__n_start_req_45,\n  s_n_llhttp__internal__n_start_req_47,\n  s_n_llhttp__internal__n_start_req_48,\n  s_n_llhttp__internal__n_start_req_46,\n  s_n_llhttp__internal__n_start_req_49,\n  s_n_llhttp__internal__n_start_req_44,\n  s_n_llhttp__internal__n_start_req_43,\n  s_n_llhttp__internal__n_start_req,\n  s_n_llhttp__internal__n_res_line_almost_done,\n  s_n_llhttp__internal__n_res_status,\n  s_n_llhttp__internal__n_span_start_llhttp__on_status,\n  s_n_llhttp__internal__n_res_status_start,\n  s_n_llhttp__internal__n_res_status_code_otherwise,\n  s_n_llhttp__internal__n_res_status_code,\n  s_n_llhttp__internal__n_res_http_end,\n  s_n_llhttp__internal__n_res_http_minor,\n  s_n_llhttp__internal__n_res_http_dot,\n  s_n_llhttp__internal__n_res_http_major,\n  s_n_llhttp__internal__n_start_res,\n  s_n_llhttp__internal__n_req_or_res_method_2,\n  s_n_llhttp__internal__n_req_or_res_method_3,\n  s_n_llhttp__internal__n_req_or_res_method_1,\n  s_n_llhttp__internal__n_req_or_res_method,\n  s_n_llhttp__internal__n_start_req_or_res,\n  s_n_llhttp__internal__n_invoke_load_type,\n  s_n_llhttp__internal__n_start,\n};\ntypedef enum llparse_state_e llparse_state_t;\n\nint llhttp__on_url(\n    llhttp__internal_t* s, const unsigned char* p,\n    const unsigned char* endp);\n\nint llhttp__on_header_field(\n    llhttp__internal_t* s, const unsigned char* p,\n    const unsigned char* endp);\n\nint llhttp__on_header_value(\n    llhttp__internal_t* s, const unsigned char* p,\n    const unsigned char* endp);\n\nint llhttp__on_body(\n    llhttp__internal_t* s, const unsigned char* p,\n    const unsigned char* endp);\n\nint llhttp__on_status(\n    llhttp__internal_t* s, const unsigned char* p,\n    const unsigned char* endp);\n\nint llhttp__internal__c_update_finish(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->finish = 2;\n  return 0;\n}\n\nint llhttp__on_message_begin(\n    llhttp__internal_t* s, const unsigned char* p,\n    const unsigned char* endp);\n\nint llhttp__internal__c_load_type(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  return state->type;\n}\n\nint llhttp__internal__c_store_method(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp,\n    int match) {\n  state->method = match;\n  return 0;\n}\n\nint llhttp__internal__c_is_equal_method(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  return state->method == 5;\n}\n\nint llhttp__internal__c_update_http_major(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->http_major = 0;\n  return 0;\n}\n\nint llhttp__internal__c_update_http_minor(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->http_minor = 9;\n  return 0;\n}\n\nint llhttp__internal__c_test_flags(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  return (state->flags & 128) == 128;\n}\n\nint llhttp__on_chunk_complete(\n    llhttp__internal_t* s, const unsigned char* p,\n    const unsigned char* endp);\n\nint llhttp__on_message_complete(\n    llhttp__internal_t* s, const unsigned char* p,\n    const unsigned char* endp);\n\nint llhttp__internal__c_is_equal_upgrade(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  return state->upgrade == 1;\n}\n\nint llhttp__after_message_complete(\n    llhttp__internal_t* s, const unsigned char* p,\n    const unsigned char* endp);\n\nint llhttp__internal__c_update_finish_1(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->finish = 0;\n  return 0;\n}\n\nint llhttp__internal__c_test_flags_1(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  return (state->flags & 40) == 40;\n}\n\nint llhttp__before_headers_complete(\n    llhttp__internal_t* s, const unsigned char* p,\n    const unsigned char* endp);\n\nint llhttp__on_headers_complete(\n    llhttp__internal_t* s, const unsigned char* p,\n    const unsigned char* endp);\n\nint llhttp__after_headers_complete(\n    llhttp__internal_t* s, const unsigned char* p,\n    const unsigned char* endp);\n\nint llhttp__internal__c_update_content_length(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->content_length = 0;\n  return 0;\n}\n\nint llhttp__internal__c_mul_add_content_length(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp,\n    int match) {\n  /* Multiplication overflow */\n  if (state->content_length > 0xffffffffffffffffULL / 16) {\n    return 1;\n  }\n  \n  state->content_length *= 16;\n  \n  /* Addition overflow */\n  if (match >= 0) {\n    if (state->content_length > 0xffffffffffffffffULL - match) {\n      return 1;\n    }\n  } else {\n    if (state->content_length < 0ULL - match) {\n      return 1;\n    }\n  }\n  state->content_length += match;\n  return 0;\n}\n\nint llhttp__on_chunk_header(\n    llhttp__internal_t* s, const unsigned char* p,\n    const unsigned char* endp);\n\nint llhttp__internal__c_is_equal_content_length(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  return state->content_length == 0;\n}\n\nint llhttp__internal__c_or_flags(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->flags |= 128;\n  return 0;\n}\n\nint llhttp__internal__c_update_finish_2(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->finish = 1;\n  return 0;\n}\n\nint llhttp__internal__c_or_flags_1(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->flags |= 64;\n  return 0;\n}\n\nint llhttp__internal__c_update_upgrade(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->upgrade = 1;\n  return 0;\n}\n\nint llhttp__internal__c_store_header_state(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp,\n    int match) {\n  state->header_state = match;\n  return 0;\n}\n\nint llhttp__internal__c_load_header_state(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  return state->header_state;\n}\n\nint llhttp__internal__c_or_flags_3(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->flags |= 1;\n  return 0;\n}\n\nint llhttp__internal__c_update_header_state(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->header_state = 1;\n  return 0;\n}\n\nint llhttp__internal__c_or_flags_4(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->flags |= 2;\n  return 0;\n}\n\nint llhttp__internal__c_or_flags_5(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->flags |= 4;\n  return 0;\n}\n\nint llhttp__internal__c_or_flags_6(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->flags |= 8;\n  return 0;\n}\n\nint llhttp__internal__c_update_header_state_2(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->header_state = 6;\n  return 0;\n}\n\nint llhttp__internal__c_test_flags_2(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  return (state->flags & 256) == 256;\n}\n\nint llhttp__internal__c_update_header_state_4(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->header_state = 0;\n  return 0;\n}\n\nint llhttp__internal__c_update_header_state_5(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->header_state = 5;\n  return 0;\n}\n\nint llhttp__internal__c_update_header_state_6(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->header_state = 7;\n  return 0;\n}\n\nint llhttp__internal__c_test_flags_3(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  return (state->flags & 32) == 32;\n}\n\nint llhttp__internal__c_mul_add_content_length_1(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp,\n    int match) {\n  /* Multiplication overflow */\n  if (state->content_length > 0xffffffffffffffffULL / 10) {\n    return 1;\n  }\n  \n  state->content_length *= 10;\n  \n  /* Addition overflow */\n  if (match >= 0) {\n    if (state->content_length > 0xffffffffffffffffULL - match) {\n      return 1;\n    }\n  } else {\n    if (state->content_length < 0ULL - match) {\n      return 1;\n    }\n  }\n  state->content_length += match;\n  return 0;\n}\n\nint llhttp__internal__c_or_flags_15(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->flags |= 32;\n  return 0;\n}\n\nint llhttp__internal__c_update_header_state_8(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->header_state = 8;\n  return 0;\n}\n\nint llhttp__internal__c_or_flags_16(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->flags |= 16;\n  return 0;\n}\n\nint llhttp__internal__c_store_http_major(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp,\n    int match) {\n  state->http_major = match;\n  return 0;\n}\n\nint llhttp__internal__c_store_http_minor(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp,\n    int match) {\n  state->http_minor = match;\n  return 0;\n}\n\nint llhttp__internal__c_is_equal_method_1(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  return state->method == 33;\n}\n\nint llhttp__internal__c_update_status_code(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->status_code = 0;\n  return 0;\n}\n\nint llhttp__internal__c_mul_add_status_code(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp,\n    int match) {\n  /* Multiplication overflow */\n  if (state->status_code > 0xffff / 10) {\n    return 1;\n  }\n  \n  state->status_code *= 10;\n  \n  /* Addition overflow */\n  if (match >= 0) {\n    if (state->status_code > 0xffff - match) {\n      return 1;\n    }\n  } else {\n    if (state->status_code < 0 - match) {\n      return 1;\n    }\n  }\n  state->status_code += match;\n  \n  /* Enforce maximum */\n  if (state->status_code > 999) {\n    return 1;\n  }\n  return 0;\n}\n\nint llhttp__internal__c_update_type(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->type = 1;\n  return 0;\n}\n\nint llhttp__internal__c_update_type_1(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  state->type = 2;\n  return 0;\n}\n\nint llhttp__internal_init(llhttp__internal_t* state) {\n  memset(state, 0, sizeof(*state));\n  state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_start;\n  return 0;\n}\n\nstatic llparse_state_t llhttp__internal__run(\n    llhttp__internal_t* state,\n    const unsigned char* p,\n    const unsigned char* endp) {\n  int match;\n  switch ((llparse_state_t) (intptr_t) state->_current) {\n    case s_n_llhttp__internal__n_invoke_llhttp__after_message_complete:\n    s_n_llhttp__internal__n_invoke_llhttp__after_message_complete: {\n      switch (llhttp__after_message_complete(state, p, endp)) {\n        default:\n          goto s_n_llhttp__internal__n_invoke_update_finish_1;\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_pause_1:\n    s_n_llhttp__internal__n_pause_1: {\n      state->error = 0x15;\n      state->reason = \"Pause on CONNECT/Upgrade\";\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__after_message_complete;\n      return s_error;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_invoke_is_equal_upgrade:\n    s_n_llhttp__internal__n_invoke_is_equal_upgrade: {\n      switch (llhttp__internal__c_is_equal_upgrade(state, p, endp)) {\n        case 0:\n          goto s_n_llhttp__internal__n_invoke_llhttp__after_message_complete;\n        default:\n          goto s_n_llhttp__internal__n_pause_1;\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2:\n    s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2: {\n      switch (llhttp__on_message_complete(state, p, endp)) {\n        case 0:\n          goto s_n_llhttp__internal__n_invoke_is_equal_upgrade;\n        case 20:\n          goto s_n_llhttp__internal__n_pause_5;\n        default:\n          goto s_n_llhttp__internal__n_error_9;\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_chunk_data_almost_done_skip:\n    s_n_llhttp__internal__n_chunk_data_almost_done_skip: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_chunk_data_almost_done_skip;\n      }\n      p++;\n      goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_complete;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_chunk_data_almost_done:\n    s_n_llhttp__internal__n_chunk_data_almost_done: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_chunk_data_almost_done;\n      }\n      p++;\n      goto s_n_llhttp__internal__n_chunk_data_almost_done_skip;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_consume_content_length:\n    s_n_llhttp__internal__n_consume_content_length: {\n      size_t avail;\n      size_t need;\n      \n      avail = endp - p;\n      need = state->content_length;\n      if (avail >= need) {\n        p += need;\n        state->content_length = 0;\n        goto s_n_llhttp__internal__n_span_end_llhttp__on_body;\n      }\n      \n      state->content_length -= avail;\n      return s_n_llhttp__internal__n_consume_content_length;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_span_start_llhttp__on_body:\n    s_n_llhttp__internal__n_span_start_llhttp__on_body: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_span_start_llhttp__on_body;\n      }\n      state->_span_pos0 = (void*) p;\n      state->_span_cb0 = llhttp__on_body;\n      goto s_n_llhttp__internal__n_consume_content_length;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_invoke_is_equal_content_length:\n    s_n_llhttp__internal__n_invoke_is_equal_content_length: {\n      switch (llhttp__internal__c_is_equal_content_length(state, p, endp)) {\n        case 0:\n          goto s_n_llhttp__internal__n_span_start_llhttp__on_body;\n        default:\n          goto s_n_llhttp__internal__n_invoke_or_flags;\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_chunk_size_almost_done:\n    s_n_llhttp__internal__n_chunk_size_almost_done: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_chunk_size_almost_done;\n      }\n      p++;\n      goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_header;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_chunk_parameters:\n    s_n_llhttp__internal__n_chunk_parameters: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_chunk_parameters;\n      }\n      switch (*p) {\n        case 13: {\n          p++;\n          goto s_n_llhttp__internal__n_chunk_size_almost_done;\n        }\n        default: {\n          p++;\n          goto s_n_llhttp__internal__n_chunk_parameters;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_chunk_size_otherwise:\n    s_n_llhttp__internal__n_chunk_size_otherwise: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_chunk_size_otherwise;\n      }\n      switch (*p) {\n        case 13: {\n          p++;\n          goto s_n_llhttp__internal__n_chunk_size_almost_done;\n        }\n        case ' ': {\n          p++;\n          goto s_n_llhttp__internal__n_chunk_parameters;\n        }\n        case ';': {\n          p++;\n          goto s_n_llhttp__internal__n_chunk_parameters;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_6;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_chunk_size:\n    s_n_llhttp__internal__n_chunk_size: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_chunk_size;\n      }\n      switch (*p) {\n        case '0': {\n          p++;\n          match = 0;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case '1': {\n          p++;\n          match = 1;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case '2': {\n          p++;\n          match = 2;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case '3': {\n          p++;\n          match = 3;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case '4': {\n          p++;\n          match = 4;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case '5': {\n          p++;\n          match = 5;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case '6': {\n          p++;\n          match = 6;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case '7': {\n          p++;\n          match = 7;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case '8': {\n          p++;\n          match = 8;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case '9': {\n          p++;\n          match = 9;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'A': {\n          p++;\n          match = 10;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'B': {\n          p++;\n          match = 11;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'C': {\n          p++;\n          match = 12;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'D': {\n          p++;\n          match = 13;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'E': {\n          p++;\n          match = 14;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'F': {\n          p++;\n          match = 15;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'a': {\n          p++;\n          match = 10;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'b': {\n          p++;\n          match = 11;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'c': {\n          p++;\n          match = 12;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'd': {\n          p++;\n          match = 13;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'e': {\n          p++;\n          match = 14;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'f': {\n          p++;\n          match = 15;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_chunk_size_otherwise;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_chunk_size_digit:\n    s_n_llhttp__internal__n_chunk_size_digit: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_chunk_size_digit;\n      }\n      switch (*p) {\n        case '0': {\n          p++;\n          match = 0;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case '1': {\n          p++;\n          match = 1;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case '2': {\n          p++;\n          match = 2;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case '3': {\n          p++;\n          match = 3;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case '4': {\n          p++;\n          match = 4;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case '5': {\n          p++;\n          match = 5;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case '6': {\n          p++;\n          match = 6;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case '7': {\n          p++;\n          match = 7;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case '8': {\n          p++;\n          match = 8;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case '9': {\n          p++;\n          match = 9;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'A': {\n          p++;\n          match = 10;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'B': {\n          p++;\n          match = 11;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'C': {\n          p++;\n          match = 12;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'D': {\n          p++;\n          match = 13;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'E': {\n          p++;\n          match = 14;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'F': {\n          p++;\n          match = 15;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'a': {\n          p++;\n          match = 10;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'b': {\n          p++;\n          match = 11;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'c': {\n          p++;\n          match = 12;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'd': {\n          p++;\n          match = 13;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'e': {\n          p++;\n          match = 14;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        case 'f': {\n          p++;\n          match = 15;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_8;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_invoke_update_content_length:\n    s_n_llhttp__internal__n_invoke_update_content_length: {\n      switch (llhttp__internal__c_update_content_length(state, p, endp)) {\n        default:\n          goto s_n_llhttp__internal__n_chunk_size_digit;\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_consume_content_length_1:\n    s_n_llhttp__internal__n_consume_content_length_1: {\n      size_t avail;\n      size_t need;\n      \n      avail = endp - p;\n      need = state->content_length;\n      if (avail >= need) {\n        p += need;\n        state->content_length = 0;\n        goto s_n_llhttp__internal__n_span_end_llhttp__on_body_1;\n      }\n      \n      state->content_length -= avail;\n      return s_n_llhttp__internal__n_consume_content_length_1;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_span_start_llhttp__on_body_1:\n    s_n_llhttp__internal__n_span_start_llhttp__on_body_1: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_span_start_llhttp__on_body_1;\n      }\n      state->_span_pos0 = (void*) p;\n      state->_span_cb0 = llhttp__on_body;\n      goto s_n_llhttp__internal__n_consume_content_length_1;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_eof:\n    s_n_llhttp__internal__n_eof: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_eof;\n      }\n      p++;\n      goto s_n_llhttp__internal__n_eof;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_span_start_llhttp__on_body_2:\n    s_n_llhttp__internal__n_span_start_llhttp__on_body_2: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_span_start_llhttp__on_body_2;\n      }\n      state->_span_pos0 = (void*) p;\n      state->_span_cb0 = llhttp__on_body;\n      goto s_n_llhttp__internal__n_eof;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete:\n    s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete: {\n      switch (llhttp__after_headers_complete(state, p, endp)) {\n        case 1:\n          goto s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_1;\n        case 2:\n          goto s_n_llhttp__internal__n_invoke_update_content_length;\n        case 3:\n          goto s_n_llhttp__internal__n_span_start_llhttp__on_body_1;\n        case 4:\n          goto s_n_llhttp__internal__n_invoke_update_finish_2;\n        default:\n          goto s_n_llhttp__internal__n_invoke_llhttp__on_message_complete;\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_headers_almost_done:\n    s_n_llhttp__internal__n_headers_almost_done: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_headers_almost_done;\n      }\n      p++;\n      goto s_n_llhttp__internal__n_invoke_test_flags;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_span_start_llhttp__on_header_value:\n    s_n_llhttp__internal__n_span_start_llhttp__on_header_value: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_span_start_llhttp__on_header_value;\n      }\n      state->_span_pos0 = (void*) p;\n      state->_span_cb0 = llhttp__on_header_value;\n      goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_value_discard_lws:\n    s_n_llhttp__internal__n_header_value_discard_lws: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_value_discard_lws;\n      }\n      switch (*p) {\n        case 9: {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_discard_ws;\n        }\n        case ' ': {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_discard_ws;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_invoke_load_header_state;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_value_discard_ws_almost_done:\n    s_n_llhttp__internal__n_header_value_discard_ws_almost_done: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_value_discard_ws_almost_done;\n      }\n      p++;\n      goto s_n_llhttp__internal__n_header_value_discard_lws;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_value_lws:\n    s_n_llhttp__internal__n_header_value_lws: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_value_lws;\n      }\n      switch (*p) {\n        case 9: {\n          goto s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1;\n        }\n        case ' ': {\n          goto s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_invoke_load_header_state_2;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_value_almost_done:\n    s_n_llhttp__internal__n_header_value_almost_done: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_value_almost_done;\n      }\n      switch (*p) {\n        case 10: {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_lws;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_12;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_value_lenient:\n    s_n_llhttp__internal__n_header_value_lenient: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_value_lenient;\n      }\n      switch (*p) {\n        case 10: {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value_1;\n        }\n        case 13: {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value_3;\n        }\n        default: {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_lenient;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_value_otherwise:\n    s_n_llhttp__internal__n_header_value_otherwise: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_value_otherwise;\n      }\n      switch (*p) {\n        case 10: {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value_1;\n        }\n        case 13: {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value_2;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_invoke_test_flags_2;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_value_connection_token:\n    s_n_llhttp__internal__n_header_value_connection_token: {\n      static uint8_t lookup_table[] = {\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0\n      };\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_value_connection_token;\n      }\n      switch (lookup_table[(uint8_t) *p]) {\n        case 1: {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_connection_token;\n        }\n        case 2: {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_connection;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_header_value_otherwise;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_value_connection_ws:\n    s_n_llhttp__internal__n_header_value_connection_ws: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_value_connection_ws;\n      }\n      switch (*p) {\n        case 10: {\n          goto s_n_llhttp__internal__n_header_value_otherwise;\n        }\n        case 13: {\n          goto s_n_llhttp__internal__n_header_value_otherwise;\n        }\n        case ' ': {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_connection_ws;\n        }\n        case ',': {\n          p++;\n          goto s_n_llhttp__internal__n_invoke_load_header_state_3;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_invoke_update_header_state_4;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_value_connection_1:\n    s_n_llhttp__internal__n_header_value_connection_1: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_value_connection_1;\n      }\n      match_seq = llparse__match_sequence_to_lower_unsafe(state, p, endp, llparse_blob4, 4);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          goto s_n_llhttp__internal__n_invoke_update_header_state_2;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_header_value_connection_1;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_header_value_connection_token;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_value_connection_2:\n    s_n_llhttp__internal__n_header_value_connection_2: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_value_connection_2;\n      }\n      match_seq = llparse__match_sequence_to_lower_unsafe(state, p, endp, llparse_blob5, 9);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          goto s_n_llhttp__internal__n_invoke_update_header_state_5;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_header_value_connection_2;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_header_value_connection_token;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_value_connection_3:\n    s_n_llhttp__internal__n_header_value_connection_3: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_value_connection_3;\n      }\n      match_seq = llparse__match_sequence_to_lower_unsafe(state, p, endp, llparse_blob6, 6);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          goto s_n_llhttp__internal__n_invoke_update_header_state_6;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_header_value_connection_3;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_header_value_connection_token;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_value_connection:\n    s_n_llhttp__internal__n_header_value_connection: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_value_connection;\n      }\n      switch (((*p) | 0x20)) {\n        case 9: {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_connection;\n        }\n        case ' ': {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_connection;\n        }\n        case 'c': {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_connection_1;\n        }\n        case 'k': {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_connection_2;\n        }\n        case 'u': {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_connection_3;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_header_value_connection_token;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_error_15:\n    s_n_llhttp__internal__n_error_15: {\n      state->error = 0xb;\n      state->reason = \"Content-Length overflow\";\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_error;\n      return s_error;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_value:\n    s_n_llhttp__internal__n_header_value: {\n      static uint8_t lookup_table[] = {\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0\n      };\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_value;\n      }\n      #ifdef __SSE4_2__\n      if (endp - p >= 16) {\n        __m128i ranges;\n        __m128i input;\n        int avail;\n        int match_len;\n      \n        /* Load input */\n        input = _mm_loadu_si128((__m128i const*) p);\n        ranges = _mm_loadu_si128((__m128i const*) llparse_blob7);\n      \n        /* Find first character that does not match `ranges` */\n        match_len = _mm_cmpestri(ranges, 6,\n            input, 16,\n            _SIDD_UBYTE_OPS | _SIDD_CMP_RANGES |\n              _SIDD_NEGATIVE_POLARITY);\n      \n        if (match_len != 0) {\n          p += match_len;\n          goto s_n_llhttp__internal__n_header_value;\n        }\n        goto s_n_llhttp__internal__n_header_value_otherwise;\n      }\n      #endif  /* __SSE4_2__ */\n      switch (lookup_table[(uint8_t) *p]) {\n        case 1: {\n          p++;\n          goto s_n_llhttp__internal__n_header_value;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_header_value_otherwise;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_value_discard_rws:\n    s_n_llhttp__internal__n_header_value_discard_rws: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_value_discard_rws;\n      }\n      switch (*p) {\n        case 10: {\n          goto s_n_llhttp__internal__n_header_value_otherwise;\n        }\n        case 13: {\n          goto s_n_llhttp__internal__n_header_value_otherwise;\n        }\n        case ' ': {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_discard_rws;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_invoke_update_header_state_7;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_error_16:\n    s_n_llhttp__internal__n_error_16: {\n      state->error = 0xb;\n      state->reason = \"Invalid character in Content-Length\";\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_error;\n      return s_error;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_value_content_length_ws:\n    s_n_llhttp__internal__n_header_value_content_length_ws: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_value_content_length_ws;\n      }\n      switch (*p) {\n        case 10: {\n          goto s_n_llhttp__internal__n_invoke_or_flags_15;\n        }\n        case 13: {\n          goto s_n_llhttp__internal__n_invoke_or_flags_15;\n        }\n        case ' ': {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_content_length_ws;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value_5;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_value_content_length:\n    s_n_llhttp__internal__n_header_value_content_length: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_value_content_length;\n      }\n      switch (*p) {\n        case '0': {\n          p++;\n          match = 0;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1;\n        }\n        case '1': {\n          p++;\n          match = 1;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1;\n        }\n        case '2': {\n          p++;\n          match = 2;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1;\n        }\n        case '3': {\n          p++;\n          match = 3;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1;\n        }\n        case '4': {\n          p++;\n          match = 4;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1;\n        }\n        case '5': {\n          p++;\n          match = 5;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1;\n        }\n        case '6': {\n          p++;\n          match = 6;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1;\n        }\n        case '7': {\n          p++;\n          match = 7;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1;\n        }\n        case '8': {\n          p++;\n          match = 8;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1;\n        }\n        case '9': {\n          p++;\n          match = 9;\n          goto s_n_llhttp__internal__n_invoke_mul_add_content_length_1;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_header_value_content_length_ws;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_value_te_chunked_1:\n    s_n_llhttp__internal__n_header_value_te_chunked_1: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_value_te_chunked_1;\n      }\n      match_seq = llparse__match_sequence_to_lower_unsafe(state, p, endp, llparse_blob8, 6);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          goto s_n_llhttp__internal__n_invoke_update_header_state_8;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_header_value_te_chunked_1;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_invoke_update_header_state_7;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_value_te_chunked:\n    s_n_llhttp__internal__n_header_value_te_chunked: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_value_te_chunked;\n      }\n      switch (((*p) | 0x20)) {\n        case 10: {\n          goto s_n_llhttp__internal__n_header_value_discard_rws;\n        }\n        case 13: {\n          goto s_n_llhttp__internal__n_header_value_discard_rws;\n        }\n        case ' ': {\n          goto s_n_llhttp__internal__n_header_value_discard_rws;\n        }\n        case 'c': {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_te_chunked_1;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_invoke_update_header_state_7;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1:\n    s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1;\n      }\n      state->_span_pos0 = (void*) p;\n      state->_span_cb0 = llhttp__on_header_value;\n      goto s_n_llhttp__internal__n_invoke_load_header_state_1;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_value_discard_ws:\n    s_n_llhttp__internal__n_header_value_discard_ws: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_value_discard_ws;\n      }\n      switch (*p) {\n        case 9: {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_discard_ws;\n        }\n        case 10: {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_discard_lws;\n        }\n        case 13: {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_discard_ws_almost_done;\n        }\n        case ' ': {\n          p++;\n          goto s_n_llhttp__internal__n_header_value_discard_ws;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_span_start_llhttp__on_header_value_1;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_field_general_otherwise:\n    s_n_llhttp__internal__n_header_field_general_otherwise: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_field_general_otherwise;\n      }\n      switch (*p) {\n        case ':': {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_header_field_1;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_17;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_field_general:\n    s_n_llhttp__internal__n_header_field_general: {\n      static uint8_t lookup_table[] = {\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,\n        0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n      };\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_field_general;\n      }\n      #ifdef __SSE4_2__\n      if (endp - p >= 16) {\n        __m128i ranges;\n        __m128i input;\n        int avail;\n        int match_len;\n      \n        /* Load input */\n        input = _mm_loadu_si128((__m128i const*) p);\n        ranges = _mm_loadu_si128((__m128i const*) llparse_blob9);\n      \n        /* Find first character that does not match `ranges` */\n        match_len = _mm_cmpestri(ranges, 16,\n            input, 16,\n            _SIDD_UBYTE_OPS | _SIDD_CMP_RANGES |\n              _SIDD_NEGATIVE_POLARITY);\n      \n        if (match_len != 0) {\n          p += match_len;\n          goto s_n_llhttp__internal__n_header_field_general;\n        }\n        ranges = _mm_loadu_si128((__m128i const*) llparse_blob10);\n      \n        /* Find first character that does not match `ranges` */\n        match_len = _mm_cmpestri(ranges, 2,\n            input, 16,\n            _SIDD_UBYTE_OPS | _SIDD_CMP_RANGES |\n              _SIDD_NEGATIVE_POLARITY);\n      \n        if (match_len != 0) {\n          p += match_len;\n          goto s_n_llhttp__internal__n_header_field_general;\n        }\n        goto s_n_llhttp__internal__n_header_field_general_otherwise;\n      }\n      #endif  /* __SSE4_2__ */\n      switch (lookup_table[(uint8_t) *p]) {\n        case 1: {\n          p++;\n          goto s_n_llhttp__internal__n_header_field_general;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_header_field_general_otherwise;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_field_colon:\n    s_n_llhttp__internal__n_header_field_colon: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_field_colon;\n      }\n      switch (*p) {\n        case ' ': {\n          p++;\n          goto s_n_llhttp__internal__n_header_field_colon;\n        }\n        case ':': {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_header_field;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_invoke_update_header_state_9;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_field_3:\n    s_n_llhttp__internal__n_header_field_3: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_field_3;\n      }\n      match_seq = llparse__match_sequence_to_lower_unsafe(state, p, endp, llparse_blob3, 6);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 1;\n          goto s_n_llhttp__internal__n_invoke_store_header_state;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_header_field_3;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_invoke_update_header_state_10;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_field_4:\n    s_n_llhttp__internal__n_header_field_4: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_field_4;\n      }\n      match_seq = llparse__match_sequence_to_lower_unsafe(state, p, endp, llparse_blob11, 10);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 2;\n          goto s_n_llhttp__internal__n_invoke_store_header_state;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_header_field_4;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_invoke_update_header_state_10;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_field_2:\n    s_n_llhttp__internal__n_header_field_2: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_field_2;\n      }\n      switch (((*p) | 0x20)) {\n        case 'n': {\n          p++;\n          goto s_n_llhttp__internal__n_header_field_3;\n        }\n        case 't': {\n          p++;\n          goto s_n_llhttp__internal__n_header_field_4;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_invoke_update_header_state_10;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_field_1:\n    s_n_llhttp__internal__n_header_field_1: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_field_1;\n      }\n      match_seq = llparse__match_sequence_to_lower_unsafe(state, p, endp, llparse_blob2, 2);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          goto s_n_llhttp__internal__n_header_field_2;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_header_field_1;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_invoke_update_header_state_10;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_field_5:\n    s_n_llhttp__internal__n_header_field_5: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_field_5;\n      }\n      match_seq = llparse__match_sequence_to_lower_unsafe(state, p, endp, llparse_blob12, 15);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 1;\n          goto s_n_llhttp__internal__n_invoke_store_header_state;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_header_field_5;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_invoke_update_header_state_10;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_field_6:\n    s_n_llhttp__internal__n_header_field_6: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_field_6;\n      }\n      match_seq = llparse__match_sequence_to_lower_unsafe(state, p, endp, llparse_blob13, 16);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 3;\n          goto s_n_llhttp__internal__n_invoke_store_header_state;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_header_field_6;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_invoke_update_header_state_10;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_field_7:\n    s_n_llhttp__internal__n_header_field_7: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_field_7;\n      }\n      match_seq = llparse__match_sequence_to_lower_unsafe(state, p, endp, llparse_blob14, 6);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 4;\n          goto s_n_llhttp__internal__n_invoke_store_header_state;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_header_field_7;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_invoke_update_header_state_10;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_field:\n    s_n_llhttp__internal__n_header_field: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_field;\n      }\n      switch (((*p) | 0x20)) {\n        case 'c': {\n          p++;\n          goto s_n_llhttp__internal__n_header_field_1;\n        }\n        case 'p': {\n          p++;\n          goto s_n_llhttp__internal__n_header_field_5;\n        }\n        case 't': {\n          p++;\n          goto s_n_llhttp__internal__n_header_field_6;\n        }\n        case 'u': {\n          p++;\n          goto s_n_llhttp__internal__n_header_field_7;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_invoke_update_header_state_10;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_span_start_llhttp__on_header_field:\n    s_n_llhttp__internal__n_span_start_llhttp__on_header_field: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_span_start_llhttp__on_header_field;\n      }\n      state->_span_pos0 = (void*) p;\n      state->_span_cb0 = llhttp__on_header_field;\n      goto s_n_llhttp__internal__n_header_field;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_header_field_start:\n    s_n_llhttp__internal__n_header_field_start: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_header_field_start;\n      }\n      switch (*p) {\n        case 10: {\n          goto s_n_llhttp__internal__n_headers_almost_done;\n        }\n        case 13: {\n          p++;\n          goto s_n_llhttp__internal__n_headers_almost_done;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_span_start_llhttp__on_header_field;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_url_skip_to_http09:\n    s_n_llhttp__internal__n_url_skip_to_http09: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_url_skip_to_http09;\n      }\n      p++;\n      goto s_n_llhttp__internal__n_invoke_update_http_major;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_url_skip_lf_to_http09:\n    s_n_llhttp__internal__n_url_skip_lf_to_http09: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_url_skip_lf_to_http09;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob15, 2);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          goto s_n_llhttp__internal__n_invoke_update_http_major;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_url_skip_lf_to_http09;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_18;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_req_http_end_1:\n    s_n_llhttp__internal__n_req_http_end_1: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_req_http_end_1;\n      }\n      switch (*p) {\n        case 10: {\n          p++;\n          goto s_n_llhttp__internal__n_header_field_start;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_19;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_req_http_end:\n    s_n_llhttp__internal__n_req_http_end: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_req_http_end;\n      }\n      switch (*p) {\n        case 10: {\n          p++;\n          goto s_n_llhttp__internal__n_header_field_start;\n        }\n        case 13: {\n          p++;\n          goto s_n_llhttp__internal__n_req_http_end_1;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_19;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_req_http_minor:\n    s_n_llhttp__internal__n_req_http_minor: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_req_http_minor;\n      }\n      switch (*p) {\n        case '0': {\n          p++;\n          match = 0;\n          goto s_n_llhttp__internal__n_invoke_store_http_minor;\n        }\n        case '1': {\n          p++;\n          match = 1;\n          goto s_n_llhttp__internal__n_invoke_store_http_minor;\n        }\n        case '2': {\n          p++;\n          match = 2;\n          goto s_n_llhttp__internal__n_invoke_store_http_minor;\n        }\n        case '3': {\n          p++;\n          match = 3;\n          goto s_n_llhttp__internal__n_invoke_store_http_minor;\n        }\n        case '4': {\n          p++;\n          match = 4;\n          goto s_n_llhttp__internal__n_invoke_store_http_minor;\n        }\n        case '5': {\n          p++;\n          match = 5;\n          goto s_n_llhttp__internal__n_invoke_store_http_minor;\n        }\n        case '6': {\n          p++;\n          match = 6;\n          goto s_n_llhttp__internal__n_invoke_store_http_minor;\n        }\n        case '7': {\n          p++;\n          match = 7;\n          goto s_n_llhttp__internal__n_invoke_store_http_minor;\n        }\n        case '8': {\n          p++;\n          match = 8;\n          goto s_n_llhttp__internal__n_invoke_store_http_minor;\n        }\n        case '9': {\n          p++;\n          match = 9;\n          goto s_n_llhttp__internal__n_invoke_store_http_minor;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_20;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_req_http_dot:\n    s_n_llhttp__internal__n_req_http_dot: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_req_http_dot;\n      }\n      switch (*p) {\n        case '.': {\n          p++;\n          goto s_n_llhttp__internal__n_req_http_minor;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_21;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_req_http_major:\n    s_n_llhttp__internal__n_req_http_major: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_req_http_major;\n      }\n      switch (*p) {\n        case '0': {\n          p++;\n          match = 0;\n          goto s_n_llhttp__internal__n_invoke_store_http_major;\n        }\n        case '1': {\n          p++;\n          match = 1;\n          goto s_n_llhttp__internal__n_invoke_store_http_major;\n        }\n        case '2': {\n          p++;\n          match = 2;\n          goto s_n_llhttp__internal__n_invoke_store_http_major;\n        }\n        case '3': {\n          p++;\n          match = 3;\n          goto s_n_llhttp__internal__n_invoke_store_http_major;\n        }\n        case '4': {\n          p++;\n          match = 4;\n          goto s_n_llhttp__internal__n_invoke_store_http_major;\n        }\n        case '5': {\n          p++;\n          match = 5;\n          goto s_n_llhttp__internal__n_invoke_store_http_major;\n        }\n        case '6': {\n          p++;\n          match = 6;\n          goto s_n_llhttp__internal__n_invoke_store_http_major;\n        }\n        case '7': {\n          p++;\n          match = 7;\n          goto s_n_llhttp__internal__n_invoke_store_http_major;\n        }\n        case '8': {\n          p++;\n          match = 8;\n          goto s_n_llhttp__internal__n_invoke_store_http_major;\n        }\n        case '9': {\n          p++;\n          match = 9;\n          goto s_n_llhttp__internal__n_invoke_store_http_major;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_22;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_req_http_start_1:\n    s_n_llhttp__internal__n_req_http_start_1: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_req_http_start_1;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob16, 4);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          goto s_n_llhttp__internal__n_req_http_major;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_req_http_start_1;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_24;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_req_http_start_2:\n    s_n_llhttp__internal__n_req_http_start_2: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_req_http_start_2;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob17, 3);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          goto s_n_llhttp__internal__n_invoke_is_equal_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_req_http_start_2;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_24;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_req_http_start:\n    s_n_llhttp__internal__n_req_http_start: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_req_http_start;\n      }\n      switch (*p) {\n        case ' ': {\n          p++;\n          goto s_n_llhttp__internal__n_req_http_start;\n        }\n        case 'H': {\n          p++;\n          goto s_n_llhttp__internal__n_req_http_start_1;\n        }\n        case 'I': {\n          p++;\n          goto s_n_llhttp__internal__n_req_http_start_2;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_24;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_url_skip_to_http:\n    s_n_llhttp__internal__n_url_skip_to_http: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_url_skip_to_http;\n      }\n      p++;\n      goto s_n_llhttp__internal__n_req_http_start;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_url_fragment:\n    s_n_llhttp__internal__n_url_fragment: {\n      static uint8_t lookup_table[] = {\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 1, 3, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1\n      };\n      if (p == endp) {\n        return s_n_llhttp__internal__n_url_fragment;\n      }\n      switch (lookup_table[(uint8_t) *p]) {\n        case 1: {\n          p++;\n          goto s_n_llhttp__internal__n_url_fragment;\n        }\n        case 2: {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_url_6;\n        }\n        case 3: {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_url_7;\n        }\n        case 4: {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_url_8;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_25;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_span_end_stub_query_3:\n    s_n_llhttp__internal__n_span_end_stub_query_3: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_span_end_stub_query_3;\n      }\n      p++;\n      goto s_n_llhttp__internal__n_url_fragment;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_url_query:\n    s_n_llhttp__internal__n_url_query: {\n      static uint8_t lookup_table[] = {\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 1, 3, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        4, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1\n      };\n      if (p == endp) {\n        return s_n_llhttp__internal__n_url_query;\n      }\n      switch (lookup_table[(uint8_t) *p]) {\n        case 1: {\n          p++;\n          goto s_n_llhttp__internal__n_url_query;\n        }\n        case 2: {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_url_9;\n        }\n        case 3: {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_url_10;\n        }\n        case 4: {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_url_11;\n        }\n        case 5: {\n          goto s_n_llhttp__internal__n_span_end_stub_query_3;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_26;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_url_query_or_fragment:\n    s_n_llhttp__internal__n_url_query_or_fragment: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_url_query_or_fragment;\n      }\n      switch (*p) {\n        case 10: {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_url_3;\n        }\n        case 13: {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_url_4;\n        }\n        case ' ': {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_url_5;\n        }\n        case '#': {\n          p++;\n          goto s_n_llhttp__internal__n_url_fragment;\n        }\n        case '?': {\n          p++;\n          goto s_n_llhttp__internal__n_url_query;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_27;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_url_path:\n    s_n_llhttp__internal__n_url_path: {\n      static uint8_t lookup_table[] = {\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1\n      };\n      if (p == endp) {\n        return s_n_llhttp__internal__n_url_path;\n      }\n      #ifdef __SSE4_2__\n      if (endp - p >= 16) {\n        __m128i ranges;\n        __m128i input;\n        int avail;\n        int match_len;\n      \n        /* Load input */\n        input = _mm_loadu_si128((__m128i const*) p);\n        ranges = _mm_loadu_si128((__m128i const*) llparse_blob1);\n      \n        /* Find first character that does not match `ranges` */\n        match_len = _mm_cmpestri(ranges, 12,\n            input, 16,\n            _SIDD_UBYTE_OPS | _SIDD_CMP_RANGES |\n              _SIDD_NEGATIVE_POLARITY);\n      \n        if (match_len != 0) {\n          p += match_len;\n          goto s_n_llhttp__internal__n_url_path;\n        }\n        goto s_n_llhttp__internal__n_url_query_or_fragment;\n      }\n      #endif  /* __SSE4_2__ */\n      switch (lookup_table[(uint8_t) *p]) {\n        case 1: {\n          p++;\n          goto s_n_llhttp__internal__n_url_path;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_url_query_or_fragment;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_span_start_stub_path_2:\n    s_n_llhttp__internal__n_span_start_stub_path_2: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_span_start_stub_path_2;\n      }\n      p++;\n      goto s_n_llhttp__internal__n_url_path;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_span_start_stub_path:\n    s_n_llhttp__internal__n_span_start_stub_path: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_span_start_stub_path;\n      }\n      p++;\n      goto s_n_llhttp__internal__n_url_path;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_span_start_stub_path_1:\n    s_n_llhttp__internal__n_span_start_stub_path_1: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_span_start_stub_path_1;\n      }\n      p++;\n      goto s_n_llhttp__internal__n_url_path;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_url_server_with_at:\n    s_n_llhttp__internal__n_url_server_with_at: {\n      static uint8_t lookup_table[] = {\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        3, 4, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5,\n        4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 4, 0, 6,\n        7, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,\n        4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 4, 0, 4,\n        0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,\n        4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 4, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n      };\n      if (p == endp) {\n        return s_n_llhttp__internal__n_url_server_with_at;\n      }\n      switch (lookup_table[(uint8_t) *p]) {\n        case 1: {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_url_12;\n        }\n        case 2: {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_url_13;\n        }\n        case 3: {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_url_14;\n        }\n        case 4: {\n          p++;\n          goto s_n_llhttp__internal__n_url_server;\n        }\n        case 5: {\n          goto s_n_llhttp__internal__n_span_start_stub_path_1;\n        }\n        case 6: {\n          p++;\n          goto s_n_llhttp__internal__n_url_query;\n        }\n        case 7: {\n          p++;\n          goto s_n_llhttp__internal__n_error_28;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_29;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_url_server:\n    s_n_llhttp__internal__n_url_server: {\n      static uint8_t lookup_table[] = {\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        3, 4, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5,\n        4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 4, 0, 6,\n        7, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,\n        4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 4, 0, 4,\n        0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,\n        4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 4, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n      };\n      if (p == endp) {\n        return s_n_llhttp__internal__n_url_server;\n      }\n      switch (lookup_table[(uint8_t) *p]) {\n        case 1: {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_url;\n        }\n        case 2: {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_url_1;\n        }\n        case 3: {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_url_2;\n        }\n        case 4: {\n          p++;\n          goto s_n_llhttp__internal__n_url_server;\n        }\n        case 5: {\n          goto s_n_llhttp__internal__n_span_start_stub_path;\n        }\n        case 6: {\n          p++;\n          goto s_n_llhttp__internal__n_url_query;\n        }\n        case 7: {\n          p++;\n          goto s_n_llhttp__internal__n_url_server_with_at;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_30;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_url_schema_delim_1:\n    s_n_llhttp__internal__n_url_schema_delim_1: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_url_schema_delim_1;\n      }\n      switch (*p) {\n        case '/': {\n          p++;\n          goto s_n_llhttp__internal__n_url_server;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_32;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_url_schema_delim:\n    s_n_llhttp__internal__n_url_schema_delim: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_url_schema_delim;\n      }\n      switch (*p) {\n        case 10: {\n          p++;\n          goto s_n_llhttp__internal__n_error_31;\n        }\n        case 13: {\n          p++;\n          goto s_n_llhttp__internal__n_error_31;\n        }\n        case ' ': {\n          p++;\n          goto s_n_llhttp__internal__n_error_31;\n        }\n        case '/': {\n          p++;\n          goto s_n_llhttp__internal__n_url_schema_delim_1;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_32;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_span_end_stub_schema:\n    s_n_llhttp__internal__n_span_end_stub_schema: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_span_end_stub_schema;\n      }\n      p++;\n      goto s_n_llhttp__internal__n_url_schema_delim;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_url_schema:\n    s_n_llhttp__internal__n_url_schema: {\n      static uint8_t lookup_table[] = {\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0,\n        0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,\n        3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0,\n        0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,\n        3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n      };\n      if (p == endp) {\n        return s_n_llhttp__internal__n_url_schema;\n      }\n      switch (lookup_table[(uint8_t) *p]) {\n        case 1: {\n          p++;\n          goto s_n_llhttp__internal__n_error_31;\n        }\n        case 2: {\n          goto s_n_llhttp__internal__n_span_end_stub_schema;\n        }\n        case 3: {\n          p++;\n          goto s_n_llhttp__internal__n_url_schema;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_33;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_url_start:\n    s_n_llhttp__internal__n_url_start: {\n      static uint8_t lookup_table[] = {\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,\n        3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0,\n        0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,\n        3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\n      };\n      if (p == endp) {\n        return s_n_llhttp__internal__n_url_start;\n      }\n      switch (lookup_table[(uint8_t) *p]) {\n        case 1: {\n          p++;\n          goto s_n_llhttp__internal__n_error_31;\n        }\n        case 2: {\n          goto s_n_llhttp__internal__n_span_start_stub_path_2;\n        }\n        case 3: {\n          goto s_n_llhttp__internal__n_url_schema;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_34;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_span_start_llhttp__on_url_1:\n    s_n_llhttp__internal__n_span_start_llhttp__on_url_1: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_span_start_llhttp__on_url_1;\n      }\n      state->_span_pos0 = (void*) p;\n      state->_span_cb0 = llhttp__on_url;\n      goto s_n_llhttp__internal__n_url_start;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_span_start_llhttp__on_url:\n    s_n_llhttp__internal__n_span_start_llhttp__on_url: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_span_start_llhttp__on_url;\n      }\n      state->_span_pos0 = (void*) p;\n      state->_span_cb0 = llhttp__on_url;\n      goto s_n_llhttp__internal__n_url_server;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_req_spaces_before_url:\n    s_n_llhttp__internal__n_req_spaces_before_url: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_req_spaces_before_url;\n      }\n      switch (*p) {\n        case ' ': {\n          p++;\n          goto s_n_llhttp__internal__n_req_spaces_before_url;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_invoke_is_equal_method;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_req_first_space_before_url:\n    s_n_llhttp__internal__n_req_first_space_before_url: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_req_first_space_before_url;\n      }\n      switch (*p) {\n        case ' ': {\n          p++;\n          goto s_n_llhttp__internal__n_req_spaces_before_url;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_35;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_1:\n    s_n_llhttp__internal__n_start_req_1: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_1;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob0, 2);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 19;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_1;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_43;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_2:\n    s_n_llhttp__internal__n_start_req_2: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_2;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob18, 3);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 16;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_2;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_43;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_4:\n    s_n_llhttp__internal__n_start_req_4: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_4;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob19, 6);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 22;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_4;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_43;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_6:\n    s_n_llhttp__internal__n_start_req_6: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_6;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob20, 4);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 5;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_6;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_43;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_7:\n    s_n_llhttp__internal__n_start_req_7: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_7;\n      }\n      switch (*p) {\n        case 'Y': {\n          p++;\n          match = 8;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_43;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_5:\n    s_n_llhttp__internal__n_start_req_5: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_5;\n      }\n      switch (*p) {\n        case 'N': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_6;\n        }\n        case 'P': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_7;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_43;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_3:\n    s_n_llhttp__internal__n_start_req_3: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_3;\n      }\n      switch (*p) {\n        case 'H': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_4;\n        }\n        case 'O': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_5;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_43;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_8:\n    s_n_llhttp__internal__n_start_req_8: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_8;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob21, 5);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 0;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_8;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_43;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_9:\n    s_n_llhttp__internal__n_start_req_9: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_9;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob22, 2);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 1;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_9;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_43;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_10:\n    s_n_llhttp__internal__n_start_req_10: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_10;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob23, 3);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 2;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_10;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_43;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_12:\n    s_n_llhttp__internal__n_start_req_12: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_12;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob24, 2);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 31;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_12;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_43;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_13:\n    s_n_llhttp__internal__n_start_req_13: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_13;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob25, 2);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 9;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_13;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_43;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_11:\n    s_n_llhttp__internal__n_start_req_11: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_11;\n      }\n      switch (*p) {\n        case 'I': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_12;\n        }\n        case 'O': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_13;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_43;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_15:\n    s_n_llhttp__internal__n_start_req_15: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_15;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob26, 6);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 24;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_15;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_43;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_16:\n    s_n_llhttp__internal__n_start_req_16: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_16;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob27, 3);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 23;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_16;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_43;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_18:\n    s_n_llhttp__internal__n_start_req_18: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_18;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob28, 7);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 21;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_18;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_43;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_20:\n    s_n_llhttp__internal__n_start_req_20: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_20;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob29, 6);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 30;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_20;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_43;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_21:\n    s_n_llhttp__internal__n_start_req_21: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_21;\n      }\n      switch (*p) {\n        case 'L': {\n          p++;\n          match = 10;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_43;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_19:\n    s_n_llhttp__internal__n_start_req_19: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_19;\n      }\n      switch (*p) {\n        case 'A': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_20;\n        }\n        case 'O': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_21;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_43;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_17:\n    s_n_llhttp__internal__n_start_req_17: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_17;\n      }\n      switch (*p) {\n        case 'A': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_18;\n        }\n        case 'C': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_19;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_43;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_22:\n    s_n_llhttp__internal__n_start_req_22: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_22;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob30, 2);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 11;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_22;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_43;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_14:\n    s_n_llhttp__internal__n_start_req_14: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_14;\n      }\n      switch (*p) {\n        case '-': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_15;\n        }\n        case 'E': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_16;\n        }\n        case 'K': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_17;\n        }\n        case 'O': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_22;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_43;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_23:\n    s_n_llhttp__internal__n_start_req_23: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_23;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob31, 5);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 25;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_23;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_43;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_24:\n    s_n_llhttp__internal__n_start_req_24: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_24;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob32, 6);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 6;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_24;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_43;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_26:\n    s_n_llhttp__internal__n_start_req_26: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_26;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob33, 3);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 28;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_26;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_43;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_27:\n    s_n_llhttp__internal__n_start_req_27: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_27;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob34, 2);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 3;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_27;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_43;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_30:\n    s_n_llhttp__internal__n_start_req_30: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_30;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob36, 3);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 12;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_30;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_43;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_31:\n    s_n_llhttp__internal__n_start_req_31: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_31;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob37, 4);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 13;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_31;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_43;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_29:\n    s_n_llhttp__internal__n_start_req_29: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_29;\n      }\n      switch (*p) {\n        case 'F': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_30;\n        }\n        case 'P': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_31;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_43;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_28:\n    s_n_llhttp__internal__n_start_req_28: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_28;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob35, 2);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_29;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_28;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_43;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_33:\n    s_n_llhttp__internal__n_start_req_33: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_33;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob38, 2);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 29;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_33;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_43;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_32:\n    s_n_llhttp__internal__n_start_req_32: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_32;\n      }\n      switch (*p) {\n        case 'R': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_33;\n        }\n        case 'T': {\n          p++;\n          match = 4;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_43;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_25:\n    s_n_llhttp__internal__n_start_req_25: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_25;\n      }\n      switch (*p) {\n        case 'A': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_26;\n        }\n        case 'O': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_27;\n        }\n        case 'R': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_28;\n        }\n        case 'U': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_32;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_43;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_36:\n    s_n_llhttp__internal__n_start_req_36: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_36;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob39, 3);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 17;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_36;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_43;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_37:\n    s_n_llhttp__internal__n_start_req_37: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_37;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob40, 3);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 20;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_37;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_43;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_35:\n    s_n_llhttp__internal__n_start_req_35: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_35;\n      }\n      switch (*p) {\n        case 'B': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_36;\n        }\n        case 'P': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_37;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_43;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_34:\n    s_n_llhttp__internal__n_start_req_34: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_34;\n      }\n      switch (*p) {\n        case 'E': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_35;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_43;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_39:\n    s_n_llhttp__internal__n_start_req_39: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_39;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob41, 4);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 14;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_39;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_43;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_40:\n    s_n_llhttp__internal__n_start_req_40: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_40;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob42, 4);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 33;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_40;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_43;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_41:\n    s_n_llhttp__internal__n_start_req_41: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_41;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob43, 7);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 26;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_41;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_43;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_38:\n    s_n_llhttp__internal__n_start_req_38: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_38;\n      }\n      switch (*p) {\n        case 'E': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_39;\n        }\n        case 'O': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_40;\n        }\n        case 'U': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_41;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_43;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_42:\n    s_n_llhttp__internal__n_start_req_42: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_42;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob44, 4);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 7;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_42;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_43;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_45:\n    s_n_llhttp__internal__n_start_req_45: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_45;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob45, 3);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 18;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_45;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_43;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_47:\n    s_n_llhttp__internal__n_start_req_47: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_47;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob46, 2);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 32;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_47;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_43;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_48:\n    s_n_llhttp__internal__n_start_req_48: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_48;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob47, 2);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 15;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_48;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_43;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_46:\n    s_n_llhttp__internal__n_start_req_46: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_46;\n      }\n      switch (*p) {\n        case 'I': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_47;\n        }\n        case 'O': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_48;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_43;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_49:\n    s_n_llhttp__internal__n_start_req_49: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_49;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob48, 8);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 27;\n          goto s_n_llhttp__internal__n_invoke_store_method_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_req_49;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_43;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_44:\n    s_n_llhttp__internal__n_start_req_44: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_44;\n      }\n      switch (*p) {\n        case 'B': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_45;\n        }\n        case 'L': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_46;\n        }\n        case 'S': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_49;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_43;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_43:\n    s_n_llhttp__internal__n_start_req_43: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_43;\n      }\n      switch (*p) {\n        case 'N': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_44;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_43;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req:\n    s_n_llhttp__internal__n_start_req: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req;\n      }\n      switch (*p) {\n        case 'A': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_1;\n        }\n        case 'B': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_2;\n        }\n        case 'C': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_3;\n        }\n        case 'D': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_8;\n        }\n        case 'G': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_9;\n        }\n        case 'H': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_10;\n        }\n        case 'L': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_11;\n        }\n        case 'M': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_14;\n        }\n        case 'N': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_23;\n        }\n        case 'O': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_24;\n        }\n        case 'P': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_25;\n        }\n        case 'R': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_34;\n        }\n        case 'S': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_38;\n        }\n        case 'T': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_42;\n        }\n        case 'U': {\n          p++;\n          goto s_n_llhttp__internal__n_start_req_43;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_43;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_res_line_almost_done:\n    s_n_llhttp__internal__n_res_line_almost_done: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_res_line_almost_done;\n      }\n      p++;\n      goto s_n_llhttp__internal__n_header_field_start;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_res_status:\n    s_n_llhttp__internal__n_res_status: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_res_status;\n      }\n      switch (*p) {\n        case 10: {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_status;\n        }\n        case 13: {\n          goto s_n_llhttp__internal__n_span_end_llhttp__on_status_1;\n        }\n        default: {\n          p++;\n          goto s_n_llhttp__internal__n_res_status;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_span_start_llhttp__on_status:\n    s_n_llhttp__internal__n_span_start_llhttp__on_status: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_span_start_llhttp__on_status;\n      }\n      state->_span_pos0 = (void*) p;\n      state->_span_cb0 = llhttp__on_status;\n      goto s_n_llhttp__internal__n_res_status;\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_res_status_start:\n    s_n_llhttp__internal__n_res_status_start: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_res_status_start;\n      }\n      switch (*p) {\n        case 10: {\n          p++;\n          goto s_n_llhttp__internal__n_header_field_start;\n        }\n        case 13: {\n          p++;\n          goto s_n_llhttp__internal__n_res_line_almost_done;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_span_start_llhttp__on_status;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_res_status_code_otherwise:\n    s_n_llhttp__internal__n_res_status_code_otherwise: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_res_status_code_otherwise;\n      }\n      switch (*p) {\n        case 10: {\n          goto s_n_llhttp__internal__n_res_status_start;\n        }\n        case 13: {\n          goto s_n_llhttp__internal__n_res_status_start;\n        }\n        case ' ': {\n          p++;\n          goto s_n_llhttp__internal__n_res_status_start;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_37;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_res_status_code:\n    s_n_llhttp__internal__n_res_status_code: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_res_status_code;\n      }\n      switch (*p) {\n        case '0': {\n          p++;\n          match = 0;\n          goto s_n_llhttp__internal__n_invoke_mul_add_status_code;\n        }\n        case '1': {\n          p++;\n          match = 1;\n          goto s_n_llhttp__internal__n_invoke_mul_add_status_code;\n        }\n        case '2': {\n          p++;\n          match = 2;\n          goto s_n_llhttp__internal__n_invoke_mul_add_status_code;\n        }\n        case '3': {\n          p++;\n          match = 3;\n          goto s_n_llhttp__internal__n_invoke_mul_add_status_code;\n        }\n        case '4': {\n          p++;\n          match = 4;\n          goto s_n_llhttp__internal__n_invoke_mul_add_status_code;\n        }\n        case '5': {\n          p++;\n          match = 5;\n          goto s_n_llhttp__internal__n_invoke_mul_add_status_code;\n        }\n        case '6': {\n          p++;\n          match = 6;\n          goto s_n_llhttp__internal__n_invoke_mul_add_status_code;\n        }\n        case '7': {\n          p++;\n          match = 7;\n          goto s_n_llhttp__internal__n_invoke_mul_add_status_code;\n        }\n        case '8': {\n          p++;\n          match = 8;\n          goto s_n_llhttp__internal__n_invoke_mul_add_status_code;\n        }\n        case '9': {\n          p++;\n          match = 9;\n          goto s_n_llhttp__internal__n_invoke_mul_add_status_code;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_res_status_code_otherwise;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_res_http_end:\n    s_n_llhttp__internal__n_res_http_end: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_res_http_end;\n      }\n      switch (*p) {\n        case ' ': {\n          p++;\n          goto s_n_llhttp__internal__n_invoke_update_status_code;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_38;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_res_http_minor:\n    s_n_llhttp__internal__n_res_http_minor: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_res_http_minor;\n      }\n      switch (*p) {\n        case '0': {\n          p++;\n          match = 0;\n          goto s_n_llhttp__internal__n_invoke_store_http_minor_1;\n        }\n        case '1': {\n          p++;\n          match = 1;\n          goto s_n_llhttp__internal__n_invoke_store_http_minor_1;\n        }\n        case '2': {\n          p++;\n          match = 2;\n          goto s_n_llhttp__internal__n_invoke_store_http_minor_1;\n        }\n        case '3': {\n          p++;\n          match = 3;\n          goto s_n_llhttp__internal__n_invoke_store_http_minor_1;\n        }\n        case '4': {\n          p++;\n          match = 4;\n          goto s_n_llhttp__internal__n_invoke_store_http_minor_1;\n        }\n        case '5': {\n          p++;\n          match = 5;\n          goto s_n_llhttp__internal__n_invoke_store_http_minor_1;\n        }\n        case '6': {\n          p++;\n          match = 6;\n          goto s_n_llhttp__internal__n_invoke_store_http_minor_1;\n        }\n        case '7': {\n          p++;\n          match = 7;\n          goto s_n_llhttp__internal__n_invoke_store_http_minor_1;\n        }\n        case '8': {\n          p++;\n          match = 8;\n          goto s_n_llhttp__internal__n_invoke_store_http_minor_1;\n        }\n        case '9': {\n          p++;\n          match = 9;\n          goto s_n_llhttp__internal__n_invoke_store_http_minor_1;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_39;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_res_http_dot:\n    s_n_llhttp__internal__n_res_http_dot: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_res_http_dot;\n      }\n      switch (*p) {\n        case '.': {\n          p++;\n          goto s_n_llhttp__internal__n_res_http_minor;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_40;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_res_http_major:\n    s_n_llhttp__internal__n_res_http_major: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_res_http_major;\n      }\n      switch (*p) {\n        case '0': {\n          p++;\n          match = 0;\n          goto s_n_llhttp__internal__n_invoke_store_http_major_1;\n        }\n        case '1': {\n          p++;\n          match = 1;\n          goto s_n_llhttp__internal__n_invoke_store_http_major_1;\n        }\n        case '2': {\n          p++;\n          match = 2;\n          goto s_n_llhttp__internal__n_invoke_store_http_major_1;\n        }\n        case '3': {\n          p++;\n          match = 3;\n          goto s_n_llhttp__internal__n_invoke_store_http_major_1;\n        }\n        case '4': {\n          p++;\n          match = 4;\n          goto s_n_llhttp__internal__n_invoke_store_http_major_1;\n        }\n        case '5': {\n          p++;\n          match = 5;\n          goto s_n_llhttp__internal__n_invoke_store_http_major_1;\n        }\n        case '6': {\n          p++;\n          match = 6;\n          goto s_n_llhttp__internal__n_invoke_store_http_major_1;\n        }\n        case '7': {\n          p++;\n          match = 7;\n          goto s_n_llhttp__internal__n_invoke_store_http_major_1;\n        }\n        case '8': {\n          p++;\n          match = 8;\n          goto s_n_llhttp__internal__n_invoke_store_http_major_1;\n        }\n        case '9': {\n          p++;\n          match = 9;\n          goto s_n_llhttp__internal__n_invoke_store_http_major_1;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_41;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_res:\n    s_n_llhttp__internal__n_start_res: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_res;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob49, 5);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          goto s_n_llhttp__internal__n_res_http_major;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_start_res;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_44;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_req_or_res_method_2:\n    s_n_llhttp__internal__n_req_or_res_method_2: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_req_or_res_method_2;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob50, 2);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          match = 2;\n          goto s_n_llhttp__internal__n_invoke_store_method;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_req_or_res_method_2;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_42;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_req_or_res_method_3:\n    s_n_llhttp__internal__n_req_or_res_method_3: {\n      llparse_match_t match_seq;\n      \n      if (p == endp) {\n        return s_n_llhttp__internal__n_req_or_res_method_3;\n      }\n      match_seq = llparse__match_sequence_id(state, p, endp, llparse_blob51, 3);\n      p = match_seq.current;\n      switch (match_seq.status) {\n        case kMatchComplete: {\n          p++;\n          goto s_n_llhttp__internal__n_invoke_update_type_1;\n        }\n        case kMatchPause: {\n          return s_n_llhttp__internal__n_req_or_res_method_3;\n        }\n        case kMatchMismatch: {\n          goto s_n_llhttp__internal__n_error_42;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_req_or_res_method_1:\n    s_n_llhttp__internal__n_req_or_res_method_1: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_req_or_res_method_1;\n      }\n      switch (*p) {\n        case 'E': {\n          p++;\n          goto s_n_llhttp__internal__n_req_or_res_method_2;\n        }\n        case 'T': {\n          p++;\n          goto s_n_llhttp__internal__n_req_or_res_method_3;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_42;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_req_or_res_method:\n    s_n_llhttp__internal__n_req_or_res_method: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_req_or_res_method;\n      }\n      switch (*p) {\n        case 'H': {\n          p++;\n          goto s_n_llhttp__internal__n_req_or_res_method_1;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_error_42;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start_req_or_res:\n    s_n_llhttp__internal__n_start_req_or_res: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start_req_or_res;\n      }\n      switch (*p) {\n        case 'H': {\n          goto s_n_llhttp__internal__n_req_or_res_method;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_invoke_update_type_2;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_invoke_load_type:\n    s_n_llhttp__internal__n_invoke_load_type: {\n      switch (llhttp__internal__c_load_type(state, p, endp)) {\n        case 1:\n          goto s_n_llhttp__internal__n_start_req;\n        case 2:\n          goto s_n_llhttp__internal__n_start_res;\n        default:\n          goto s_n_llhttp__internal__n_start_req_or_res;\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    case s_n_llhttp__internal__n_start:\n    s_n_llhttp__internal__n_start: {\n      if (p == endp) {\n        return s_n_llhttp__internal__n_start;\n      }\n      switch (*p) {\n        case 10: {\n          p++;\n          goto s_n_llhttp__internal__n_start;\n        }\n        case 13: {\n          p++;\n          goto s_n_llhttp__internal__n_start;\n        }\n        default: {\n          goto s_n_llhttp__internal__n_invoke_update_finish;\n        }\n      }\n      /* UNREACHABLE */;\n      abort();\n    }\n    default:\n      /* UNREACHABLE */\n      abort();\n  }\n  s_n_llhttp__internal__n_error_31: {\n    state->error = 0x7;\n    state->reason = \"Invalid characters in url\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_finish_1: {\n    switch (llhttp__internal__c_update_finish_1(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_start;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_pause_5: {\n    state->error = 0x14;\n    state->reason = \"on_message_complete pause\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_is_equal_upgrade;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_9: {\n    state->error = 0x11;\n    state->reason = \"`on_message_complete` callback error\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_pause_7: {\n    state->error = 0x14;\n    state->reason = \"on_chunk_complete pause\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_11: {\n    state->error = 0x13;\n    state->reason = \"`on_chunk_complete` callback error\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_llhttp__on_chunk_complete_1: {\n    switch (llhttp__on_chunk_complete(state, p, endp)) {\n      case 0:\n        goto s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2;\n      case 20:\n        goto s_n_llhttp__internal__n_pause_7;\n      default:\n        goto s_n_llhttp__internal__n_error_11;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_10: {\n    state->error = 0x4;\n    state->reason = \"Content-Length can't be present with chunked encoding\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_pause_2: {\n    state->error = 0x14;\n    state->reason = \"on_message_complete pause\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_pause_1;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_3: {\n    state->error = 0x11;\n    state->reason = \"`on_message_complete` callback error\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_1: {\n    switch (llhttp__on_message_complete(state, p, endp)) {\n      case 0:\n        goto s_n_llhttp__internal__n_pause_1;\n      case 20:\n        goto s_n_llhttp__internal__n_pause_2;\n      default:\n        goto s_n_llhttp__internal__n_error_3;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_7: {\n    state->error = 0xc;\n    state->reason = \"Chunk size overflow\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_pause_3: {\n    state->error = 0x14;\n    state->reason = \"on_chunk_complete pause\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_update_content_length;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_5: {\n    state->error = 0x13;\n    state->reason = \"`on_chunk_complete` callback error\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_llhttp__on_chunk_complete: {\n    switch (llhttp__on_chunk_complete(state, p, endp)) {\n      case 0:\n        goto s_n_llhttp__internal__n_invoke_update_content_length;\n      case 20:\n        goto s_n_llhttp__internal__n_pause_3;\n      default:\n        goto s_n_llhttp__internal__n_error_5;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_body: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_body(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_chunk_data_almost_done;\n      return s_error;\n    }\n    goto s_n_llhttp__internal__n_chunk_data_almost_done;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_or_flags: {\n    switch (llhttp__internal__c_or_flags(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_header_field_start;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_pause_4: {\n    state->error = 0x14;\n    state->reason = \"on_chunk_header pause\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_is_equal_content_length;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_4: {\n    state->error = 0x12;\n    state->reason = \"`on_chunk_header` callback error\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_llhttp__on_chunk_header: {\n    switch (llhttp__on_chunk_header(state, p, endp)) {\n      case 0:\n        goto s_n_llhttp__internal__n_invoke_is_equal_content_length;\n      case 20:\n        goto s_n_llhttp__internal__n_pause_4;\n      default:\n        goto s_n_llhttp__internal__n_error_4;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_6: {\n    state->error = 0xc;\n    state->reason = \"Invalid character in chunk size\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_mul_add_content_length: {\n    switch (llhttp__internal__c_mul_add_content_length(state, p, endp, match)) {\n      case 1:\n        goto s_n_llhttp__internal__n_error_7;\n      default:\n        goto s_n_llhttp__internal__n_chunk_size;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_8: {\n    state->error = 0xc;\n    state->reason = \"Invalid character in chunk size\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_body_1: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_body(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2;\n      return s_error;\n    }\n    goto s_n_llhttp__internal__n_invoke_llhttp__on_message_complete_2;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_finish_2: {\n    switch (llhttp__internal__c_update_finish_2(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_span_start_llhttp__on_body_2;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_pause: {\n    state->error = 0x14;\n    state->reason = \"on_message_complete pause\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__after_message_complete;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_2: {\n    state->error = 0x11;\n    state->reason = \"`on_message_complete` callback error\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_llhttp__on_message_complete: {\n    switch (llhttp__on_message_complete(state, p, endp)) {\n      case 0:\n        goto s_n_llhttp__internal__n_invoke_llhttp__after_message_complete;\n      case 20:\n        goto s_n_llhttp__internal__n_pause;\n      default:\n        goto s_n_llhttp__internal__n_error_2;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_or_flags_1: {\n    switch (llhttp__internal__c_or_flags_1(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_or_flags_2: {\n    switch (llhttp__internal__c_or_flags_1(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_upgrade: {\n    switch (llhttp__internal__c_update_upgrade(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_invoke_or_flags_2;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_pause_6: {\n    state->error = 0x14;\n    state->reason = \"Paused by on_headers_complete\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_1: {\n    state->error = 0x10;\n    state->reason = \"User callback error\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_llhttp__on_headers_complete: {\n    switch (llhttp__on_headers_complete(state, p, endp)) {\n      case 0:\n        goto s_n_llhttp__internal__n_invoke_llhttp__after_headers_complete;\n      case 1:\n        goto s_n_llhttp__internal__n_invoke_or_flags_1;\n      case 2:\n        goto s_n_llhttp__internal__n_invoke_update_upgrade;\n      case 20:\n        goto s_n_llhttp__internal__n_pause_6;\n      default:\n        goto s_n_llhttp__internal__n_error_1;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_llhttp__before_headers_complete: {\n    switch (llhttp__before_headers_complete(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_invoke_llhttp__on_headers_complete;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_test_flags_1: {\n    switch (llhttp__internal__c_test_flags_1(state, p, endp)) {\n      case 1:\n        goto s_n_llhttp__internal__n_error_10;\n      default:\n        goto s_n_llhttp__internal__n_invoke_llhttp__before_headers_complete;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_test_flags: {\n    switch (llhttp__internal__c_test_flags(state, p, endp)) {\n      case 1:\n        goto s_n_llhttp__internal__n_invoke_llhttp__on_chunk_complete_1;\n      default:\n        goto s_n_llhttp__internal__n_invoke_test_flags_1;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_header_value: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_header_value(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_header_field_start;\n      return s_error;\n    }\n    goto s_n_llhttp__internal__n_header_field_start;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_header_state: {\n    switch (llhttp__internal__c_update_header_state(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_span_start_llhttp__on_header_value;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_or_flags_3: {\n    switch (llhttp__internal__c_or_flags_3(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_invoke_update_header_state;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_or_flags_4: {\n    switch (llhttp__internal__c_or_flags_4(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_invoke_update_header_state;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_or_flags_5: {\n    switch (llhttp__internal__c_or_flags_5(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_invoke_update_header_state;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_or_flags_6: {\n    switch (llhttp__internal__c_or_flags_6(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_span_start_llhttp__on_header_value;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_load_header_state: {\n    switch (llhttp__internal__c_load_header_state(state, p, endp)) {\n      case 5:\n        goto s_n_llhttp__internal__n_invoke_or_flags_3;\n      case 6:\n        goto s_n_llhttp__internal__n_invoke_or_flags_4;\n      case 7:\n        goto s_n_llhttp__internal__n_invoke_or_flags_5;\n      case 8:\n        goto s_n_llhttp__internal__n_invoke_or_flags_6;\n      default:\n        goto s_n_llhttp__internal__n_span_start_llhttp__on_header_value;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_header_state_1: {\n    switch (llhttp__internal__c_update_header_state(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_header_field_start;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_or_flags_7: {\n    switch (llhttp__internal__c_or_flags_3(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_invoke_update_header_state_1;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_or_flags_8: {\n    switch (llhttp__internal__c_or_flags_4(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_invoke_update_header_state_1;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_or_flags_9: {\n    switch (llhttp__internal__c_or_flags_5(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_invoke_update_header_state_1;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_or_flags_10: {\n    switch (llhttp__internal__c_or_flags_6(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_header_field_start;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_load_header_state_2: {\n    switch (llhttp__internal__c_load_header_state(state, p, endp)) {\n      case 5:\n        goto s_n_llhttp__internal__n_invoke_or_flags_7;\n      case 6:\n        goto s_n_llhttp__internal__n_invoke_or_flags_8;\n      case 7:\n        goto s_n_llhttp__internal__n_invoke_or_flags_9;\n      case 8:\n        goto s_n_llhttp__internal__n_invoke_or_flags_10;\n      default:\n        goto s_n_llhttp__internal__n_header_field_start;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_12: {\n    state->error = 0x3;\n    state->reason = \"Missing expected LF after header value\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_header_value_1: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_header_value(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_header_value_almost_done;\n      return s_error;\n    }\n    goto s_n_llhttp__internal__n_header_value_almost_done;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_header_value_2: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_header_value(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) (p + 1);\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_header_value_almost_done;\n      return s_error;\n    }\n    p++;\n    goto s_n_llhttp__internal__n_header_value_almost_done;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_header_value_3: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_header_value(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) (p + 1);\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_header_value_almost_done;\n      return s_error;\n    }\n    p++;\n    goto s_n_llhttp__internal__n_header_value_almost_done;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_13: {\n    state->error = 0xa;\n    state->reason = \"Invalid header value char\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_test_flags_2: {\n    switch (llhttp__internal__c_test_flags_2(state, p, endp)) {\n      case 1:\n        goto s_n_llhttp__internal__n_header_value_lenient;\n      default:\n        goto s_n_llhttp__internal__n_error_13;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_header_state_3: {\n    switch (llhttp__internal__c_update_header_state(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_header_value_connection;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_or_flags_11: {\n    switch (llhttp__internal__c_or_flags_3(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_invoke_update_header_state_3;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_or_flags_12: {\n    switch (llhttp__internal__c_or_flags_4(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_invoke_update_header_state_3;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_or_flags_13: {\n    switch (llhttp__internal__c_or_flags_5(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_invoke_update_header_state_3;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_or_flags_14: {\n    switch (llhttp__internal__c_or_flags_6(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_header_value_connection;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_load_header_state_3: {\n    switch (llhttp__internal__c_load_header_state(state, p, endp)) {\n      case 5:\n        goto s_n_llhttp__internal__n_invoke_or_flags_11;\n      case 6:\n        goto s_n_llhttp__internal__n_invoke_or_flags_12;\n      case 7:\n        goto s_n_llhttp__internal__n_invoke_or_flags_13;\n      case 8:\n        goto s_n_llhttp__internal__n_invoke_or_flags_14;\n      default:\n        goto s_n_llhttp__internal__n_header_value_connection;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_header_state_4: {\n    switch (llhttp__internal__c_update_header_state_4(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_header_value_connection_token;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_header_state_2: {\n    switch (llhttp__internal__c_update_header_state_2(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_header_value_connection_ws;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_header_state_5: {\n    switch (llhttp__internal__c_update_header_state_5(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_header_value_connection_ws;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_header_state_6: {\n    switch (llhttp__internal__c_update_header_state_6(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_header_value_connection_ws;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_header_value_4: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_header_value(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_15;\n      return s_error;\n    }\n    goto s_n_llhttp__internal__n_error_15;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_mul_add_content_length_1: {\n    switch (llhttp__internal__c_mul_add_content_length_1(state, p, endp, match)) {\n      case 1:\n        goto s_n_llhttp__internal__n_span_end_llhttp__on_header_value_4;\n      default:\n        goto s_n_llhttp__internal__n_header_value_content_length;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_header_state_7: {\n    switch (llhttp__internal__c_update_header_state_4(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_header_value;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_or_flags_15: {\n    switch (llhttp__internal__c_or_flags_15(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_header_value_discard_rws;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_header_value_5: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_header_value(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_error_16;\n      return s_error;\n    }\n    goto s_n_llhttp__internal__n_error_16;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_14: {\n    state->error = 0x4;\n    state->reason = \"Duplicate Content-Length\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_test_flags_3: {\n    switch (llhttp__internal__c_test_flags_3(state, p, endp)) {\n      case 0:\n        goto s_n_llhttp__internal__n_header_value_content_length;\n      default:\n        goto s_n_llhttp__internal__n_error_14;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_header_state_8: {\n    switch (llhttp__internal__c_update_header_state_8(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_header_value_discard_rws;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_or_flags_16: {\n    switch (llhttp__internal__c_or_flags_16(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_invoke_update_header_state_7;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_load_header_state_1: {\n    switch (llhttp__internal__c_load_header_state(state, p, endp)) {\n      case 1:\n        goto s_n_llhttp__internal__n_header_value_connection;\n      case 2:\n        goto s_n_llhttp__internal__n_invoke_test_flags_3;\n      case 3:\n        goto s_n_llhttp__internal__n_header_value_te_chunked;\n      case 4:\n        goto s_n_llhttp__internal__n_invoke_or_flags_16;\n      default:\n        goto s_n_llhttp__internal__n_header_value;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_header_field: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_header_field(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) (p + 1);\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_header_value_discard_ws;\n      return s_error;\n    }\n    p++;\n    goto s_n_llhttp__internal__n_header_value_discard_ws;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_header_field_1: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_header_field(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) (p + 1);\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_header_value_discard_ws;\n      return s_error;\n    }\n    p++;\n    goto s_n_llhttp__internal__n_header_value_discard_ws;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_17: {\n    state->error = 0xa;\n    state->reason = \"Invalid header token\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_header_state_9: {\n    switch (llhttp__internal__c_update_header_state_4(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_header_field_general;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_store_header_state: {\n    switch (llhttp__internal__c_store_header_state(state, p, endp, match)) {\n      default:\n        goto s_n_llhttp__internal__n_header_field_colon;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_header_state_10: {\n    switch (llhttp__internal__c_update_header_state_4(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_header_field_general;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_http_minor: {\n    switch (llhttp__internal__c_update_http_minor(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_header_field_start;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_http_major: {\n    switch (llhttp__internal__c_update_http_major(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_invoke_update_http_minor;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_url_3: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_url(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http09;\n      return s_error;\n    }\n    goto s_n_llhttp__internal__n_url_skip_to_http09;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_18: {\n    state->error = 0x7;\n    state->reason = \"Expected CRLF\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_url_4: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_url(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_lf_to_http09;\n      return s_error;\n    }\n    goto s_n_llhttp__internal__n_url_skip_lf_to_http09;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_19: {\n    state->error = 0x9;\n    state->reason = \"Expected CRLF after version\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_store_http_minor: {\n    switch (llhttp__internal__c_store_http_minor(state, p, endp, match)) {\n      default:\n        goto s_n_llhttp__internal__n_req_http_end;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_20: {\n    state->error = 0x9;\n    state->reason = \"Invalid minor version\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_21: {\n    state->error = 0x9;\n    state->reason = \"Expected dot\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_store_http_major: {\n    switch (llhttp__internal__c_store_http_major(state, p, endp, match)) {\n      default:\n        goto s_n_llhttp__internal__n_req_http_dot;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_22: {\n    state->error = 0x9;\n    state->reason = \"Invalid major version\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_24: {\n    state->error = 0x8;\n    state->reason = \"Expected HTTP/\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_23: {\n    state->error = 0x8;\n    state->reason = \"Expected SOURCE method for ICE/x.x request\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_is_equal_method_1: {\n    switch (llhttp__internal__c_is_equal_method_1(state, p, endp)) {\n      case 0:\n        goto s_n_llhttp__internal__n_error_23;\n      default:\n        goto s_n_llhttp__internal__n_req_http_major;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_url_5: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_url(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http;\n      return s_error;\n    }\n    goto s_n_llhttp__internal__n_url_skip_to_http;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_url_6: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_url(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http09;\n      return s_error;\n    }\n    goto s_n_llhttp__internal__n_url_skip_to_http09;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_url_7: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_url(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_lf_to_http09;\n      return s_error;\n    }\n    goto s_n_llhttp__internal__n_url_skip_lf_to_http09;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_url_8: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_url(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http;\n      return s_error;\n    }\n    goto s_n_llhttp__internal__n_url_skip_to_http;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_25: {\n    state->error = 0x7;\n    state->reason = \"Invalid char in url fragment start\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_url_9: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_url(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http09;\n      return s_error;\n    }\n    goto s_n_llhttp__internal__n_url_skip_to_http09;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_url_10: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_url(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_lf_to_http09;\n      return s_error;\n    }\n    goto s_n_llhttp__internal__n_url_skip_lf_to_http09;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_url_11: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_url(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http;\n      return s_error;\n    }\n    goto s_n_llhttp__internal__n_url_skip_to_http;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_26: {\n    state->error = 0x7;\n    state->reason = \"Invalid char in url query\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_27: {\n    state->error = 0x7;\n    state->reason = \"Invalid char in url path\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_url: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_url(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http09;\n      return s_error;\n    }\n    goto s_n_llhttp__internal__n_url_skip_to_http09;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_url_1: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_url(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_lf_to_http09;\n      return s_error;\n    }\n    goto s_n_llhttp__internal__n_url_skip_lf_to_http09;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_url_2: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_url(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http;\n      return s_error;\n    }\n    goto s_n_llhttp__internal__n_url_skip_to_http;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_url_12: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_url(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http09;\n      return s_error;\n    }\n    goto s_n_llhttp__internal__n_url_skip_to_http09;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_url_13: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_url(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_lf_to_http09;\n      return s_error;\n    }\n    goto s_n_llhttp__internal__n_url_skip_lf_to_http09;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_url_14: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_url(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) p;\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_url_skip_to_http;\n      return s_error;\n    }\n    goto s_n_llhttp__internal__n_url_skip_to_http;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_28: {\n    state->error = 0x7;\n    state->reason = \"Double @ in url\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_29: {\n    state->error = 0x7;\n    state->reason = \"Unexpected char in url server\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_30: {\n    state->error = 0x7;\n    state->reason = \"Unexpected char in url server\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_32: {\n    state->error = 0x7;\n    state->reason = \"Unexpected char in url schema\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_33: {\n    state->error = 0x7;\n    state->reason = \"Unexpected char in url schema\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_34: {\n    state->error = 0x7;\n    state->reason = \"Unexpected start char in url\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_is_equal_method: {\n    switch (llhttp__internal__c_is_equal_method(state, p, endp)) {\n      case 0:\n        goto s_n_llhttp__internal__n_span_start_llhttp__on_url_1;\n      default:\n        goto s_n_llhttp__internal__n_span_start_llhttp__on_url;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_35: {\n    state->error = 0x6;\n    state->reason = \"Expected space after method\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_store_method_1: {\n    switch (llhttp__internal__c_store_method(state, p, endp, match)) {\n      default:\n        goto s_n_llhttp__internal__n_req_first_space_before_url;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_43: {\n    state->error = 0x6;\n    state->reason = \"Invalid method encountered\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_36: {\n    state->error = 0xd;\n    state->reason = \"Response overflow\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_mul_add_status_code: {\n    switch (llhttp__internal__c_mul_add_status_code(state, p, endp, match)) {\n      case 1:\n        goto s_n_llhttp__internal__n_error_36;\n      default:\n        goto s_n_llhttp__internal__n_res_status_code;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_status: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_status(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) (p + 1);\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_header_field_start;\n      return s_error;\n    }\n    p++;\n    goto s_n_llhttp__internal__n_header_field_start;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_span_end_llhttp__on_status_1: {\n    const unsigned char* start;\n    int err;\n    \n    start = state->_span_pos0;\n    state->_span_pos0 = NULL;\n    err = llhttp__on_status(state, start, p);\n    if (err != 0) {\n      state->error = err;\n      state->error_pos = (const char*) (p + 1);\n      state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_res_line_almost_done;\n      return s_error;\n    }\n    p++;\n    goto s_n_llhttp__internal__n_res_line_almost_done;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_37: {\n    state->error = 0xd;\n    state->reason = \"Invalid response status\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_status_code: {\n    switch (llhttp__internal__c_update_status_code(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_res_status_code;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_38: {\n    state->error = 0x9;\n    state->reason = \"Expected space after version\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_store_http_minor_1: {\n    switch (llhttp__internal__c_store_http_minor(state, p, endp, match)) {\n      default:\n        goto s_n_llhttp__internal__n_res_http_end;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_39: {\n    state->error = 0x9;\n    state->reason = \"Invalid minor version\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_40: {\n    state->error = 0x9;\n    state->reason = \"Expected dot\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_store_http_major_1: {\n    switch (llhttp__internal__c_store_http_major(state, p, endp, match)) {\n      default:\n        goto s_n_llhttp__internal__n_res_http_dot;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_41: {\n    state->error = 0x9;\n    state->reason = \"Invalid major version\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_44: {\n    state->error = 0x8;\n    state->reason = \"Expected HTTP/\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_type: {\n    switch (llhttp__internal__c_update_type(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_req_first_space_before_url;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_store_method: {\n    switch (llhttp__internal__c_store_method(state, p, endp, match)) {\n      default:\n        goto s_n_llhttp__internal__n_invoke_update_type;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error_42: {\n    state->error = 0x8;\n    state->reason = \"Invalid word encountered\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_type_1: {\n    switch (llhttp__internal__c_update_type_1(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_res_http_major;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_type_2: {\n    switch (llhttp__internal__c_update_type(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_start_req;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_pause_8: {\n    state->error = 0x14;\n    state->reason = \"on_message_begin pause\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_n_llhttp__internal__n_invoke_load_type;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_error: {\n    state->error = 0xf;\n    state->reason = \"`on_message_begin` callback error\";\n    state->error_pos = (const char*) p;\n    state->_current = (void*) (intptr_t) s_error;\n    return s_error;\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_llhttp__on_message_begin: {\n    switch (llhttp__on_message_begin(state, p, endp)) {\n      case 0:\n        goto s_n_llhttp__internal__n_invoke_load_type;\n      case 20:\n        goto s_n_llhttp__internal__n_pause_8;\n      default:\n        goto s_n_llhttp__internal__n_error;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n  s_n_llhttp__internal__n_invoke_update_finish: {\n    switch (llhttp__internal__c_update_finish(state, p, endp)) {\n      default:\n        goto s_n_llhttp__internal__n_invoke_llhttp__on_message_begin;\n    }\n    /* UNREACHABLE */;\n    abort();\n  }\n}\n\nint llhttp__internal_execute(llhttp__internal_t* state, const char* p, const char* endp) {\n  llparse_state_t next;\n\n  /* check lingering errors */\n  if (state->error != 0) {\n    return state->error;\n  }\n\n  /* restart spans */\n  if (state->_span_pos0 != NULL) {\n    state->_span_pos0 = (void*) p;\n  }\n  \n  next = llhttp__internal__run(state, (const unsigned char*) p, (const unsigned char*) endp);\n  if (next == s_error) {\n    return state->error;\n  }\n  state->_current = (void*) (intptr_t) next;\n\n  /* execute spans */\n  if (state->_span_pos0 != NULL) {\n    int error;\n  \n    error = ((llhttp__internal__span_cb) state->_span_cb0)(state, state->_span_pos0, (const char*) endp);\n    if (error != 0) {\n      state->error = error;\n      state->error_pos = endp;\n      return error;\n    }\n  }\n  \n  return 0;\n}"
  },
  {
    "path": "llhttp/llhttp.h",
    "content": "#ifndef INCLUDE_LLHTTP_H_\n#define INCLUDE_LLHTTP_H_\n\n#define LLHTTP_VERSION_MAJOR 2\n#define LLHTTP_VERSION_MINOR 0\n#define LLHTTP_VERSION_PATCH 1\n\n#ifndef INCLUDE_LLHTTP_ITSELF_H_\n#define INCLUDE_LLHTTP_ITSELF_H_\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#include <stdint.h>\n\ntypedef struct llhttp__internal_s llhttp__internal_t;\nstruct llhttp__internal_s\n{\n    int32_t _index;\n    void* _span_pos0;\n    void* _span_cb0;\n    int32_t error;\n    const char* reason;\n    const char* error_pos;\n    void* data;\n    void* _current;\n    uint64_t content_length;\n    uint8_t type;\n    uint8_t method;\n    uint8_t http_major;\n    uint8_t http_minor;\n    uint8_t header_state;\n    uint16_t flags;\n    uint8_t upgrade;\n    uint16_t status_code;\n    uint8_t finish;\n    void* settings;\n};\n\nint llhttp__internal_init(llhttp__internal_t* s);\nint llhttp__internal_execute(llhttp__internal_t* s, const char* p, const char* endp);\n\n#ifdef __cplusplus\n}  /* extern \"C\" */\n#endif\n#endif  /* INCLUDE_LLHTTP_ITSELF_H_ */\n\n#ifndef LLLLHTTP_C_HEADERS_\n#define LLLLHTTP_C_HEADERS_\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nenum llhttp_errno\n{\n    HPE_OK = 0,\n    HPE_INTERNAL = 1,\n    HPE_STRICT = 2,\n    HPE_LF_EXPECTED = 3,\n    HPE_UNEXPECTED_CONTENT_LENGTH = 4,\n    HPE_CLOSED_CONNECTION = 5,\n    HPE_INVALID_METHOD = 6,\n    HPE_INVALID_URL = 7,\n    HPE_INVALID_CONSTANT = 8,\n    HPE_INVALID_VERSION = 9,\n    HPE_INVALID_HEADER_TOKEN = 10,\n    HPE_INVALID_CONTENT_LENGTH = 11,\n    HPE_INVALID_CHUNK_SIZE = 12,\n    HPE_INVALID_STATUS = 13,\n    HPE_INVALID_EOF_STATE = 14,\n    HPE_CB_MESSAGE_BEGIN = 15,\n    HPE_CB_HEADERS_COMPLETE = 16,\n    HPE_CB_MESSAGE_COMPLETE = 17,\n    HPE_CB_CHUNK_HEADER = 18,\n    HPE_CB_CHUNK_COMPLETE = 19,\n    HPE_PAUSED = 20,\n    HPE_PAUSED_UPGRADE = 21,\n    HPE_USER = 22\n};\ntypedef enum llhttp_errno llhttp_errno_t;\n\nenum llhttp_flags\n{\n    F_CONNECTION_KEEP_ALIVE = 0x1,\n    F_CONNECTION_CLOSE = 0x2,\n    F_CONNECTION_UPGRADE = 0x4,\n    F_CHUNKED = 0x8,\n    F_UPGRADE = 0x10,\n    F_CONTENT_LENGTH = 0x20,\n    F_SKIPBODY = 0x40,\n    F_TRAILING = 0x80,\n    F_LENIENT = 0x100\n};\ntypedef enum llhttp_flags llhttp_flags_t;\n\nenum llhttp_type\n{\n    HTTP_BOTH = 0,\n    HTTP_REQUEST = 1,\n    HTTP_RESPONSE = 2\n};\ntypedef enum llhttp_type llhttp_type_t;\n\nenum llhttp_finish\n{\n    HTTP_FINISH_SAFE = 0,\n    HTTP_FINISH_SAFE_WITH_CB = 1,\n    HTTP_FINISH_UNSAFE = 2\n};\ntypedef enum llhttp_finish llhttp_finish_t;\n\nenum llhttp_method\n{\n    HTTP_DELETE = 0,\n    HTTP_GET = 1,\n    HTTP_HEAD = 2,\n    HTTP_POST = 3,\n    HTTP_PUT = 4,\n    HTTP_CONNECT = 5,\n    HTTP_OPTIONS = 6,\n    HTTP_TRACE = 7,\n    HTTP_COPY = 8,\n    HTTP_LOCK = 9,\n    HTTP_MKCOL = 10,\n    HTTP_MOVE = 11,\n    HTTP_PROPFIND = 12,\n    HTTP_PROPPATCH = 13,\n    HTTP_SEARCH = 14,\n    HTTP_UNLOCK = 15,\n    HTTP_BIND = 16,\n    HTTP_REBIND = 17,\n    HTTP_UNBIND = 18,\n    HTTP_ACL = 19,\n    HTTP_REPORT = 20,\n    HTTP_MKACTIVITY = 21,\n    HTTP_CHECKOUT = 22,\n    HTTP_MERGE = 23,\n    HTTP_MSEARCH = 24,\n    HTTP_NOTIFY = 25,\n    HTTP_SUBSCRIBE = 26,\n    HTTP_UNSUBSCRIBE = 27,\n    HTTP_PATCH = 28,\n    HTTP_PURGE = 29,\n    HTTP_MKCALENDAR = 30,\n    HTTP_LINK = 31,\n    HTTP_UNLINK = 32,\n    HTTP_SOURCE = 33\n};\ntypedef enum llhttp_method llhttp_method_t;\n\n#define HTTP_ERRNO_MAP(XX) \\\n    XX(0, OK, OK) \\\n    XX(1, INTERNAL, INTERNAL) \\\n    XX(2, STRICT, STRICT) \\\n    XX(3, LF_EXPECTED, LF_EXPECTED) \\\n    XX(4, UNEXPECTED_CONTENT_LENGTH, UNEXPECTED_CONTENT_LENGTH) \\\n    XX(5, CLOSED_CONNECTION, CLOSED_CONNECTION) \\\n    XX(6, INVALID_METHOD, INVALID_METHOD) \\\n    XX(7, INVALID_URL, INVALID_URL) \\\n    XX(8, INVALID_CONSTANT, INVALID_CONSTANT) \\\n    XX(9, INVALID_VERSION, INVALID_VERSION) \\\n    XX(10, INVALID_HEADER_TOKEN, INVALID_HEADER_TOKEN) \\\n    XX(11, INVALID_CONTENT_LENGTH, INVALID_CONTENT_LENGTH) \\\n    XX(12, INVALID_CHUNK_SIZE, INVALID_CHUNK_SIZE) \\\n    XX(13, INVALID_STATUS, INVALID_STATUS) \\\n    XX(14, INVALID_EOF_STATE, INVALID_EOF_STATE) \\\n    XX(15, CB_MESSAGE_BEGIN, CB_MESSAGE_BEGIN) \\\n    XX(16, CB_HEADERS_COMPLETE, CB_HEADERS_COMPLETE) \\\n    XX(17, CB_MESSAGE_COMPLETE, CB_MESSAGE_COMPLETE) \\\n    XX(18, CB_CHUNK_HEADER, CB_CHUNK_HEADER) \\\n    XX(19, CB_CHUNK_COMPLETE, CB_CHUNK_COMPLETE) \\\n    XX(20, PAUSED, PAUSED) \\\n    XX(21, PAUSED_UPGRADE, PAUSED_UPGRADE) \\\n    XX(22, USER, USER) \\\n\n\n#define HTTP_METHOD_MAP(XX) \\\n    XX(0, DELETE, DELETE) \\\n    XX(1, GET, GET) \\\n    XX(2, HEAD, HEAD) \\\n    XX(3, POST, POST) \\\n    XX(4, PUT, PUT) \\\n    XX(5, CONNECT, CONNECT) \\\n    XX(6, OPTIONS, OPTIONS) \\\n    XX(7, TRACE, TRACE) \\\n    XX(8, COPY, COPY) \\\n    XX(9, LOCK, LOCK) \\\n    XX(10, MKCOL, MKCOL) \\\n    XX(11, MOVE, MOVE) \\\n    XX(12, PROPFIND, PROPFIND) \\\n    XX(13, PROPPATCH, PROPPATCH) \\\n    XX(14, SEARCH, SEARCH) \\\n    XX(15, UNLOCK, UNLOCK) \\\n    XX(16, BIND, BIND) \\\n    XX(17, REBIND, REBIND) \\\n    XX(18, UNBIND, UNBIND) \\\n    XX(19, ACL, ACL) \\\n    XX(20, REPORT, REPORT) \\\n    XX(21, MKACTIVITY, MKACTIVITY) \\\n    XX(22, CHECKOUT, CHECKOUT) \\\n    XX(23, MERGE, MERGE) \\\n    XX(24, MSEARCH, M-SEARCH) \\\n    XX(25, NOTIFY, NOTIFY) \\\n    XX(26, SUBSCRIBE, SUBSCRIBE) \\\n    XX(27, UNSUBSCRIBE, UNSUBSCRIBE) \\\n    XX(28, PATCH, PATCH) \\\n    XX(29, PURGE, PURGE) \\\n    XX(30, MKCALENDAR, MKCALENDAR) \\\n    XX(31, LINK, LINK) \\\n    XX(32, UNLINK, UNLINK) \\\n    XX(33, SOURCE, SOURCE) \\\n\n\n\n#ifdef __cplusplus\n}  /* extern \"C\" */\n#endif\n#endif  /* LLLLHTTP_C_HEADERS_ */\n\n#ifndef INCLUDE_LLHTTP_API_H_\n#define INCLUDE_LLHTTP_API_H_\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n#include <stddef.h>\n\ntypedef llhttp__internal_t llhttp_t;\ntypedef struct llhttp_settings_s llhttp_settings_t;\n\ntypedef int (*llhttp_data_cb)(llhttp_t*, const char* at, size_t length);\ntypedef int (*llhttp_cb)(llhttp_t*);\n\nstruct llhttp_settings_s\n{\n    /* Possible return values 0, -1, `HPE_PAUSED` */\n    llhttp_cb      on_message_begin;\n\n    llhttp_data_cb on_url;\n    llhttp_data_cb on_status;\n    llhttp_data_cb on_header_field;\n    llhttp_data_cb on_header_value;\n\n    /* Possible return values:\n     * 0  - Proceed normally\n     * 1  - Assume that request/response has no body, and proceed to parsing the\n     *      next message\n     * 2  - Assume absence of body (as above) and make `llhttp_execute()` return\n     *      `HPE_PAUSED_UPGRADE`\n     * -1 - Error\n     * `HPE_PAUSED`\n     */\n    llhttp_cb      on_headers_complete;\n\n    llhttp_data_cb on_body;\n\n    /* Possible return values 0, -1, `HPE_PAUSED` */\n    llhttp_cb      on_message_complete;\n\n    /* When on_chunk_header is called, the current chunk length is stored\n     * in parser->content_length.\n     * Possible return values 0, -1, `HPE_PAUSED`\n     */\n    llhttp_cb      on_chunk_header;\n    llhttp_cb      on_chunk_complete;\n};\n\n/* Initialize the parser with specific type and user settings */\nvoid llhttp_init(llhttp_t* parser, llhttp_type_t type,\n                 const llhttp_settings_t* settings);\n\n/* Initialize the settings object */\nvoid llhttp_settings_init(llhttp_settings_t* settings);\n\n/* Parse full or partial request/response, invoking user callbacks along the\n * way.\n *\n * If any of `llhttp_data_cb` returns errno not equal to `HPE_OK` - the parsing\n * interrupts, and such errno is returned from `llhttp_execute()`. If\n * `HPE_PAUSED` was used as a errno, the execution can be resumed with\n * `llhttp_resume()` call.\n *\n * In a special case of CONNECT/Upgrade request/response `HPE_PAUSED_UPGRADE`\n * is returned after fully parsing the request/response. If the user wishes to\n * continue parsing, they need to invoke `llhttp_resume_after_upgrade()`.\n *\n * NOTE: if this function ever returns a non-pause type error, it will continue\n * to return the same error upon each successive call up until `llhttp_init()`\n * is called.\n */\nllhttp_errno_t llhttp_execute(llhttp_t* parser, const char* data, size_t len);\n\n/* This method should be called when the other side has no further bytes to\n * send (e.g. shutdown of readable side of the TCP connection.)\n *\n * Requests without `Content-Length` and other messages might require treating\n * all incoming bytes as the part of the body, up to the last byte of the\n * connection. This method will invoke `on_message_complete()` callback if the\n * request was terminated safely. Otherwise a error code would be returned.\n */\nllhttp_errno_t llhttp_finish(llhttp_t* parser);\n\n/* Returns `1` if the incoming message is parsed until the last byte, and has\n * to be completed by calling `llhttp_finish()` on EOF\n */\nint llhttp_message_needs_eof(const llhttp_t* parser);\n\n/* Returns `1` if there might be any other messages following the last that was\n * successfully parsed.\n */\nint llhttp_should_keep_alive(const llhttp_t* parser);\n\n/* Make further calls of `llhttp_execute()` return `HPE_PAUSED` and set\n * appropriate error reason.\n *\n * Important: do not call this from user callbacks! User callbacks must return\n * `HPE_PAUSED` if pausing is required.\n */\nvoid llhttp_pause(llhttp_t* parser);\n\n/* Might be called to resume the execution after the pause in user's callback.\n * See `llhttp_execute()` above for details.\n *\n * Call this only if `llhttp_execute()` returns `HPE_PAUSED`.\n */\nvoid llhttp_resume(llhttp_t* parser);\n\n/* Might be called to resume the execution after the pause in user's callback.\n * See `llhttp_execute()` above for details.\n *\n * Call this only if `llhttp_execute()` returns `HPE_PAUSED_UPGRADE`\n */\nvoid llhttp_resume_after_upgrade(llhttp_t* parser);\n\n/* Returns the latest return error */\nllhttp_errno_t llhttp_get_errno(const llhttp_t* parser);\n\n/* Returns the verbal explanation of the latest returned error.\n *\n * Note: User callback should set error reason when returning the error. See\n * `llhttp_set_error_reason()` for details.\n */\nconst char* llhttp_get_error_reason(const llhttp_t* parser);\n\n/* Assign verbal description to the returned error. Must be called in user\n * callbacks right before returning the errno.\n *\n * Note: `HPE_USER` error code might be useful in user callbacks.\n */\nvoid llhttp_set_error_reason(llhttp_t* parser, const char* reason);\n\n/* Returns the pointer to the last parsed byte before the returned error. The\n * pointer is relative to the `data` argument of `llhttp_execute()`.\n *\n * Note: this method might be useful for counting the number of parsed bytes.\n */\nconst char* llhttp_get_error_pos(const llhttp_t* parser);\n\n/* Returns textual name of error code */\nconst char* llhttp_errno_name(llhttp_errno_t err);\n\n/* Returns textual name of HTTP method */\nconst char* llhttp_method_name(llhttp_method_t method);\n\n\n/* Enables/disables lenient header value parsing (disabled by default).\n *\n * Lenient parsing disables header value token checks, extending llhttp's\n * protocol support to highly non-compliant clients/server. No\n * `HPE_INVALID_HEADER_TOKEN` will be raised for incorrect header values when\n * lenient parsing is \"on\".\n *\n * **(USE AT YOUR OWN RISK)**\n */\nvoid llhttp_set_lenient(llhttp_t* parser, int enabled);\n\n#ifdef __cplusplus\n}  /* extern \"C\" */\n#endif\n#endif  /* INCLUDE_LLHTTP_API_H_ */\n\n#endif  /* INCLUDE_LLHTTP_H_ */\n"
  },
  {
    "path": "multipart-parser/.gitignore",
    "content": "*.o\n"
  },
  {
    "path": "multipart-parser/CMakeLists.txt",
    "content": "project(multipart_parser)\n\naux_source_directory(. MMPART_PARSER_SRC_FILES)\n\ninclude_directories(.)\n\nif(_DAQI_TARGET_TYPE_ STREQUAL \"SHARED_LIB\")    \n    add_compile_options(-fPIC)\nendif()\n\nadd_library(${PROJECT_NAME} STATIC ${MMPART_PARSER_SRC_FILES})        \nset_target_properties (${PROJECT_NAME} PROPERTIES DEBUG_POSTFIX _d)\n"
  },
  {
    "path": "multipart-parser/README.md",
    "content": "## Multipart form data parser\n\n### Features\n* No dependencies\n* Works with chunks of a data - no need to buffer the whole request\n* Almost no internal buffering. Buffer size doesn't exceed the size of the boundary (~60-70 bytes)\n\nTested as part of [Cosmonaut](https://github.com/iafonov/cosmonaut) HTTP server.\n\nImplementation based on [node-formidable](https://github.com/felixge/node-formidable) by [Felix Geisendörfer](https://github.com/felixge).\n\nInspired by [http-parser](https://github.com/joyent/http-parser) by [Ryan Dahl](https://github.com/ry).\n\n### Usage (C)\nThis parser library works with several callbacks, which the user may set up at application initialization time.\n\n```c\nmultipart_parser_settings callbacks;\n\nmemset(&callbacks, 0, sizeof(multipart_parser_settings));\n\ncallbacks.on_header_field = read_header_name;\ncallbacks.on_header_value = read_header_value;\n```\n\nThese functions must match the signatures defined in the multipart-parser header file.  For this simple example, we'll just use two of the available callbacks to print all headers the library finds in multipart messages.\n\nReturning a value other than 0 from the callbacks will abort message processing.\n\n```c\nint read_header_name(multipart_parser* p, const char *at, size_t length)\n{\n   printf(\"%.*s: \", length, at);\n   return 0;\n}\n\nint read_header_value(multipart_parser* p, const char *at, size_t length)\n{\n   printf(\"%.*s\\n\", length, at);\n   return 0;\n}\n```\n\nWhen a message arrives, callers must parse the multipart boundary from the **Content-Type** header (see the [RFC](http://tools.ietf.org/html/rfc2387#section-5.1) for more information and examples), and then execute the parser.\n\n```c\nmultipart_parser* parser = multipart_parser_init(boundary, &callbacks);\nmultipart_parser_execute(parser, body, length);\nmultipart_parser_free(parser);\n```\n\n### Usage (C++)\nIn C++, when the callbacks are static member functions it may be helpful to pass the instantiated multipart consumer along as context.  The following (abbreviated) class called `MultipartConsumer` shows how to pass `this` to callback functions in order to access non-static member data.\n\n```cpp\nclass MultipartConsumer\n{\npublic:\n    MultipartConsumer(const std::string& boundary)\n    {\n        memset(&m_callbacks, 0, sizeof(multipart_parser_settings));\n        m_callbacks.on_header_field = ReadHeaderName;\n        m_callbacks.on_header_value = ReadHeaderValue;\n\n        m_parser = multipart_parser_init(boundary.c_str(), &m_callbacks);\n        multipart_parser_set_data(m_parser, this);\n    }\n\n    ~MultipartConsumer()\n    {\n        multipart_parser_free(m_parser);\n    }\n\n    int CountHeaders(const std::string& body)\n    {\n        multipart_parser_execute(m_parser, body.c_str(), body.size());\n        return m_headers;\n    }\n\nprivate:\n    static int ReadHeaderName(multipart_parser* p, const char *at, size_t length)\n    {\n        MultipartConsumer* me = (MultipartConsumer*)multipart_parser_get_data(p);\n        me->m_headers++;\n    }\n\n    multipart_parser* m_parser;\n    multipart_parser_settings m_callbacks;\n    int m_headers;\n};\n```\n\n### Contributors\n* [Daniel T. Wagner](http://www.danieltwagner.de/)\n* [James McLaughlin](http://udp.github.com/)\n* [Jay Miller](http://www.cryptofreak.org)\n\n© 2012 [Igor Afonov](http://iafonov.github.com)\n"
  },
  {
    "path": "multipart-parser/multipart_parser.c",
    "content": "/* Based on node-formidable by Felix Geisendörfer \n * Igor Afonov - afonov@gmail.com - 2012\n * MIT License - http://www.opensource.org/licenses/mit-license.php\n */\n\n#include \"multipart_parser.h\"\n\n#include <stdio.h>\n#include <stdarg.h>\n#include <string.h>\n\nstatic void multipart_log(const char * format, ...)\n{\n#ifdef DEBUG_MULTIPART\n    va_list args;\n    va_start(args, format);\n\n    fprintf(stderr, \"[HTTP_MULTIPART_PARSER] %s:%d: \", __FILE__, __LINE__);\n    vfprintf(stderr, format, args);\n    fprintf(stderr, \"\\n\");\n#endif\n}\n\n#define NOTIFY_CB(FOR)                                                 \\\ndo {                                                                   \\\n  if (p->settings->on_##FOR) {                                         \\\n    if (p->settings->on_##FOR(p) != 0) {                               \\\n      return i;                                                        \\\n    }                                                                  \\\n  }                                                                    \\\n} while (0)\n\n#define EMIT_DATA_CB(FOR, ptr, len)                                    \\\ndo {                                                                   \\\n  if (p->settings->on_##FOR) {                                         \\\n    if (p->settings->on_##FOR(p, ptr, len) != 0) {                     \\\n      return i;                                                        \\\n    }                                                                  \\\n  }                                                                    \\\n} while (0)\n\n\n#define LF 10\n#define CR 13\n\nstruct multipart_parser {\n  void * data;\n\n  size_t index;\n  size_t boundary_length;\n\n  unsigned char state;\n\n  const multipart_parser_settings* settings;\n\n  char* lookbehind;\n  char multipart_boundary[1];\n};\n\nenum state {\n  s_uninitialized = 1,\n  s_start,\n  s_start_boundary,\n  s_header_field_start,\n  s_header_field,\n  s_headers_almost_done,\n  s_header_value_start,\n  s_header_value,\n  s_header_value_almost_done,\n  s_part_data_start,\n  s_part_data,\n  s_part_data_almost_boundary,\n  s_part_data_boundary,\n  s_part_data_almost_end,\n  s_part_data_end,\n  s_part_data_final_hyphen,\n  s_end\n};\n\nmultipart_parser* multipart_parser_init\n    (const char *boundary, const multipart_parser_settings* settings) {\n\n  multipart_parser* p = malloc(sizeof(multipart_parser) +\n                               strlen(boundary) +\n                               strlen(boundary) + 9);\n\n  strcpy(p->multipart_boundary, boundary);\n  p->boundary_length = strlen(boundary);\n  \n  p->lookbehind = (p->multipart_boundary + p->boundary_length + 1);\n\n  p->index = 0;\n  p->state = s_start;\n  p->settings = settings;\n\n  return p;\n}\n\nvoid multipart_parser_free(multipart_parser* p) {\n  free(p);\n}\n\nvoid multipart_parser_set_data(multipart_parser *p, void *data) {\n    p->data = data;\n}\n\nvoid *multipart_parser_get_data(multipart_parser *p) {\n    return p->data;\n}\n\nsize_t multipart_parser_execute(multipart_parser* p, const char *buf, size_t len) {\n  size_t i = 0;\n  size_t mark = 0;\n  char c, cl;\n  int is_last = 0;\n\n  while(i < len) {\n    c = buf[i];\n    is_last = (i == (len - 1));\n    switch (p->state) {\n      case s_start:\n        multipart_log(\"s_start\");\n        p->index = 0;\n        p->state = s_start_boundary;\n\n      /* fallthrough */\n      case s_start_boundary:\n        multipart_log(\"s_start_boundary\");\n        if (p->index == p->boundary_length) {\n          if (c != CR) {\n            return i;\n          }\n          p->index++;\n          break;\n        } else if (p->index == (p->boundary_length + 1)) {\n          if (c != LF) {\n            return i;\n          }\n          p->index = 0;\n          NOTIFY_CB(part_data_begin);\n          p->state = s_header_field_start;\n          break;\n        }\n        if (c != p->multipart_boundary[p->index]) {\n          return i;\n        }\n        p->index++;\n        break;\n\n      case s_header_field_start:\n        multipart_log(\"s_header_field_start\");\n        mark = i;\n        p->state = s_header_field;\n\n      /* fallthrough */\n      case s_header_field:\n        multipart_log(\"s_header_field\");\n        if (c == CR) {\n          p->state = s_headers_almost_done;\n          break;\n        }\n\n        if (c == ':') {\n          EMIT_DATA_CB(header_field, buf + mark, i - mark);\n          p->state = s_header_value_start;\n          break;\n        }\n\n        cl = tolower(c);\n        if ((c != '-') && (cl < 'a' || cl > 'z')) {\n          multipart_log(\"invalid character in header name\");\n          return i;\n        }\n        if (is_last)\n            EMIT_DATA_CB(header_field, buf + mark, (i - mark) + 1);\n        break;\n\n      case s_headers_almost_done:\n        multipart_log(\"s_headers_almost_done\");\n        if (c != LF) {\n          return i;\n        }\n\n        p->state = s_part_data_start;\n        break;\n\n      case s_header_value_start:\n        multipart_log(\"s_header_value_start\");\n        if (c == ' ') {\n          break;\n        }\n\n        mark = i;\n        p->state = s_header_value;\n\n      /* fallthrough */\n      case s_header_value:\n        multipart_log(\"s_header_value\");\n        if (c == CR) {\n          EMIT_DATA_CB(header_value, buf + mark, i - mark);\n          p->state = s_header_value_almost_done;\n          break;\n        }\n        if (is_last)\n            EMIT_DATA_CB(header_value, buf + mark, (i - mark) + 1);\n        break;\n\n      case s_header_value_almost_done:\n        multipart_log(\"s_header_value_almost_done\");\n        if (c != LF) {\n          return i;\n        }\n        p->state = s_header_field_start;\n        break;\n\n      case s_part_data_start:\n        multipart_log(\"s_part_data_start\");\n        NOTIFY_CB(headers_complete);\n        mark = i;\n        p->state = s_part_data;\n\n      /* fallthrough */\n      case s_part_data:\n        multipart_log(\"s_part_data\");\n        if (c == CR) {\n            EMIT_DATA_CB(part_data, buf + mark, i - mark);\n            mark = i;\n            p->state = s_part_data_almost_boundary;\n            p->lookbehind[0] = CR;\n            break;\n        }\n        if (is_last)\n            EMIT_DATA_CB(part_data, buf + mark, (i - mark) + 1);\n        break;\n\n      case s_part_data_almost_boundary:\n        multipart_log(\"s_part_data_almost_boundary\");\n        if (c == LF) {\n            p->state = s_part_data_boundary;\n            p->lookbehind[1] = LF;\n            p->index = 0;\n            break;\n        }\n        EMIT_DATA_CB(part_data, p->lookbehind, 1);\n        p->state = s_part_data;\n        mark = i --;\n        break;\n\n      case s_part_data_boundary:\n        multipart_log(\"s_part_data_boundary\");\n        if (p->multipart_boundary[p->index] != c) {\n          EMIT_DATA_CB(part_data, p->lookbehind, 2 + p->index);\n          p->state = s_part_data;\n          mark = i --;\n          break;\n        }\n        p->lookbehind[2 + p->index] = c;\n        if ((++ p->index) == p->boundary_length) {\n            NOTIFY_CB(part_data_end);\n            p->state = s_part_data_almost_end;\n        }\n        break;\n\n      case s_part_data_almost_end:\n        multipart_log(\"s_part_data_almost_end\");\n        if (c == '-') {\n            p->state = s_part_data_final_hyphen;\n            break;\n        }\n        if (c == CR) {\n            p->state = s_part_data_end;\n            break;\n        }\n        return i;\n   \n      case s_part_data_final_hyphen:\n        multipart_log(\"s_part_data_final_hyphen\");\n        if (c == '-') {\n            NOTIFY_CB(body_end);\n            p->state = s_end;\n            break;\n        }\n        return i;\n\n      case s_part_data_end:\n        multipart_log(\"s_part_data_end\");\n        if (c == LF) {\n            p->state = s_header_field_start;\n            NOTIFY_CB(part_data_begin);\n            break;\n        }\n        return i;\n\n      case s_end:\n        multipart_log(\"s_end: %02X\", (int) c);\n        break;\n\n      default:\n        multipart_log(\"Multipart parser unrecoverable error\");\n        return 0;\n    }\n    ++ i;\n  }\n\n  return len;\n}\n"
  },
  {
    "path": "multipart-parser/multipart_parser.h",
    "content": "/* Based on node-formidable by Felix Geisendörfer \n * Igor Afonov - afonov@gmail.com - 2012\n * MIT License - http://www.opensource.org/licenses/mit-license.php\n */\n#ifndef _multipart_parser_h\n#define _multipart_parser_h\n\n#ifdef __cplusplus\nextern \"C\"\n{\n#endif\n\n#include <stdlib.h>\n#include <ctype.h>\n\ntypedef struct multipart_parser multipart_parser;\ntypedef struct multipart_parser_settings multipart_parser_settings;\ntypedef struct multipart_parser_state multipart_parser_state;\n\ntypedef int (*multipart_data_cb) (multipart_parser*, const char *at, size_t length);\ntypedef int (*multipart_notify_cb) (multipart_parser*);\n\nstruct multipart_parser_settings {\n  multipart_data_cb on_header_field;\n  multipart_data_cb on_header_value;\n  multipart_data_cb on_part_data;\n\n  multipart_notify_cb on_part_data_begin;\n  multipart_notify_cb on_headers_complete;\n  multipart_notify_cb on_part_data_end;\n  multipart_notify_cb on_body_end;\n};\n\nmultipart_parser* multipart_parser_init\n    (const char *boundary, const multipart_parser_settings* settings);\n\nvoid multipart_parser_free(multipart_parser* p);\n\nsize_t multipart_parser_execute(multipart_parser* p, const char *buf, size_t len);\n\nvoid multipart_parser_set_data(multipart_parser* p, void* data);\nvoid * multipart_parser_get_data(multipart_parser* p);\n\n#ifdef __cplusplus\n} /* extern \"C\" */\n#endif\n\n#endif\n"
  },
  {
    "path": "nlohmann_json/.github/CONTRIBUTING.md",
    "content": "[![Issue Stats](http://issuestats.com/github/nlohmann/json/badge/pr?style=flat)](http://issuestats.com/github/nlohmann/json) [![Issue Stats](http://issuestats.com/github/nlohmann/json/badge/issue?style=flat)](http://issuestats.com/github/nlohmann/json)\n\n# How to contribute\n\nThis project started as a little excuse to exercise some of the cool new C++11 features. Over time, people actually started to use the JSON library (yey!) and started to help improve it by proposing features, finding bugs, or even fixing my mistakes. I am really [thankful](https://github.com/nlohmann/json/blob/master/README.md#thanks) for this and try to keep track of all the helpers.\n\nTo make it as easy as possible for you to contribute and for me to keep an overview, here are a few guidelines which should help us avoid all kinds of unnecessary work or disappointment. And of course, this document is subject to discussion, so please [create an issue](https://github.com/nlohmann/json/issues/new) or a pull request if you find a way to improve it!\n\n## Private reports\n\nUsually, all issues are tracked publicly on [GitHub](https://github.com/nlohmann/json/issues). If you want to make a private report (e.g., for a vulnerability or to attach an example that is not meant to be published), please send an email to <mail@nlohmann.me>.\n\n## Prerequisites\n\nPlease [create an issue](https://github.com/nlohmann/json/issues/new), assuming one does not already exist, and describe your concern. Note you need a [GitHub account](https://github.com/signup/free) for this.\n\n## Describe your issue\n\nClearly describe the issue:\n\n- If it is a bug, please describe how to **reproduce** it. If possible, attach a complete example which demonstrates the error. Please also state what you **expected** to happen instead of the error.\n- If you propose a change or addition, try to give an **example** how the improved code could look like or how to use it.\n- If you found a compilation error, please tell us which **compiler** (version and operating system) you used and paste the (relevant part of) the error messages to the ticket.\n\nPlease stick to the [issue template](https://github.com/nlohmann/json/blob/develop/.github/ISSUE_TEMPLATE.md) if possible.\n\n## Files to change\n\n:exclamation: Before you make any changes, note the single-header file [`single_include/nlohmann/json.hpp`](https://github.com/nlohmann/json/blob/develop/single_include/nlohmann/json.hpp) is **generated** from the source files in the [`include/nlohmann` directory](https://github.com/nlohmann/json/tree/develop/include/nlohmann). Please **do not** edit file `single_include/nlohmann/json.hpp` directly, but change the `include/nlohmann` sources and regenerate file `single_include/nlohmann/json.hpp` by executing `make amalgamate`.\n\nTo make changes, you need to edit the following files:\n\n1. [`include/nlohmann/*`](https://github.com/nlohmann/json/tree/develop/include/nlohmann) - These files are the sources of the library. Before testing or creating a pull request, execute `make amalgamate` to regenerate `single_include/nlohmann/json.hpp`.\n\n2. [`test/src/unit-*.cpp`](https://github.com/nlohmann/json/tree/develop/test/src) - These files contain the [Catch](https://github.com/philsquared/Catch) unit tests which currently cover [100 %](https://coveralls.io/github/nlohmann/json) of the library's code.\n\n   If you add or change a feature, please also add a unit test to this file. The unit tests can be compiled and executed with\n\n   ```sh\n   $ mkdir build\n   $ cd build\n   $ cmake ..\n   $ cmake --build .\n   $ ctest\n   ```\n\n   The test cases are also executed with several different compilers on [Travis](https://travis-ci.org/nlohmann/json) once you open a pull request.\n\n\n## Note\n\n- If you open a pull request, the code will be automatically tested with [Valgrind](http://valgrind.org)'s Memcheck tool to detect memory leaks. Please be aware that the execution with Valgrind _may_ in rare cases yield different behavior than running the code directly. This can result in failing unit tests which run successfully without Valgrind.\n- There is a Makefile target `make pretty` which runs [Artistic Style](http://astyle.sourceforge.net) to fix indentation. If possible, run it before opening the pull request. Otherwise, we shall run it afterward.\n\n## Please don't\n\n- The C++11 support varies between different **compilers** and versions. Please note the [list of supported compilers](https://github.com/nlohmann/json/blob/master/README.md#supported-compilers). Some compilers like GCC 4.7 (and earlier), Clang 3.3 (and earlier), or Microsoft Visual Studio 13.0 and earlier are known not to work due to missing or incomplete C++11 support. Please refrain from proposing changes that work around these compiler's limitations with `#ifdef`s or other means.\n- Specifically, I am aware of compilation problems with **Microsoft Visual Studio** (there even is an [issue label](https://github.com/nlohmann/json/issues?utf8=✓&q=label%3A%22visual+studio%22+) for these kind of bugs). I understand that even in 2016, complete C++11 support isn't there yet. But please also understand that I do not want to drop features or uglify the code just to make Microsoft's sub-standard compiler happy. The past has shown that there are ways to express the functionality such that the code compiles with the most recent MSVC - unfortunately, this is not the main objective of the project.\n- Please refrain from proposing changes that would **break [JSON](http://json.org) conformance**. If you propose a conformant extension of JSON to be supported by the library, please motivate this extension.\n  - We shall not extend the library to **support comments**. There is quite some [controversy](https://www.reddit.com/r/programming/comments/4v6chu/why_json_doesnt_support_comments_douglas_crockford/) around this topic, and there were quite some [issues](https://github.com/nlohmann/json/issues/376) on this. We believe that JSON is fine without comments.\n  - We do not preserve the **insertion order of object elements**. The [JSON standard](https://tools.ietf.org/html/rfc7159.html) defines objects as \"an unordered collection of zero or more name/value pairs\". To this end, this library does not preserve insertion order of name/value pairs. (In fact, keys will be traversed in alphabetical order as `std::map` with `std::less` is used by default.) Note this behavior conforms to the standard, and we shall not change it to any other order. If you do want to preserve the insertion order, you can specialize the object type with containers like [`tsl::ordered_map`](https://github.com/Tessil/ordered-map) or [`nlohmann::fifo_map`](https://github.com/nlohmann/fifo_map).\n\n- Please do not open pull requests that address **multiple issues**.\n\n## Wanted\n\nThe following areas really need contribution:\n\n- Extending the **continuous integration** toward more exotic compilers such as Android NDK, Intel's Compiler, or the bleeding-edge versions of GCC or Clang.\n- Improving the efficiency of the **JSON parser**. The current parser is implemented as a naive recursive descent parser with hand coded string handling. More sophisticated approaches like LALR parsers would be really appreciated. That said, parser generators like Bison or ANTLR do not play nice with single-header files -- I really would like to keep the parser inside the `json.hpp` header, and I am not aware of approaches similar to [`re2c`](http://re2c.org) for parsing.\n- Extending and updating existing **benchmarks** to include (the most recent version of) this library. Though efficiency is not everything, speed and memory consumption are very important characteristics for C++ developers, so having proper comparisons would be interesting.\n"
  },
  {
    "path": "nlohmann_json/.github/ISSUE_TEMPLATE/Bug_report.md",
    "content": "---\r\nname: Bug report\r\nabout: Create a report to help us improve\r\n\r\n---\r\n\r\n- What is the issue you have?\r\n\r\n- Please describe the steps to reproduce the issue. Can you provide a small but working code example?\r\n\r\n- What is the expected behavior?\r\n\r\n- And what is the actual behavior instead?\r\n\r\n- Which compiler and operating system are you using? Is it a [supported compiler](https://github.com/nlohmann/json#supported-compilers)?\r\n\r\n- Did you use a released version of the library or the version from the `develop` branch?\r\n\r\n- If you experience a compilation error: can you [compile and run the unit tests](https://github.com/nlohmann/json#execute-unit-tests)?\r\n"
  },
  {
    "path": "nlohmann_json/.github/ISSUE_TEMPLATE/Feature_request.md",
    "content": "---\r\nname: Feature request\r\nabout: Suggest an idea for this project\r\n\r\n---\r\n\r\n- Describe the feature in as much detail as possible.\r\n\r\n- Include sample usage where appropriate.\r\n"
  },
  {
    "path": "nlohmann_json/.github/PULL_REQUEST_TEMPLATE.md",
    "content": "[Describe your pull request here. Please read the text below the line, and make sure you follow the checklist.]\n\n* * *\n\n## Pull request checklist\n\nRead the [Contribution Guidelines](https://github.com/nlohmann/json/blob/develop/.github/CONTRIBUTING.md) for detailed information.\n\n- [ ]  Changes are described in the pull request, or an [existing issue is referenced](https://github.com/nlohmann/json/issues).\n- [ ]  The test suite [compiles and runs](https://github.com/nlohmann/json/blob/develop/README.md#execute-unit-tests) without error.\n- [ ]  [Code coverage](https://coveralls.io/github/nlohmann/json) is 100%. Test cases can be added by editing the [test suite](https://github.com/nlohmann/json/tree/develop/test/src).\n- [ ]  The source code is amalgamated; that is, after making changes to the sources in the `include/nlohmann` directory, run `make amalgamate` to create the single-header file `single_include/nlohmann/json.hpp`. The whole process is described [here](https://github.com/nlohmann/json/blob/develop/.github/CONTRIBUTING.md#files-to-change).\n\n## Please don't\n\n- The C++11 support varies between different **compilers** and versions. Please note the [list of supported compilers](https://github.com/nlohmann/json/blob/master/README.md#supported-compilers). Some compilers like GCC 4.7 (and earlier), Clang 3.3 (and earlier), or Microsoft Visual Studio 13.0 and earlier are known not to work due to missing or incomplete C++11 support. Please refrain from proposing changes that work around these compiler's limitations with `#ifdef`s or other means.\n- Specifically, I am aware of compilation problems with **Microsoft Visual Studio** (there even is an [issue label](https://github.com/nlohmann/json/issues?utf8=✓&q=label%3A%22visual+studio%22+) for these kind of bugs). I understand that even in 2016, complete C++11 support isn't there yet. But please also understand that I do not want to drop features or uglify the code just to make Microsoft's sub-standard compiler happy. The past has shown that there are ways to express the functionality such that the code compiles with the most recent MSVC - unfortunately, this is not the main objective of the project.\n- Please refrain from proposing changes that would **break [JSON](http://json.org) conformance**. If you propose a conformant extension of JSON to be supported by the library, please motivate this extension.\n- Please do not open pull requests that address **multiple issues**.\n"
  },
  {
    "path": "nlohmann_json/.github/config.yml",
    "content": "# Configuration for sentiment-bot - https://github.com/behaviorbot/sentiment-bot\n\n# *Required* toxicity threshold between 0 and .99 with the higher numbers being the most toxic\n# Anything higher than this threshold will be marked as toxic and commented on\nsentimentBotToxicityThreshold: .7\n\n# *Required* Comment to reply with\nsentimentBotReplyComment: >\n  Please be sure to review the [code of conduct](https://github.com/nlohmann/json/blob/develop/CODE_OF_CONDUCT.md) and be respectful of other users. cc/ @nlohmann\n\n\n# Configuration for request-info - https://github.com/behaviorbot/request-info\n\n# *Required* Comment to reply with\nrequestInfoReplyComment: >\n  We would appreciate it if you could provide us with more info about this issue or pull request! Please check the [issue template](https://github.com/nlohmann/json/blob/develop/.github/ISSUE_TEMPLATE.md) and the [pull request template](https://github.com/nlohmann/json/blob/develop/.github/PULL_REQUEST_TEMPLATE.md).\n\n# *OPTIONAL* Label to be added to Issues and Pull Requests with insufficient information given\nrequestInfoLabelToAdd: \"state: needs more info\"\n"
  },
  {
    "path": "nlohmann_json/.github/stale.yml",
    "content": "# Number of days of inactivity before an issue becomes stale\ndaysUntilStale: 30\n# Number of days of inactivity before a stale issue is closed\ndaysUntilClose: 7\n# Issues with these labels will never be considered stale\nexemptLabels:\n  - pinned\n  - security\n# Label to use when marking an issue as stale\nstaleLabel: \"state: stale\"\n# Comment to post when marking an issue as stale. Set to `false` to disable\nmarkComment: >\n  This issue has been automatically marked as stale because it has not had\n  recent activity. It will be closed if no further activity occurs. Thank you\n  for your contributions.\n# Comment to post when closing a stale issue. Set to `false` to disable\ncloseComment: false\n"
  },
  {
    "path": "nlohmann_json/.travis.yml",
    "content": "#########################\n# project configuration #\n#########################\n\n# C++ project\nlanguage: cpp\n\ndist: trusty\nsudo: required\ngroup: edge\n\n\n###################\n# global settings #\n###################\n\nenv:\n  global:\n   # The next declaration is the encrypted COVERITY_SCAN_TOKEN, created\n   #   via the \"travis encrypt\" command using the project repo's public key\n   - secure: \"m89SSgE+ASLO38rSKx7MTXK3n5NkP9bIx95jwY71YEiuFzib30PDJ/DifKnXxBjvy/AkCGztErQRk/8ZCvq+4HXozU2knEGnL/RUitvlwbhzfh2D4lmS3BvWBGS3N3NewoPBrRmdcvnT0xjOGXxtZaJ3P74TkB9GBnlz/HmKORA=\"\n\n\n################\n# build matrix #\n################\n\nmatrix:\n  include:\n\n  # Valgrind\n  - os: linux\n    compiler: gcc\n    env:\n      - COMPILER=g++-4.9\n      - CMAKE_OPTIONS=-DJSON_Valgrind=ON\n    addons:\n      apt:\n        sources: ['ubuntu-toolchain-r-test']\n        packages: ['g++-4.9', 'valgrind', 'ninja-build']\n\n  # clang sanitizer\n  - os: linux\n    compiler: clang\n    env:\n      - COMPILER=clang++-5.0\n      - CMAKE_OPTIONS=-DJSON_Sanitizer=ON\n    addons:\n      apt:\n        sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-5.0']\n        packages: ['g++-6', 'clang-5.0', 'ninja-build']\n\n  # cppcheck\n  - os: linux\n    compiler: gcc\n    env:\n      - COMPILER=g++-4.9\n      - SPECIAL=cppcheck\n    addons:\n      apt:\n        sources: ['ubuntu-toolchain-r-test']\n        packages: ['g++-4.9', 'cppcheck', 'ninja-build']\n    after_success:\n      - make cppcheck\n\n  # no exceptions\n  - os: linux\n    compiler: gcc\n    env:\n      - COMPILER=g++-4.9\n      - CMAKE_OPTIONS=-DJSON_NoExceptions=ON\n    addons:\n      apt:\n        sources: ['ubuntu-toolchain-r-test']\n        packages: ['g++-4.9', 'ninja-build']\n\n  # check amalgamation\n  - os: linux\n    compiler: gcc\n    env:\n      - COMPILER=g++-4.9\n      - SPECIAL=amalgamation\n      - MULTIPLE_HEADERS=ON\n    addons:\n      apt:\n        sources: ['ubuntu-toolchain-r-test']\n        packages: ['g++-4.9', 'astyle', 'ninja-build']\n    after_success:\n      - make check-amalgamation\n\n  # Coveralls (http://gronlier.fr/blog/2015/01/adding-code-coverage-to-your-c-project/)\n\n  - os: linux\n    compiler: gcc\n    addons:\n      apt:\n        sources: ['ubuntu-toolchain-r-test']\n        packages: ['g++-4.9', 'ninja-build']\n    before_script:\n      - pip install --user cpp-coveralls\n    after_success:\n      - coveralls --build-root test --include include/nlohmann --gcov 'gcov-4.9' --gcov-options '\\-lp'\n    env:\n      - COMPILER=g++-4.9\n      - CMAKE_OPTIONS=-DJSON_Coverage=ON\n      - MULTIPLE_HEADERS=ON\n\n  # Coverity (only for branch coverity_scan)\n\n  - os: linux\n    compiler: clang\n    before_install: echo -n | openssl s_client -connect scan.coverity.com:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' | sudo tee -a /etc/ssl/certs/ca-certificates.crt\n    addons:\n      apt:\n        sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.6']\n        packages: ['g++-6', 'clang-3.6', 'ninja-build']\n      coverity_scan:\n        project:\n          name: \"nlohmann/json\"\n          description: \"Build submitted via Travis CI\"\n        notification_email: niels.lohmann@gmail.com\n        build_command_prepend: \"mkdir coverity_build ; cd coverity_build ; cmake .. ; cd ..\"\n        build_command: \"make -C coverity_build\"\n        branch_pattern: coverity_scan\n    env:\n      - SPECIAL=coverity\n      - COMPILER=clang++-3.6\n\n  # OSX / Clang\n\n  - os: osx\n    osx_image: xcode6.4\n\n  - os: osx\n    osx_image: xcode7.3\n\n  - os: osx\n    osx_image: xcode8\n\n  - os: osx\n    osx_image: xcode8.1\n\n  - os: osx\n    osx_image: xcode8.2\n\n  - os: osx\n    osx_image: xcode8.3\n\n  - os: osx\n    osx_image: xcode9\n\n  - os: osx\n    osx_image: xcode9.1\n\n  - os: osx\n    osx_image: xcode9.2\n\n  - os: osx\n    osx_image: xcode9.3\n\n  - os: osx\n    osx_image: xcode9.4\n\n  - os: osx\n    osx_image: xcode10\n\n  # Linux / GCC\n\n  - os: linux\n    compiler: gcc\n    env: compiler=g++-4.8\n    addons:\n      apt:\n        sources: ['ubuntu-toolchain-r-test']\n        packages: ['g++-4.8', 'ninja-build']\n\n  - os: linux\n    compiler: gcc\n    env: compiler=g++-4.9\n    addons:\n      apt:\n        sources: ['ubuntu-toolchain-r-test']\n        packages: ['g++-4.9', 'ninja-build']\n\n  - os: linux\n    compiler: gcc\n    env: COMPILER=g++-5\n    addons:\n      apt:\n        sources: ['ubuntu-toolchain-r-test']\n        packages: ['g++-5', 'ninja-build']\n\n  - os: linux\n    compiler: gcc\n    env: COMPILER=g++-6\n    addons:\n      apt:\n        sources: ['ubuntu-toolchain-r-test']\n        packages: ['g++-6', 'ninja-build']\n\n  - os: linux\n    compiler: gcc\n    env: COMPILER=g++-7\n    addons:\n      apt:\n        sources: ['ubuntu-toolchain-r-test']\n        packages: ['g++-7', 'ninja-build']\n\n  - os: linux\n    compiler: gcc\n    env: COMPILER=g++-8\n    addons:\n      apt:\n        sources: ['ubuntu-toolchain-r-test']\n        packages: ['g++-8', 'ninja-build']\n\n  - os: linux\n    compiler: gcc\n    env:\n      - COMPILER=g++-8\n      - CXXFLAGS=-std=c++17\n    addons:\n      apt:\n        sources: ['ubuntu-toolchain-r-test']\n        packages: ['g++-8', 'ninja-build']\n\n  # Linux / Clang\n\n  - os: linux\n    compiler: clang\n    env: COMPILER=clang++-3.5\n    addons:\n      apt:\n        sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.5']\n        packages: ['g++-6', 'clang-3.5', 'ninja-build']\n\n  - os: linux\n    compiler: clang\n    env: COMPILER=clang++-3.6\n    addons:\n      apt:\n        sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.6']\n        packages: ['g++-6', 'clang-3.6', 'ninja-build']\n\n  - os: linux\n    compiler: clang\n    env: COMPILER=clang++-3.7\n    addons:\n      apt:\n        sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.7']\n        packages: ['g++-6', 'clang-3.7', 'ninja-build']\n\n  - os: linux\n    compiler: clang\n    env: COMPILER=clang++-3.8\n    addons:\n      apt:\n        sources: ['ubuntu-toolchain-r-test']\n        packages: ['g++-6', 'clang-3.8', 'ninja-build']\n\n  - os: linux\n    compiler: clang\n    env: COMPILER=clang++-3.9\n    addons:\n      apt:\n        sources: ['ubuntu-toolchain-r-test']\n        packages: ['g++-6', 'clang-3.9', 'ninja-build']\n\n  - os: linux\n    compiler: clang\n    env: COMPILER=clang++-4.0\n    addons:\n      apt:\n        sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-4.0']\n        packages: ['g++-6', 'clang-4.0', 'ninja-build']\n\n  - os: linux\n    compiler: clang\n    env: COMPILER=clang++-5.0\n    addons:\n      apt:\n        sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-5.0']\n        packages: ['g++-6', 'clang-5.0', 'ninja-build']\n\n  - os: linux\n    compiler: clang\n    env: COMPILER=clang++-6.0\n    addons:\n      apt:\n        sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-6.0']\n        packages: ['g++-6', 'clang-6.0', 'ninja-build']\n\n  - os: linux\n    compiler: clang\n    env:\n      - COMPILER=clang++-6.0\n      - CXXFLAGS=-std=c++1z\n    addons:\n      apt:\n        sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-6.0']\n        packages: ['g++-6', 'clang-6.0', 'ninja-build']\n\n################\n# build script #\n################\n\nscript:\n  # get CMake and Ninja (only for systems with brew - macOS)\n  - |\n     if [[ (-x $(which brew)) ]]; then\n       brew update\n       brew install cmake ninja\n       brew upgrade cmake\n       cmake --version\n     fi\n\n  # make sure CXX is correctly set\n  - if [[ \"${COMPILER}\" != \"\" ]]; then export CXX=${COMPILER}; fi\n  # by default, use the single-header version\n  - if [[ \"${MULTIPLE_HEADERS}\" == \"\" ]]; then export MULTIPLE_HEADERS=OFF; fi\n\n  # show OS/compiler version\n  - uname -a\n  - $CXX --version\n\n  # compile and execute unit tests\n  - mkdir -p build && cd build\n  - cmake .. ${CMAKE_OPTIONS} -DJSON_MultipleHeaders=${MULTIPLE_HEADERS} -GNinja && cmake --build . --config Release\n  - ctest -C Release -V -j\n  - cd ..\n\n  # check if homebrew works (only checks develop branch)   \n  - if [ `which brew` ]; then   \n    brew update ;   \n    brew tap nlohmann/json ;    \n    brew install nlohmann_json --HEAD ;    \n    brew test nlohmann_json ;    \n    fi\n"
  },
  {
    "path": "nlohmann_json/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.8)\n\n##\n## PROJECT\n## name and version\n##\nproject(nlohmann_json VERSION 3.5.0 LANGUAGES CXX)\n\n##\n## INCLUDE\n##\n##\ninclude(ExternalProject)\n\n##\n## OPTIONS\n##\noption(JSON_BuildTests \"Build the unit tests when BUILD_TESTING is enabled.\" ON)\noption(JSON_MultipleHeaders \"Use non-amalgamated version of the library.\" OFF)\n\n##\n## CONFIGURATION\n##\nset(NLOHMANN_JSON_TARGET_NAME               ${PROJECT_NAME})\nset(NLOHMANN_JSON_CONFIG_INSTALL_DIR        \"lib/cmake/${PROJECT_NAME}\"\n  CACHE INTERNAL \"\")\nset(NLOHMANN_JSON_INCLUDE_INSTALL_DIR       \"include\")\nset(NLOHMANN_JSON_TARGETS_EXPORT_NAME       \"${PROJECT_NAME}Targets\")\nset(NLOHMANN_JSON_CMAKE_CONFIG_TEMPLATE     \"cmake/config.cmake.in\")\nset(NLOHMANN_JSON_CMAKE_CONFIG_DIR          \"${CMAKE_CURRENT_BINARY_DIR}\")\nset(NLOHMANN_JSON_CMAKE_VERSION_CONFIG_FILE \"${NLOHMANN_JSON_CMAKE_CONFIG_DIR}/${PROJECT_NAME}ConfigVersion.cmake\")\nset(NLOHMANN_JSON_CMAKE_PROJECT_CONFIG_FILE \"${NLOHMANN_JSON_CMAKE_CONFIG_DIR}/${PROJECT_NAME}Config.cmake\")\nset(NLOHMANN_JSON_CMAKE_PROJECT_TARGETS_FILE \"${NLOHMANN_JSON_CMAKE_CONFIG_DIR}/${PROJECT_NAME}Targets.cmake\")\n\nif (JSON_MultipleHeaders)\n    set(NLOHMANN_JSON_INCLUDE_BUILD_DIR \"${PROJECT_SOURCE_DIR}/include/\")\n    message(STATUS \"Using the multi-header code from ${NLOHMANN_JSON_INCLUDE_BUILD_DIR}\")\nelse()\n    set(NLOHMANN_JSON_INCLUDE_BUILD_DIR \"${PROJECT_SOURCE_DIR}/single_include/\")\n    message(STATUS \"Using the single-header code from ${NLOHMANN_JSON_INCLUDE_BUILD_DIR}\")\nendif()\n\n##\n## TARGET\n## create target and add include path\n##\nadd_library(${NLOHMANN_JSON_TARGET_NAME} INTERFACE)\nadd_library(${PROJECT_NAME}::${NLOHMANN_JSON_TARGET_NAME} ALIAS ${NLOHMANN_JSON_TARGET_NAME})\ntarget_compile_features(${NLOHMANN_JSON_TARGET_NAME} INTERFACE cxx_std_11)\n\ntarget_include_directories(\n    ${NLOHMANN_JSON_TARGET_NAME}\n    INTERFACE\n    $<BUILD_INTERFACE:${NLOHMANN_JSON_INCLUDE_BUILD_DIR}>\n    $<INSTALL_INTERFACE:include>\n)\n\n## add debug view definition file for msvc (natvis)\nif (MSVC)\n    set(NLOHMANN_ADD_NATVIS TRUE)\n    set(NLOHMANN_NATVIS_FILE \"nlohmann_json.natvis\")\n    target_sources(\n        ${NLOHMANN_JSON_TARGET_NAME}\n        INTERFACE\n            $<INSTALL_INTERFACE:${NLOHMANN_NATVIS_FILE}>\n            $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/${NLOHMANN_NATVIS_FILE}>\n    )\nendif()\n\n##\n## TESTS\n## create and configure the unit test target\n##\ninclude(CTest) #adds option BUILD_TESTING (default ON)\n\nif(BUILD_TESTING AND JSON_BuildTests)\n    enable_testing()\n    add_subdirectory(test)\nendif()\n\n##\n## INSTALL\n## install header files, generate and install cmake config files for find_package()\n##\ninclude(CMakePackageConfigHelpers)\nwrite_basic_package_version_file(\n    ${NLOHMANN_JSON_CMAKE_VERSION_CONFIG_FILE} COMPATIBILITY SameMajorVersion\n)\nconfigure_file(\n    ${NLOHMANN_JSON_CMAKE_CONFIG_TEMPLATE}\n    ${NLOHMANN_JSON_CMAKE_PROJECT_CONFIG_FILE}\n    @ONLY\n)\n\ninstall(\n    DIRECTORY ${NLOHMANN_JSON_INCLUDE_BUILD_DIR}\n    DESTINATION ${NLOHMANN_JSON_INCLUDE_INSTALL_DIR}\n)\ninstall(\n    FILES ${NLOHMANN_JSON_CMAKE_PROJECT_CONFIG_FILE} ${NLOHMANN_JSON_CMAKE_VERSION_CONFIG_FILE}\n    DESTINATION ${NLOHMANN_JSON_CONFIG_INSTALL_DIR}\n)\nif (NLOHMANN_ADD_NATVIS)\n    install(\n        FILES ${NLOHMANN_NATVIS_FILE}\n        DESTINATION .\n)\nendif()\nexport(\n    TARGETS ${NLOHMANN_JSON_TARGET_NAME}\n    NAMESPACE ${PROJECT_NAME}::\n    FILE ${NLOHMANN_JSON_CMAKE_PROJECT_TARGETS_FILE}\n)\ninstall(\n    TARGETS ${NLOHMANN_JSON_TARGET_NAME}\n    EXPORT ${NLOHMANN_JSON_TARGETS_EXPORT_NAME}\n    INCLUDES DESTINATION ${NLOHMANN_JSON_INCLUDE_INSTALL_DIR}\n)\ninstall(\n    EXPORT ${NLOHMANN_JSON_TARGETS_EXPORT_NAME}\n    NAMESPACE ${PROJECT_NAME}::\n    DESTINATION ${NLOHMANN_JSON_CONFIG_INSTALL_DIR}\n)\n"
  },
  {
    "path": "nlohmann_json/CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.\n\n## Our Standards\n\nExamples of behavior that contributes to creating a positive environment include:\n\n* Using welcoming and inclusive language\n* Being respectful of differing viewpoints and experiences\n* Gracefully accepting constructive criticism\n* Focusing on what is best for the community\n* Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n* The use of sexualized language or imagery and unwelcome sexual attention or advances\n* Trolling, insulting/derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or electronic address, without explicit permission\n* Other conduct which could reasonably be considered inappropriate in a professional setting\n\n## Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.\n\n## Scope\n\nThis Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at mail@nlohmann.me. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]\n\n[homepage]: http://contributor-covenant.org\n[version]: http://contributor-covenant.org/version/1/4/\n"
  },
  {
    "path": "nlohmann_json/ChangeLog.md",
    "content": "# Change Log\nAll notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/).\n\n## [v3.5.0](https://github.com/nlohmann/json/releases/tag/v3.5.0) (2018-12-21)\n[Full Changelog](https://github.com/nlohmann/json/compare/v3.4.0...v3.5.0)\n\n- Copyconstructor inserts original into array with single element [\\#1397](https://github.com/nlohmann/json/issues/1397)\n- Get value without explicit typecasting [\\#1395](https://github.com/nlohmann/json/issues/1395)\n- Big file parsing [\\#1393](https://github.com/nlohmann/json/issues/1393)\n- some static analysis warning at line 11317 [\\#1390](https://github.com/nlohmann/json/issues/1390)\n- Adding Structured Binding Support [\\#1388](https://github.com/nlohmann/json/issues/1388)\n- map\\<json::value\\_t, string\\> exhibits unexpected behavior [\\#1387](https://github.com/nlohmann/json/issues/1387)\n- Error Code Return [\\#1386](https://github.com/nlohmann/json/issues/1386)\n- using unordered\\_map as object type [\\#1385](https://github.com/nlohmann/json/issues/1385)\n- float precision [\\#1384](https://github.com/nlohmann/json/issues/1384)\n- \\[json.exception.type\\_error.316\\] invalid UTF-8 byte at index 1: 0xC3 [\\#1383](https://github.com/nlohmann/json/issues/1383)\n- Inconsistent Constructor \\(GCC vs. Clang\\) [\\#1381](https://github.com/nlohmann/json/issues/1381)\n- \\#define or || [\\#1379](https://github.com/nlohmann/json/issues/1379)\n- How to iterate inside the values ? [\\#1377](https://github.com/nlohmann/json/issues/1377)\n- items\\(\\) unable to get the elements [\\#1375](https://github.com/nlohmann/json/issues/1375)\n- conversion json to std::map doesn't work for types \\<int, double\\>  [\\#1372](https://github.com/nlohmann/json/issues/1372)\n- A minor issue in the build instructions [\\#1371](https://github.com/nlohmann/json/issues/1371)\n- Using this library without stream ? [\\#1370](https://github.com/nlohmann/json/issues/1370)\n- Writing and reading BSON data [\\#1368](https://github.com/nlohmann/json/issues/1368)\n- Retrieving array elements from object type iterator. [\\#1367](https://github.com/nlohmann/json/issues/1367)\n- json::dump\\(\\) silently crashes if items contain accented letters [\\#1365](https://github.com/nlohmann/json/issues/1365)\n- warnings in MSVC \\(2015\\) in 3.4.0 related to bool... [\\#1364](https://github.com/nlohmann/json/issues/1364)\n- Cant compile with -C++17 and beyond compiler options [\\#1362](https://github.com/nlohmann/json/issues/1362)\n- json to concrete type conversion through reference or pointer fails [\\#1361](https://github.com/nlohmann/json/issues/1361)\n- the first attributes of JSON string is misplaced  [\\#1360](https://github.com/nlohmann/json/issues/1360)\n- Copy-construct using initializer-list converts objects to arrays [\\#1359](https://github.com/nlohmann/json/issues/1359)\n- About value\\(key, default\\_value\\) and operator\\[\\]\\(key\\)  [\\#1358](https://github.com/nlohmann/json/issues/1358)\n- Problem with printing json response object [\\#1356](https://github.com/nlohmann/json/issues/1356)\n- Serializing pointer segfaults [\\#1355](https://github.com/nlohmann/json/issues/1355)\n- Read `long long int` data as a number. [\\#1354](https://github.com/nlohmann/json/issues/1354)\n- eclipse oxygen in ubuntu get\\<size\\_t\\> is ambiguous  [\\#1353](https://github.com/nlohmann/json/issues/1353)\n- Can't build on Visual Studio 2017 v15.8.9 [\\#1350](https://github.com/nlohmann/json/issues/1350)\n- cannot parse from string? [\\#1349](https://github.com/nlohmann/json/issues/1349)\n- Error: out\\_of\\_range [\\#1348](https://github.com/nlohmann/json/issues/1348)\n- expansion pattern 'CompatibleObjectType' contains no argument packs, with CUDA 10 [\\#1347](https://github.com/nlohmann/json/issues/1347)\n- Unable to update a value for a nested\\(multi-level\\) json file [\\#1344](https://github.com/nlohmann/json/issues/1344)\n- Fails to compile when std::iterator\\_traits is not SFINAE friendly. [\\#1341](https://github.com/nlohmann/json/issues/1341)\n- EOF flag not set on exhausted input streams. [\\#1340](https://github.com/nlohmann/json/issues/1340)\n- Shadowed Member in merge\\_patch [\\#1339](https://github.com/nlohmann/json/issues/1339)\n- Periods/literal dots in keys? [\\#1338](https://github.com/nlohmann/json/issues/1338)\n- Protect macro expansion of commonly defined macros [\\#1337](https://github.com/nlohmann/json/issues/1337)\n- How to validate an input before parsing? [\\#1336](https://github.com/nlohmann/json/issues/1336)\n- Non-verifying dump\\(\\) alternative for debugging/logging needed [\\#1335](https://github.com/nlohmann/json/issues/1335)\n- Improve number-to-string conversion [\\#1334](https://github.com/nlohmann/json/issues/1334)\n- Json Libarary is not responding for me in c++ [\\#1332](https://github.com/nlohmann/json/issues/1332)\n- Question - how to find an object in an array [\\#1331](https://github.com/nlohmann/json/issues/1331)\n- Nesting additional data in json object [\\#1328](https://github.com/nlohmann/json/issues/1328)\n- can to\\_json\\(\\) be defined inside a class? [\\#1324](https://github.com/nlohmann/json/issues/1324)\n- CodeBlocks IDE can't find `json.hpp` header [\\#1318](https://github.com/nlohmann/json/issues/1318)\n- Change json\\_pointer to provide an iterator begin/end/etc, don't use vectors, and also enable string\\_view [\\#1312](https://github.com/nlohmann/json/issues/1312)\n- Xcode - adding it to library  [\\#1300](https://github.com/nlohmann/json/issues/1300)\n- unicode: accept char16\\_t, char32\\_t sequences [\\#1298](https://github.com/nlohmann/json/issues/1298)\n- unicode: char16\\_t\\* is compiler error, but char16\\_t\\[\\] is accepted [\\#1297](https://github.com/nlohmann/json/issues/1297)\n- Dockerfile Project Help Needed [\\#1296](https://github.com/nlohmann/json/issues/1296)\n- Comparisons between large unsigned and negative signed integers [\\#1295](https://github.com/nlohmann/json/issues/1295)\n- CMake alias to `nlohmann::json` [\\#1291](https://github.com/nlohmann/json/issues/1291)\n- Release zips without tests [\\#1285](https://github.com/nlohmann/json/issues/1285)\n- Suggestion to improve value\\(\\) accessors with respect to move semantics [\\#1275](https://github.com/nlohmann/json/issues/1275)\n- separate object\\_t::key\\_type from basic\\_json::key\\_type, and use an allocator which returns object\\_t::key\\_type [\\#1274](https://github.com/nlohmann/json/issues/1274)\n- Is there a nice way to associate external values with json elements? [\\#1256](https://github.com/nlohmann/json/issues/1256)\n- Delete by json\\_pointer [\\#1248](https://github.com/nlohmann/json/issues/1248)\n- Expose lexer, as a StAX parser [\\#1219](https://github.com/nlohmann/json/issues/1219)\n- Subclassing json\\(\\) & error on recursive load [\\#1201](https://github.com/nlohmann/json/issues/1201)\n- Check value for existence by json\\_pointer [\\#1194](https://github.com/nlohmann/json/issues/1194)\n\n- Feature/add file input adapter [\\#1392](https://github.com/nlohmann/json/pull/1392) ([dumarjo](https://github.com/dumarjo))\n-  Added Support for Structured Bindings  [\\#1391](https://github.com/nlohmann/json/pull/1391) ([pratikpc](https://github.com/pratikpc))\n- Link to issue \\#958 broken [\\#1382](https://github.com/nlohmann/json/pull/1382) ([kjpus](https://github.com/kjpus))\n- readme: fix typo [\\#1380](https://github.com/nlohmann/json/pull/1380) ([manu-chroma](https://github.com/manu-chroma))\n- recommend using explicit from JSON conversions [\\#1363](https://github.com/nlohmann/json/pull/1363) ([theodelrieu](https://github.com/theodelrieu))\n- Fix merge\\_patch shadow warning [\\#1346](https://github.com/nlohmann/json/pull/1346) ([ax3l](https://github.com/ax3l))\n- Allow installation via Meson [\\#1345](https://github.com/nlohmann/json/pull/1345) ([mpoquet](https://github.com/mpoquet))\n- Set eofbit on exhausted input stream. [\\#1343](https://github.com/nlohmann/json/pull/1343) ([mefyl](https://github.com/mefyl))\n- Add a SFINAE friendly iterator\\_traits and use that instead. [\\#1342](https://github.com/nlohmann/json/pull/1342) ([davedissian](https://github.com/davedissian))\n- Fix EOL Whitespaces & CMake Spelling [\\#1329](https://github.com/nlohmann/json/pull/1329) ([ax3l](https://github.com/ax3l))\n\n## [v3.4.0](https://github.com/nlohmann/json/releases/tag/v3.4.0) (2018-10-30)\n[Full Changelog](https://github.com/nlohmann/json/compare/v3.3.0...v3.4.0)\n\n- Big uint64\\_t values are serialized wrong [\\#1327](https://github.com/nlohmann/json/issues/1327)\n- \\[Question\\] Efficient check for equivalency? [\\#1325](https://github.com/nlohmann/json/issues/1325)\n- Can't use ifstream and .clear\\(\\) [\\#1321](https://github.com/nlohmann/json/issues/1321)\n- \\[Warning\\] -Wparentheses on line 555 on single\\_include [\\#1319](https://github.com/nlohmann/json/issues/1319)\n- Compilation error using at and find with enum struct [\\#1316](https://github.com/nlohmann/json/issues/1316)\n- Parsing JSON from a web address [\\#1311](https://github.com/nlohmann/json/issues/1311)\n- How to convert JSON to Struct with embeded subject [\\#1310](https://github.com/nlohmann/json/issues/1310)\n- Null safety/coalescing function? [\\#1309](https://github.com/nlohmann/json/issues/1309)\n- Building fails using single include file: json.hpp [\\#1308](https://github.com/nlohmann/json/issues/1308)\n- json::parse\\(std::string\\) Exception inside packaged Lib [\\#1306](https://github.com/nlohmann/json/issues/1306)\n- Problem in Dockerfile with installation of library [\\#1304](https://github.com/nlohmann/json/issues/1304)\n- compile error in from\\_json converting to container with std::pair [\\#1299](https://github.com/nlohmann/json/issues/1299)\n- Json that I am trying to parse, and I am lost Structure Array below top level [\\#1293](https://github.com/nlohmann/json/issues/1293)\n- Serializing std::variant causes stack overflow [\\#1292](https://github.com/nlohmann/json/issues/1292)\n- How do I go about customising from\\_json to support \\_\\_int128\\_t/\\_\\_uint128\\_t? [\\#1290](https://github.com/nlohmann/json/issues/1290)\n- merge\\_patch: inconsistent behaviour merging empty sub-object [\\#1289](https://github.com/nlohmann/json/issues/1289)\n- Buffer over/underrun using UBJson? [\\#1288](https://github.com/nlohmann/json/issues/1288)\n- Enable the latest C++ standard with Visual Studio [\\#1287](https://github.com/nlohmann/json/issues/1287)\n- truncation of constant value in to\\_cbor\\(\\) [\\#1286](https://github.com/nlohmann/json/issues/1286)\n- eosio.wasmsdk error [\\#1284](https://github.com/nlohmann/json/issues/1284)\n- use the same interface for writing arrays and non-arrays [\\#1283](https://github.com/nlohmann/json/issues/1283)\n- How to read json file with optional  entries and entries with different types [\\#1281](https://github.com/nlohmann/json/issues/1281)\n- merge result not as espected [\\#1279](https://github.com/nlohmann/json/issues/1279)\n- how to get only \"name\" from below json [\\#1278](https://github.com/nlohmann/json/issues/1278)\n- syntax error  on right json string [\\#1276](https://github.com/nlohmann/json/issues/1276)\n- Parsing JSON Array where members have no key, using custom types [\\#1267](https://github.com/nlohmann/json/issues/1267)\n- I get a json exception periodically from json::parse for the same json  [\\#1263](https://github.com/nlohmann/json/issues/1263)\n- serialize std::variant\\<...\\> [\\#1261](https://github.com/nlohmann/json/issues/1261)\n- GCC 8.2.1. Compilation error: invalid conversion from... [\\#1246](https://github.com/nlohmann/json/issues/1246)\n- BSON support [\\#1244](https://github.com/nlohmann/json/issues/1244)\n- enum to json mapping [\\#1208](https://github.com/nlohmann/json/issues/1208)\n- Soften the landing when dumping non-UTF8 strings \\(type\\_error.316 exception\\) [\\#1198](https://github.com/nlohmann/json/issues/1198)\n- CMakeLists.txt in release zips? [\\#1184](https://github.com/nlohmann/json/issues/1184)\n- CBOR byte string support [\\#1129](https://github.com/nlohmann/json/issues/1129)\n\n- Add macro to define enum/JSON mapping [\\#1323](https://github.com/nlohmann/json/pull/1323) ([nlohmann](https://github.com/nlohmann))\n- Add BSON support [\\#1320](https://github.com/nlohmann/json/pull/1320) ([nlohmann](https://github.com/nlohmann))\n- Properly convert constants to CharType [\\#1315](https://github.com/nlohmann/json/pull/1315) ([nlohmann](https://github.com/nlohmann))\n- Allow to set error handler for decoding errors [\\#1314](https://github.com/nlohmann/json/pull/1314) ([nlohmann](https://github.com/nlohmann))\n- Add Meson related info to README [\\#1305](https://github.com/nlohmann/json/pull/1305) ([koponomarenko](https://github.com/koponomarenko))\n- Improve diagnostic messages for binary formats [\\#1303](https://github.com/nlohmann/json/pull/1303) ([nlohmann](https://github.com/nlohmann))\n- add new is\\_constructible\\_\\* traits used in from\\_json [\\#1301](https://github.com/nlohmann/json/pull/1301) ([theodelrieu](https://github.com/theodelrieu))\n- add constraints for variadic json\\_ref constructors [\\#1294](https://github.com/nlohmann/json/pull/1294) ([theodelrieu](https://github.com/theodelrieu))\n- Improve diagnostic messages [\\#1282](https://github.com/nlohmann/json/pull/1282) ([nlohmann](https://github.com/nlohmann))\n- Removed linter warnings [\\#1280](https://github.com/nlohmann/json/pull/1280) ([nlohmann](https://github.com/nlohmann))\n- Thirdparty benchmark: Fix Clang detection. [\\#1277](https://github.com/nlohmann/json/pull/1277) ([Lord-Kamina](https://github.com/Lord-Kamina))\n\n## [v3.3.0](https://github.com/nlohmann/json/releases/tag/v3.3.0) (2018-10-05)\n[Full Changelog](https://github.com/nlohmann/json/compare/v3.2.0...v3.3.0)\n\n- When key is not found print the key name into error too [\\#1273](https://github.com/nlohmann/json/issues/1273)\n- Visual Studio 2017 15.8.5 \"conditional expression is constant\" warning on Line 1851 in json.hpp [\\#1268](https://github.com/nlohmann/json/issues/1268)\n- how can we get this working on WSL? [\\#1264](https://github.com/nlohmann/json/issues/1264)\n- Help needed [\\#1259](https://github.com/nlohmann/json/issues/1259)\n- A way to get to a JSON values \"key\" [\\#1258](https://github.com/nlohmann/json/issues/1258)\n- While compiling got 76 errors [\\#1255](https://github.com/nlohmann/json/issues/1255)\n- Two blackslashes on json output file [\\#1253](https://github.com/nlohmann/json/issues/1253)\n- Including nlohmann the badwrong way. [\\#1250](https://github.com/nlohmann/json/issues/1250)\n- how to build with clang? [\\#1247](https://github.com/nlohmann/json/issues/1247)\n- Cmake target\\_link\\_libraries unable to find nlohmann\\_json since version 3.2.0 [\\#1243](https://github.com/nlohmann/json/issues/1243)\n- \\[Question\\] Access to end\\(\\) iterator reference [\\#1242](https://github.com/nlohmann/json/issues/1242)\n- Parsing different json format [\\#1241](https://github.com/nlohmann/json/issues/1241)\n- Parsing Multiple JSON Files [\\#1240](https://github.com/nlohmann/json/issues/1240)\n- Doesn't compile under C++17 [\\#1239](https://github.com/nlohmann/json/issues/1239)\n- Conversion operator for nlohmann::json is not SFINAE friendly [\\#1237](https://github.com/nlohmann/json/issues/1237)\n- Custom deserialization of number\\_float\\_t [\\#1236](https://github.com/nlohmann/json/issues/1236)\n- Move tests to a separate repo [\\#1235](https://github.com/nlohmann/json/issues/1235)\n- deprecated-declarations warnings when compiling tests with GCC 8.2.1. [\\#1233](https://github.com/nlohmann/json/issues/1233)\n- Incomplete type with json\\_fwd.hpp [\\#1232](https://github.com/nlohmann/json/issues/1232)\n- Parse Error [\\#1229](https://github.com/nlohmann/json/issues/1229)\n- json::get function with argument [\\#1227](https://github.com/nlohmann/json/issues/1227)\n- questions regarding from\\_json [\\#1226](https://github.com/nlohmann/json/issues/1226)\n- Lambda in unevaluated context [\\#1225](https://github.com/nlohmann/json/issues/1225)\n- NLohmann doesn't compile when enabling strict warning policies [\\#1224](https://github.com/nlohmann/json/issues/1224)\n- Creating array of objects [\\#1223](https://github.com/nlohmann/json/issues/1223)\n- Somewhat unhelpful error message \"cannot use operator\\[\\] with object\" [\\#1220](https://github.com/nlohmann/json/issues/1220)\n- single\\_include json.hpp [\\#1218](https://github.com/nlohmann/json/issues/1218)\n- Maps with enum class keys which are convertible to JSON strings should be converted to JSON dictionaries [\\#1217](https://github.com/nlohmann/json/issues/1217)\n- Adding JSON Array to the Array  [\\#1216](https://github.com/nlohmann/json/issues/1216)\n- Best way to output a vector of a given type to json [\\#1215](https://github.com/nlohmann/json/issues/1215)\n- compiler warning: double definition of macro JSON\\_INTERNAL\\_CATCH  [\\#1213](https://github.com/nlohmann/json/issues/1213)\n- Compilation error when using MOCK\\_METHOD1 from GMock and nlohmann::json [\\#1212](https://github.com/nlohmann/json/issues/1212)\n- Issues parsing a previously encoded binary \\(non-UTF8\\) string. [\\#1211](https://github.com/nlohmann/json/issues/1211)\n- Yet another ordering question: char \\* and parse\\(\\) [\\#1209](https://github.com/nlohmann/json/issues/1209)\n- Error using gcc 8.1.0 on Ubuntu 14.04 [\\#1207](https://github.com/nlohmann/json/issues/1207)\n- \"type must be string, but is \" std::string\\(j.type\\_name\\(\\)  [\\#1206](https://github.com/nlohmann/json/issues/1206)\n- Returning empty json object from a function of type const json& ? [\\#1205](https://github.com/nlohmann/json/issues/1205)\n- VS2017 compiler suggests using constexpr if [\\#1204](https://github.com/nlohmann/json/issues/1204)\n- Template instatiation error on compiling [\\#1203](https://github.com/nlohmann/json/issues/1203)\n- BUG - json dump field with unicode -\\> array of ints \\(instead of string\\) [\\#1197](https://github.com/nlohmann/json/issues/1197)\n- Compile error using Code::Blocks // mingw-w64 GCC 8.1.0 - \"Incomplete Type\" [\\#1193](https://github.com/nlohmann/json/issues/1193)\n- SEGFAULT on arm target  [\\#1190](https://github.com/nlohmann/json/issues/1190)\n- Compiler crash with old Clang [\\#1179](https://github.com/nlohmann/json/issues/1179)\n- Custom Precision on floating point numbers [\\#1170](https://github.com/nlohmann/json/issues/1170)\n- Can we have a json\\_view class like std::string\\_view? [\\#1158](https://github.com/nlohmann/json/issues/1158)\n- improve error handling [\\#1152](https://github.com/nlohmann/json/issues/1152)\n- We should remove static\\_asserts [\\#960](https://github.com/nlohmann/json/issues/960)\n\n- Fix warning C4127: conditional expression is constant [\\#1272](https://github.com/nlohmann/json/pull/1272) ([antonioborondo](https://github.com/antonioborondo))\n- Turn off additional deprecation warnings for GCC. [\\#1271](https://github.com/nlohmann/json/pull/1271) ([chuckatkins](https://github.com/chuckatkins))\n- docs: Add additional CMake documentation [\\#1270](https://github.com/nlohmann/json/pull/1270) ([chuckatkins](https://github.com/chuckatkins))\n- unit-testsuites.cpp: fix hangup if file not found [\\#1262](https://github.com/nlohmann/json/pull/1262) ([knilch0r](https://github.com/knilch0r))\n- Fix broken cmake imported target alias [\\#1260](https://github.com/nlohmann/json/pull/1260) ([chuckatkins](https://github.com/chuckatkins))\n- GCC 48 [\\#1257](https://github.com/nlohmann/json/pull/1257) ([henryiii](https://github.com/henryiii))\n- Add version and license to meson.build [\\#1252](https://github.com/nlohmann/json/pull/1252) ([koponomarenko](https://github.com/koponomarenko))\n- \\#1179 Reordered the code. It seems to stop clang 3.4.2 in RHEL 7 from crash… [\\#1249](https://github.com/nlohmann/json/pull/1249) ([LEgregius](https://github.com/LEgregius))\n- Use a version check to provide backwards comatible CMake imported target names [\\#1245](https://github.com/nlohmann/json/pull/1245) ([chuckatkins](https://github.com/chuckatkins))\n- Fix issue \\#1237 [\\#1238](https://github.com/nlohmann/json/pull/1238) ([theodelrieu](https://github.com/theodelrieu))\n- Add a get overload taking a parameter. [\\#1231](https://github.com/nlohmann/json/pull/1231) ([theodelrieu](https://github.com/theodelrieu))\n- Move lambda out of unevaluated context [\\#1230](https://github.com/nlohmann/json/pull/1230) ([mandreyel](https://github.com/mandreyel))\n- Remove static asserts [\\#1228](https://github.com/nlohmann/json/pull/1228) ([theodelrieu](https://github.com/theodelrieu))\n- Better error 305 [\\#1221](https://github.com/nlohmann/json/pull/1221) ([rivertam](https://github.com/rivertam))\n- Fix \\#1213 [\\#1214](https://github.com/nlohmann/json/pull/1214) ([simnalamburt](https://github.com/simnalamburt))\n- Export package to allow builds without installing [\\#1202](https://github.com/nlohmann/json/pull/1202) ([dennisfischer](https://github.com/dennisfischer))\n\n## [v3.2.0](https://github.com/nlohmann/json/releases/tag/v3.2.0) (2018-08-20)\n[Full Changelog](https://github.com/nlohmann/json/compare/v3.1.2...v3.2.0)\n\n- Am I doing this wrong? Getting an empty string [\\#1199](https://github.com/nlohmann/json/issues/1199)\n- Incompatible Pointer Type [\\#1196](https://github.com/nlohmann/json/issues/1196)\n- json.exception.type\\_error.316 [\\#1195](https://github.com/nlohmann/json/issues/1195)\n- Strange warnings in Code::Blocks 17.12, GNU GCC [\\#1192](https://github.com/nlohmann/json/issues/1192)\n- \\[Question\\] Current place in code to change floating point resolution [\\#1191](https://github.com/nlohmann/json/issues/1191)\n- Add key name when throwing type error [\\#1189](https://github.com/nlohmann/json/issues/1189)\n- Not able to include in visual studio code? [\\#1188](https://github.com/nlohmann/json/issues/1188)\n- Get an Index or row number of an element [\\#1186](https://github.com/nlohmann/json/issues/1186)\n- reduce repos size [\\#1185](https://github.com/nlohmann/json/issues/1185)\n- Difference between `merge\\_patch` and `update` [\\#1183](https://github.com/nlohmann/json/issues/1183)\n- Is there a way to get an element from a JSON without throwing an exception on failure? [\\#1182](https://github.com/nlohmann/json/issues/1182)\n- to\\_string? [\\#1181](https://github.com/nlohmann/json/issues/1181)\n- How to cache a json object's pointer into a map? [\\#1180](https://github.com/nlohmann/json/issues/1180)\n- Can this library work within a Qt project for Android using Qt Creator? [\\#1178](https://github.com/nlohmann/json/issues/1178)\n- How to get all keys of one object? [\\#1177](https://github.com/nlohmann/json/issues/1177)\n- How can I only parse the first level and get the value as string? [\\#1175](https://github.com/nlohmann/json/issues/1175)\n- I have a query regarding nlohmann::basic\\_json::basic\\_json [\\#1174](https://github.com/nlohmann/json/issues/1174)\n- unordered\\_map with vectors won't convert to json? [\\#1173](https://github.com/nlohmann/json/issues/1173)\n- return json objects from functions [\\#1172](https://github.com/nlohmann/json/issues/1172)\n- Problem when exporting to CBOR [\\#1171](https://github.com/nlohmann/json/issues/1171)\n- Roundtripping null to nullptr does not work [\\#1169](https://github.com/nlohmann/json/issues/1169)\n- MSVC fails to compile std::swap specialization for nlohmann::json [\\#1168](https://github.com/nlohmann/json/issues/1168)\n- Unexpected behaviour of is\\_null - Part II [\\#1167](https://github.com/nlohmann/json/issues/1167)\n- Floating point imprecision [\\#1166](https://github.com/nlohmann/json/issues/1166)\n- Combine json objects into one? [\\#1165](https://github.com/nlohmann/json/issues/1165)\n- Is there any way to know if the object has changed? [\\#1164](https://github.com/nlohmann/json/issues/1164)\n- Value throws on null string [\\#1163](https://github.com/nlohmann/json/issues/1163)\n- Weird template issue in large project [\\#1162](https://github.com/nlohmann/json/issues/1162)\n- \\_json returns a different result vs ::parse [\\#1161](https://github.com/nlohmann/json/issues/1161)\n- Showing difference between two json objects [\\#1160](https://github.com/nlohmann/json/issues/1160)\n- no instance of overloaded function \"std::swap\" matches the specified type\t [\\#1159](https://github.com/nlohmann/json/issues/1159)\n- resize\\(...\\)? [\\#1157](https://github.com/nlohmann/json/issues/1157)\n- Issue with struct nested in class' to\\_json [\\#1155](https://github.com/nlohmann/json/issues/1155)\n- Deserialize std::map with std::nan [\\#1154](https://github.com/nlohmann/json/issues/1154)\n- Parse throwing errors [\\#1149](https://github.com/nlohmann/json/issues/1149)\n- cocoapod integration [\\#1148](https://github.com/nlohmann/json/issues/1148)\n- wstring parsing [\\#1147](https://github.com/nlohmann/json/issues/1147)\n- Is it possible to dump a two-dimensional array to \"\\[\\[null\\],\\[1,2,3\\]\\]\"? [\\#1146](https://github.com/nlohmann/json/issues/1146)\n- Want to write a class member variable and a struct variable \\( this structure is inside the class\\) to the json file [\\#1145](https://github.com/nlohmann/json/issues/1145)\n- Does json support converting an instance of a struct into json string? [\\#1143](https://github.com/nlohmann/json/issues/1143)\n- \\#Most efficient way to search for child parameters \\(recursive find?\\) [\\#1141](https://github.com/nlohmann/json/issues/1141)\n-  could not find to\\_json\\(\\) method in T's namespace [\\#1140](https://github.com/nlohmann/json/issues/1140)\n- chars get treated as JSON numbers not JSON strings [\\#1139](https://github.com/nlohmann/json/issues/1139)\n- How do I count number of objects in array? [\\#1137](https://github.com/nlohmann/json/issues/1137)\n- Serializing a vector of classes? [\\#1136](https://github.com/nlohmann/json/issues/1136)\n- Compile error. Unable convert form nullptr to nullptr&& [\\#1135](https://github.com/nlohmann/json/issues/1135)\n- std::unordered\\_map in struct, serialization [\\#1133](https://github.com/nlohmann/json/issues/1133)\n- dump\\(\\) can't handle umlauts [\\#1131](https://github.com/nlohmann/json/issues/1131)\n- Add a way to get a key reference from the iterator [\\#1127](https://github.com/nlohmann/json/issues/1127)\n- can't not parse \"\\\\“ string [\\#1123](https://github.com/nlohmann/json/issues/1123)\n-  if  json file  contain Internationalization   chars   ,  get  exception [\\#1122](https://github.com/nlohmann/json/issues/1122)\n- How to use a json::iterator dereferenced value in code? [\\#1120](https://github.com/nlohmann/json/issues/1120)\n- clang compiler: error : unknown type name 'not' [\\#1119](https://github.com/nlohmann/json/issues/1119)\n- Disable implicit conversions from json to std::initializer\\_list\\<T\\> for any T [\\#1118](https://github.com/nlohmann/json/issues/1118)\n- Implicit conversions to complex types can lead to surprising and confusing errors [\\#1116](https://github.com/nlohmann/json/issues/1116)\n- How can I write from\\_json for a complex datatype that is not default constructible? [\\#1115](https://github.com/nlohmann/json/issues/1115)\n- Compile error in VS2015 when compiling unit-conversions.cpp [\\#1114](https://github.com/nlohmann/json/issues/1114)\n- ADL Serializer for std::any / boost::any [\\#1113](https://github.com/nlohmann/json/issues/1113)\n- Unexpected behaviour of is\\_null [\\#1112](https://github.com/nlohmann/json/issues/1112)\n- How to resolve  \" undefined reference to `std::\\_\\_throw\\_bad\\_cast\\(\\)'\" [\\#1111](https://github.com/nlohmann/json/issues/1111)\n- cannot compile on ubuntu 18.04 and 16.04 [\\#1110](https://github.com/nlohmann/json/issues/1110)\n- JSON representation for floating point values has too many digits [\\#1109](https://github.com/nlohmann/json/issues/1109)\n- Not working for classes containing \"\\_declspec\\(dllimport\\)\" in their declaration [\\#1108](https://github.com/nlohmann/json/issues/1108)\n- Get keys from json object [\\#1107](https://github.com/nlohmann/json/issues/1107)\n- dump\\(\\) without alphabetical order [\\#1106](https://github.com/nlohmann/json/issues/1106)\n- Cannot deserialize types using std::ratio [\\#1105](https://github.com/nlohmann/json/issues/1105)\n-  i want to learn json [\\#1104](https://github.com/nlohmann/json/issues/1104)\n- Type checking during compile [\\#1103](https://github.com/nlohmann/json/issues/1103)\n- Iterate through sub items [\\#1102](https://github.com/nlohmann/json/issues/1102)\n- cppcheck failing for version 3.1.2 [\\#1101](https://github.com/nlohmann/json/issues/1101)\n- Deserializing std::map [\\#1100](https://github.com/nlohmann/json/issues/1100)\n- accessing key by reference [\\#1098](https://github.com/nlohmann/json/issues/1098)\n- clang 3.8.0 croaks while trying to compile with debug symbols [\\#1097](https://github.com/nlohmann/json/issues/1097)\n- Serialize a list of class objects with json [\\#1096](https://github.com/nlohmann/json/issues/1096)\n- Null bytes in files are treated like EOF [\\#1095](https://github.com/nlohmann/json/issues/1095)\n- Small question [\\#1094](https://github.com/nlohmann/json/issues/1094)\n- Upgrading to 3.x: to\\_/from\\_json with enum class [\\#1093](https://github.com/nlohmann/json/issues/1093)\n- Q: few questions about json construction [\\#1092](https://github.com/nlohmann/json/issues/1092)\n- general crayCC compilation failure [\\#1091](https://github.com/nlohmann/json/issues/1091)\n- Merge Patch clears original data [\\#1090](https://github.com/nlohmann/json/issues/1090)\n- \\[Question\\] how to use nlohmann/json in c++? [\\#1088](https://github.com/nlohmann/json/issues/1088)\n- C++17 decomposition declaration support [\\#1087](https://github.com/nlohmann/json/issues/1087)\n- \\[Question\\] Access multi-level json objects [\\#1086](https://github.com/nlohmann/json/issues/1086)\n- Serializing vector [\\#1085](https://github.com/nlohmann/json/issues/1085)\n- update nested value in multi hierarchy json object [\\#1084](https://github.com/nlohmann/json/issues/1084)\n- Overriding default values? [\\#1083](https://github.com/nlohmann/json/issues/1083)\n- detail namespace collision with Cereal? [\\#1082](https://github.com/nlohmann/json/issues/1082)\n- Error using json.dump\\(\\); [\\#1081](https://github.com/nlohmann/json/issues/1081)\n- Consuming TCP Stream [\\#1080](https://github.com/nlohmann/json/issues/1080)\n- Compilation error with strong typed enums in map in combination with namespaces [\\#1079](https://github.com/nlohmann/json/issues/1079)\n- cassert error [\\#1076](https://github.com/nlohmann/json/issues/1076)\n- Valid json data not being parsed [\\#1075](https://github.com/nlohmann/json/issues/1075)\n- Feature request :: Better testing for key existance without try/catch [\\#1074](https://github.com/nlohmann/json/issues/1074)\n- Hi, I have input like a.b.c and want to convert it to \\\"a\\\"{\\\"b\\\": \\\"c\\\"} form. Any suggestions how do I do this? Thanks. [\\#1073](https://github.com/nlohmann/json/issues/1073)\n- ADL deserializer not picked up for non default-constructible type [\\#1072](https://github.com/nlohmann/json/issues/1072)\n- Deserializing std::array doesn't compiler \\(no insert\\(\\)\\) [\\#1071](https://github.com/nlohmann/json/issues/1071)\n- Serializing OpenCV Mat problem [\\#1070](https://github.com/nlohmann/json/issues/1070)\n- Compilation error with ICPC compiler [\\#1068](https://github.com/nlohmann/json/issues/1068)\n- Minimal branch? [\\#1066](https://github.com/nlohmann/json/issues/1066)\n- Not existing value, crash [\\#1065](https://github.com/nlohmann/json/issues/1065)\n- cyryllic symbols [\\#1064](https://github.com/nlohmann/json/issues/1064)\n- newbie usage question [\\#1063](https://github.com/nlohmann/json/issues/1063)\n- Trying j\\[\"strTest\"\\] = \"%A\" produces \"strTest\": \"-0X1.CCCCCCCCCCCCCP+205\" [\\#1062](https://github.com/nlohmann/json/issues/1062)\n- convert json value to std::string??? [\\#1061](https://github.com/nlohmann/json/issues/1061)\n- Commented out test cases, should they be removed? [\\#1060](https://github.com/nlohmann/json/issues/1060)\n- different behaviour between clang and gcc with braced initialization [\\#1059](https://github.com/nlohmann/json/issues/1059)\n- json array:  initialize with prescribed size and `resize` method. [\\#1057](https://github.com/nlohmann/json/issues/1057)\n- Is it possible to use exceptions istead of assertions? [\\#1056](https://github.com/nlohmann/json/issues/1056)\n- when using assign operator in with json object a static assertion fails.. [\\#1055](https://github.com/nlohmann/json/issues/1055)\n- Iterate over leafs of a JSON data structure: enrich the JSON pointer API [\\#1054](https://github.com/nlohmann/json/issues/1054)\n- \\[Feature request\\] Access by path [\\#1053](https://github.com/nlohmann/json/issues/1053)\n- document that implicit js -\\> primitive conversion does not work for std::string::value\\_type and why [\\#1052](https://github.com/nlohmann/json/issues/1052)\n- error: ‘BasicJsonType’ in namespace ‘::’ does not name a type [\\#1051](https://github.com/nlohmann/json/issues/1051)\n- Destructor is called when filling object through assignement [\\#1050](https://github.com/nlohmann/json/issues/1050)\n- Is this thing thread safe for reads? [\\#1049](https://github.com/nlohmann/json/issues/1049)\n- clang-tidy: Call to virtual function during construction  [\\#1046](https://github.com/nlohmann/json/issues/1046)\n- Using STL algorithms with JSON containers with expected results? [\\#1045](https://github.com/nlohmann/json/issues/1045)\n- Usage with gtest/gmock not working as expected [\\#1044](https://github.com/nlohmann/json/issues/1044)\n- Consequences of from\\_json / to\\_json being in namespace of data struct. [\\#1042](https://github.com/nlohmann/json/issues/1042)\n- const\\_reference operator\\[\\]\\(const typename object\\_t::key\\_type& key\\) const throw instead of assert [\\#1039](https://github.com/nlohmann/json/issues/1039)\n- Trying to retrieve data from nested objects [\\#1038](https://github.com/nlohmann/json/issues/1038)\n- Direct download link for json\\_fwd.hpp? [\\#1037](https://github.com/nlohmann/json/issues/1037)\n- I know the library supports UTF-8, but failed to dump the value [\\#1036](https://github.com/nlohmann/json/issues/1036)\n- Putting a Vec3-like vector into a json object [\\#1035](https://github.com/nlohmann/json/issues/1035)\n- Ternary operator crash [\\#1034](https://github.com/nlohmann/json/issues/1034)\n- Issued with Clion Inspection Resolution since 2018.1 [\\#1033](https://github.com/nlohmann/json/issues/1033)\n- Some testcases fail and one never finishes [\\#1032](https://github.com/nlohmann/json/issues/1032)\n- Can this class work with wchar\\_t / std::wstring? [\\#1031](https://github.com/nlohmann/json/issues/1031)\n- Makefile: Valgrind flags have no effect [\\#1030](https://github.com/nlohmann/json/issues/1030)\n- 「==」 Should be 「\\>」 [\\#1029](https://github.com/nlohmann/json/issues/1029)\n- HOCON reader? [\\#1027](https://github.com/nlohmann/json/issues/1027)\n- add json string in previous string?? [\\#1025](https://github.com/nlohmann/json/issues/1025)\n- RFC: fluent parsing interface [\\#1023](https://github.com/nlohmann/json/issues/1023)\n- Does it support chinese character? [\\#1022](https://github.com/nlohmann/json/issues/1022)\n- to/from\\_msgpack only works with standard typization [\\#1021](https://github.com/nlohmann/json/issues/1021)\n- Build failure using latest clang and GCC compilers [\\#1020](https://github.com/nlohmann/json/issues/1020)\n- can two json objects be concatenated? [\\#1019](https://github.com/nlohmann/json/issues/1019)\n- Erase by integer index [\\#1018](https://github.com/nlohmann/json/issues/1018)\n- Function find overload taking a json\\_pointer [\\#1017](https://github.com/nlohmann/json/issues/1017)\n- I think should implement an parser function [\\#1016](https://github.com/nlohmann/json/issues/1016)\n- Readme gif [\\#1015](https://github.com/nlohmann/json/issues/1015)\n- Python bindings [\\#1014](https://github.com/nlohmann/json/issues/1014)\n- how to add two json string in single object?? [\\#1012](https://github.com/nlohmann/json/issues/1012)\n- how to serialize class Object \\(convert data in object into json\\)?? [\\#1011](https://github.com/nlohmann/json/issues/1011)\n- Enable forward declaration of json by making json a class instead of a using declaration [\\#997](https://github.com/nlohmann/json/issues/997)\n- compilation error while using intel c++ compiler 2018 [\\#994](https://github.com/nlohmann/json/issues/994)\n- How to create a json variable? [\\#990](https://github.com/nlohmann/json/issues/990)\n- istream \\>\\> json  --- 1st character skipped in stream [\\#976](https://github.com/nlohmann/json/issues/976)\n- Add a SAX parser [\\#971](https://github.com/nlohmann/json/issues/971)\n- Add Key name to Exception [\\#932](https://github.com/nlohmann/json/issues/932)\n- How to solve large json file? [\\#927](https://github.com/nlohmann/json/issues/927)\n- json\\_pointer public push\\_back, pop\\_back [\\#837](https://github.com/nlohmann/json/issues/837)\n- Using input\\_adapter in a slightly unexpected way [\\#834](https://github.com/nlohmann/json/issues/834)\n- Stack-overflow \\(OSS-Fuzz 4234\\) [\\#832](https://github.com/nlohmann/json/issues/832)\n\n- Fix -Wno-sometimes-uninitialized by initializing \"result\" in parse\\_sax [\\#1200](https://github.com/nlohmann/json/pull/1200) ([thyu](https://github.com/thyu))\n- \\[RFC\\] Introduce a new macro function: JSON\\_INTERNAL\\_CATCH [\\#1187](https://github.com/nlohmann/json/pull/1187) ([simnalamburt](https://github.com/simnalamburt))\n- Fix unit tests that were silently skipped or crashed \\(depending on the compiler\\) [\\#1176](https://github.com/nlohmann/json/pull/1176) ([grembo](https://github.com/grembo))\n- Refactor/no virtual sax [\\#1153](https://github.com/nlohmann/json/pull/1153) ([theodelrieu](https://github.com/theodelrieu))\n- Fixed compiler error in VS 2015 for debug mode [\\#1151](https://github.com/nlohmann/json/pull/1151) ([sonulohani](https://github.com/sonulohani))\n- Fix links to cppreference named requirements \\(formerly concepts\\) [\\#1144](https://github.com/nlohmann/json/pull/1144) ([jrakow](https://github.com/jrakow))\n- meson: fix include directory [\\#1142](https://github.com/nlohmann/json/pull/1142) ([jrakow](https://github.com/jrakow))\n- Feature/unordered map conversion [\\#1138](https://github.com/nlohmann/json/pull/1138) ([theodelrieu](https://github.com/theodelrieu))\n- fixed compile error for \\#1045 [\\#1134](https://github.com/nlohmann/json/pull/1134) ([Daniel599](https://github.com/Daniel599))\n-  test \\(non\\)equality for alt\\_string implementation  [\\#1130](https://github.com/nlohmann/json/pull/1130) ([agrianius](https://github.com/agrianius))\n- remove stringstream dependency [\\#1117](https://github.com/nlohmann/json/pull/1117) ([TinyTinni](https://github.com/TinyTinni))\n- Provide a from\\_json overload for std::map [\\#1089](https://github.com/nlohmann/json/pull/1089) ([theodelrieu](https://github.com/theodelrieu))\n- fix typo in README [\\#1078](https://github.com/nlohmann/json/pull/1078) ([martin-mfg](https://github.com/martin-mfg))\n- Fix typo [\\#1058](https://github.com/nlohmann/json/pull/1058) ([dns13](https://github.com/dns13))\n- Misc cmake packaging enhancements [\\#1048](https://github.com/nlohmann/json/pull/1048) ([chuckatkins](https://github.com/chuckatkins))\n- Fixed incorrect LLVM version number in README [\\#1047](https://github.com/nlohmann/json/pull/1047) ([jammehcow](https://github.com/jammehcow))\n- Fix trivial typo in comment. [\\#1043](https://github.com/nlohmann/json/pull/1043) ([coryan](https://github.com/coryan))\n- Package Manager: Spack [\\#1041](https://github.com/nlohmann/json/pull/1041) ([ax3l](https://github.com/ax3l))\n- CMake: 3.8+ is Sufficient [\\#1040](https://github.com/nlohmann/json/pull/1040) ([ax3l](https://github.com/ax3l))\n- Added support for string\\_view in C++17 [\\#1028](https://github.com/nlohmann/json/pull/1028) ([gracicot](https://github.com/gracicot))\n- Added public target\\_compile\\_features for auto and constexpr [\\#1026](https://github.com/nlohmann/json/pull/1026) ([ktonon](https://github.com/ktonon))\n\n## [v3.1.2](https://github.com/nlohmann/json/releases/tag/v3.1.2) (2018-03-14)\n[Full Changelog](https://github.com/nlohmann/json/compare/v3.1.1...v3.1.2)\n\n- STL containers are always serialized to a nested array like \\[\\[1,2,3\\]\\] [\\#1013](https://github.com/nlohmann/json/issues/1013)\n- The library doesn't want to insert an unordered\\_map [\\#1010](https://github.com/nlohmann/json/issues/1010)\n- Convert Json to uint8\\_t [\\#1008](https://github.com/nlohmann/json/issues/1008)\n- How to compare two JSON objects? [\\#1007](https://github.com/nlohmann/json/issues/1007)\n- Syntax checking [\\#1003](https://github.com/nlohmann/json/issues/1003)\n- more than one operator '=' matches these operands [\\#1002](https://github.com/nlohmann/json/issues/1002)\n- How to check if key existed  [\\#1000](https://github.com/nlohmann/json/issues/1000)\n- nlohmann::json::parse exhaust memory in go binding [\\#999](https://github.com/nlohmann/json/issues/999)\n- Range-based iteration over a non-array object [\\#998](https://github.com/nlohmann/json/issues/998)\n- get\\<T\\> for types that are not default constructible [\\#996](https://github.com/nlohmann/json/issues/996)\n- Prevent Null values to appear in .dump\\(\\) [\\#995](https://github.com/nlohmann/json/issues/995)\n- number parsing [\\#993](https://github.com/nlohmann/json/issues/993)\n- C2664 \\(C++/CLR\\) cannot convert 'nullptr' to 'nullptr &&' [\\#987](https://github.com/nlohmann/json/issues/987)\n- Uniform initialization from another json object differs between gcc and clang. [\\#985](https://github.com/nlohmann/json/issues/985)\n- Problem with adding the lib as a submodule [\\#983](https://github.com/nlohmann/json/issues/983)\n- UTF-8/Unicode error [\\#982](https://github.com/nlohmann/json/issues/982)\n- \"forcing MSVC stacktrace to show which T we're talking about.\" error [\\#980](https://github.com/nlohmann/json/issues/980)\n- reverse order of serialization  [\\#979](https://github.com/nlohmann/json/issues/979)\n- Assigning between different json types [\\#977](https://github.com/nlohmann/json/issues/977)\n- Support serialisation of `unique\\_ptr\\<\\>` and `shared\\_ptr\\<\\>` [\\#975](https://github.com/nlohmann/json/issues/975)\n- Unexpected end of input \\(not same as one before\\) [\\#974](https://github.com/nlohmann/json/issues/974)\n- Segfault on direct initializing json object [\\#973](https://github.com/nlohmann/json/issues/973)\n- Segmentation fault on G++ when trying to assign json string literal to custom json type. [\\#972](https://github.com/nlohmann/json/issues/972)\n- os\\_defines.h:44:19: error: missing binary operator before token \"\\(\" [\\#970](https://github.com/nlohmann/json/issues/970)\n- Passing an iteration object by reference to a function [\\#967](https://github.com/nlohmann/json/issues/967)\n- Json and fmt::lib's format\\_arg\\(\\) [\\#964](https://github.com/nlohmann/json/issues/964)\n- Feature: to\\_string\\(const json& j\\); [\\#916](https://github.com/nlohmann/json/issues/916)\n\n- Allowing for user-defined string type in lexer/parser [\\#1009](https://github.com/nlohmann/json/pull/1009) ([nlohmann](https://github.com/nlohmann))\n- dump to alternative string type, as defined in basic\\_json template [\\#1006](https://github.com/nlohmann/json/pull/1006) ([agrianius](https://github.com/agrianius))\n- Fix memory leak during parser callback [\\#1001](https://github.com/nlohmann/json/pull/1001) ([nlohmann](https://github.com/nlohmann))\n- fixed misprinted condition detected by PVS Studio. [\\#992](https://github.com/nlohmann/json/pull/992) ([bogemic](https://github.com/bogemic))\n- Fix/basic json conversion [\\#986](https://github.com/nlohmann/json/pull/986) ([theodelrieu](https://github.com/theodelrieu))\n- Make integration section concise [\\#981](https://github.com/nlohmann/json/pull/981) ([wla80](https://github.com/wla80))\n\n## [v3.1.1](https://github.com/nlohmann/json/releases/tag/v3.1.1) (2018-02-13)\n[Full Changelog](https://github.com/nlohmann/json/compare/v3.1.0...v3.1.1)\n\n- Updation of child object isn't reflected in parent Object [\\#968](https://github.com/nlohmann/json/issues/968)\n- How to add user defined C++ path to sublime text  [\\#966](https://github.com/nlohmann/json/issues/966)\n- fast number parsing [\\#965](https://github.com/nlohmann/json/issues/965)\n- With non-unique keys, later stored entries are not taken into account anymore [\\#963](https://github.com/nlohmann/json/issues/963)\n- Timeout \\(OSS-Fuzz 6034\\) [\\#962](https://github.com/nlohmann/json/issues/962)\n- Incorrect parsing of indefinite length CBOR strings. [\\#961](https://github.com/nlohmann/json/issues/961)\n- Reload a json file at runtime without emptying my std::ifstream [\\#959](https://github.com/nlohmann/json/issues/959)\n- Split headers should be part of the release [\\#956](https://github.com/nlohmann/json/issues/956)\n- Coveralls shows no coverage data [\\#953](https://github.com/nlohmann/json/issues/953)\n- Feature request: Implicit conversion to bool [\\#951](https://github.com/nlohmann/json/issues/951)\n- converting json to vector of type with templated constructor [\\#924](https://github.com/nlohmann/json/issues/924)\n- No structured bindings support? [\\#901](https://github.com/nlohmann/json/issues/901)\n- \\[Request\\] Macro generating from\\_json\\(\\) and to\\_json\\(\\) [\\#895](https://github.com/nlohmann/json/issues/895)\n- basic\\_json::value throws exception instead of returning default value [\\#871](https://github.com/nlohmann/json/issues/871)\n\n- Fix constraints on from\\_json\\(CompatibleArrayType\\) [\\#969](https://github.com/nlohmann/json/pull/969) ([theodelrieu](https://github.com/theodelrieu))\n- Make coveralls watch the include folder [\\#957](https://github.com/nlohmann/json/pull/957) ([theodelrieu](https://github.com/theodelrieu))\n- Fix links in README.md [\\#955](https://github.com/nlohmann/json/pull/955) ([patrikhuber](https://github.com/patrikhuber))\n- Add a note about installing the library with cget [\\#954](https://github.com/nlohmann/json/pull/954) ([pfultz2](https://github.com/pfultz2))\n\n## [v3.1.0](https://github.com/nlohmann/json/releases/tag/v3.1.0) (2018-02-01)\n[Full Changelog](https://github.com/nlohmann/json/compare/v3.0.1...v3.1.0)\n\n- Order of the elements in JSON object [\\#952](https://github.com/nlohmann/json/issues/952)\n- I have a proposal [\\#949](https://github.com/nlohmann/json/issues/949)\n- VERSION define\\(s\\) [\\#948](https://github.com/nlohmann/json/issues/948)\n- v3.0.1 compile error in icc 16.0.4 [\\#947](https://github.com/nlohmann/json/issues/947)\n- Use in VS2017 15.5.5 [\\#946](https://github.com/nlohmann/json/issues/946)\n- Process for reporting Security Bugs? [\\#945](https://github.com/nlohmann/json/issues/945)\n- Please expose a NLOHMANN\\_JSON\\_VERSION macro [\\#943](https://github.com/nlohmann/json/issues/943)\n- Change header include directory to nlohmann/json [\\#942](https://github.com/nlohmann/json/issues/942)\n- string\\_type in binary\\_reader [\\#941](https://github.com/nlohmann/json/issues/941)\n- compile error with clang 5.0 -std=c++1z and no string\\_view [\\#939](https://github.com/nlohmann/json/issues/939)\n- Allow overriding JSON\\_THROW to something else than abort\\(\\) [\\#938](https://github.com/nlohmann/json/issues/938)\n- Handle invalid string in Json file [\\#937](https://github.com/nlohmann/json/issues/937)\n- Unused variable 'kMinExp' [\\#935](https://github.com/nlohmann/json/issues/935)\n- yytext is already defined [\\#933](https://github.com/nlohmann/json/issues/933)\n- Equality operator fails [\\#931](https://github.com/nlohmann/json/issues/931)\n- use in visual studio 2015 [\\#929](https://github.com/nlohmann/json/issues/929)\n- Relative includes of json\\_fwd.hpp in detail/meta.hpp. \\[Develop branch\\] [\\#928](https://github.com/nlohmann/json/issues/928)\n- GCC 7.x issue [\\#926](https://github.com/nlohmann/json/issues/926)\n- json\\_fwd.hpp not installed [\\#923](https://github.com/nlohmann/json/issues/923)\n- Use Google Benchmarks [\\#921](https://github.com/nlohmann/json/issues/921)\n- Move class json\\_pointer to separate file [\\#920](https://github.com/nlohmann/json/issues/920)\n- Unable to locate 'to\\_json\\(\\)' and 'from\\_json\\(\\)' methods in the same namespace [\\#917](https://github.com/nlohmann/json/issues/917)\n- \\[answered\\]Read key1 from .value example  [\\#914](https://github.com/nlohmann/json/issues/914)\n- Don't use `define private public` in test files [\\#913](https://github.com/nlohmann/json/issues/913)\n- value\\(\\) template argument type deduction [\\#912](https://github.com/nlohmann/json/issues/912)\n- Installation path is incorrect [\\#910](https://github.com/nlohmann/json/issues/910)\n- H [\\#909](https://github.com/nlohmann/json/issues/909)\n- Build failure using clang 5 [\\#908](https://github.com/nlohmann/json/issues/908)\n- Amalgate [\\#907](https://github.com/nlohmann/json/issues/907)\n- Update documentation and tests wrt. split headers [\\#906](https://github.com/nlohmann/json/issues/906)\n- Lib not working on ubuntu 16.04 [\\#905](https://github.com/nlohmann/json/issues/905)\n- Problem when writing to file. [\\#904](https://github.com/nlohmann/json/issues/904)\n- C2864 error when compiling with VS2015 and VS 2017 [\\#903](https://github.com/nlohmann/json/issues/903)\n- \\[json.exception.type\\_error.304\\] cannot use at\\(\\) with object [\\#902](https://github.com/nlohmann/json/issues/902)\n- How do I forward nlohmann::json declaration? [\\#899](https://github.com/nlohmann/json/issues/899)\n- How to effectively store binary data? [\\#898](https://github.com/nlohmann/json/issues/898)\n- How to get the length of a JSON string without retrieving its std::string? [\\#897](https://github.com/nlohmann/json/issues/897)\n- Regression Tests Failure using \"ctest\" [\\#887](https://github.com/nlohmann/json/issues/887)\n- Discuss: add JSON Merge Patch \\(RFC 7396\\)? [\\#877](https://github.com/nlohmann/json/issues/877)\n- Discuss: replace static \"iterator\\_wrapper\" function with \"items\" member function [\\#874](https://github.com/nlohmann/json/issues/874)\n- Make optional user-data available in from\\_json [\\#864](https://github.com/nlohmann/json/issues/864)\n- Casting to std::string not working in VS2015 [\\#861](https://github.com/nlohmann/json/issues/861)\n- Sequential reading of JSON arrays [\\#851](https://github.com/nlohmann/json/issues/851)\n- Idea: Handle Multimaps Better [\\#816](https://github.com/nlohmann/json/issues/816)\n- Floating point rounding [\\#777](https://github.com/nlohmann/json/issues/777)\n- Loss of precision when serializing \\<double\\> [\\#360](https://github.com/nlohmann/json/issues/360)\n\n- Templatize std::string in binary\\_reader \\#941 [\\#950](https://github.com/nlohmann/json/pull/950) ([kaidokert](https://github.com/kaidokert))\n- fix cmake install directory \\(for real this time\\) [\\#944](https://github.com/nlohmann/json/pull/944) ([theodelrieu](https://github.com/theodelrieu))\n- Allow overriding THROW/CATCH/TRY macros with no-exceptions \\#938 [\\#940](https://github.com/nlohmann/json/pull/940) ([kaidokert](https://github.com/kaidokert))\n- Removed compiler warning about unused variable 'kMinExp' [\\#936](https://github.com/nlohmann/json/pull/936) ([zerodefect](https://github.com/zerodefect))\n- Fix a typo in README.md [\\#930](https://github.com/nlohmann/json/pull/930) ([Pipeliner](https://github.com/Pipeliner))\n- Howto installation of json\\_fwd.hpp \\(fixes \\#923\\) [\\#925](https://github.com/nlohmann/json/pull/925) ([zerodefect](https://github.com/zerodefect))\n- fix sfinae on basic\\_json UDT constructor [\\#919](https://github.com/nlohmann/json/pull/919) ([theodelrieu](https://github.com/theodelrieu))\n- Floating-point formatting [\\#915](https://github.com/nlohmann/json/pull/915) ([abolz](https://github.com/abolz))\n- Fix/cmake install [\\#911](https://github.com/nlohmann/json/pull/911) ([theodelrieu](https://github.com/theodelrieu))\n- fix link to the documentation of the emplace function [\\#900](https://github.com/nlohmann/json/pull/900) ([Dobiasd](https://github.com/Dobiasd))\n- JSON Merge Patch \\(RFC 7396\\) [\\#876](https://github.com/nlohmann/json/pull/876) ([nlohmann](https://github.com/nlohmann))\n- Refactor/split it [\\#700](https://github.com/nlohmann/json/pull/700) ([theodelrieu](https://github.com/theodelrieu))\n\n## [v3.0.1](https://github.com/nlohmann/json/releases/tag/v3.0.1) (2017-12-29)\n[Full Changelog](https://github.com/nlohmann/json/compare/v3.0.0...v3.0.1)\n\n- Problem parsing array to global vector [\\#896](https://github.com/nlohmann/json/issues/896)\n- Invalid RFC6902 copy operation succeeds [\\#894](https://github.com/nlohmann/json/issues/894)\n- How to rename a key during looping? [\\#893](https://github.com/nlohmann/json/issues/893)\n- clang++-6.0 \\(6.0.0-svn321357-1\\) warning [\\#892](https://github.com/nlohmann/json/issues/892)\n- Make json.hpp aware of the modules TS? [\\#891](https://github.com/nlohmann/json/issues/891)\n- All enum values not handled in switch cases. \\( -Wswitch-enum \\) [\\#889](https://github.com/nlohmann/json/issues/889)\n- JSON Pointer resolve failure resulting in incorrect exception code [\\#888](https://github.com/nlohmann/json/issues/888)\n- Unexpected nested arrays from std::vector [\\#886](https://github.com/nlohmann/json/issues/886)\n- erase multiple elements from a json object [\\#884](https://github.com/nlohmann/json/issues/884)\n- Container function overview in Doxygen is not updated [\\#883](https://github.com/nlohmann/json/issues/883)\n- How to use this for binary file uploads [\\#881](https://github.com/nlohmann/json/issues/881)\n- Allow setting JSON\\_BuildTests=OFF from parent CMakeLists.txt [\\#846](https://github.com/nlohmann/json/issues/846)\n- Unit test fails for local-independent str-to-num [\\#845](https://github.com/nlohmann/json/issues/845)\n- Another idea about type support [\\#774](https://github.com/nlohmann/json/issues/774)\n\n- Includes CTest module/adds BUILD\\_TESTING option [\\#885](https://github.com/nlohmann/json/pull/885) ([TinyTinni](https://github.com/TinyTinni))\n- Fix MSVC warning C4819 [\\#882](https://github.com/nlohmann/json/pull/882) ([erengy](https://github.com/erengy))\n- Merge branch 'develop' into coverity\\_scan [\\#880](https://github.com/nlohmann/json/pull/880) ([nlohmann](https://github.com/nlohmann))\n- :wrench: Fix up a few more effc++ items [\\#858](https://github.com/nlohmann/json/pull/858) ([mattismyname](https://github.com/mattismyname))\n\n## [v3.0.0](https://github.com/nlohmann/json/releases/tag/v3.0.0) (2017-12-17)\n[Full Changelog](https://github.com/nlohmann/json/compare/v2.1.1...v3.0.0)\n\n- unicode strings [\\#878](https://github.com/nlohmann/json/issues/878)\n- Visual Studio 2017 15.5 C++17 std::allocator deprecations [\\#872](https://github.com/nlohmann/json/issues/872)\n- Typo \"excpetion\" [\\#869](https://github.com/nlohmann/json/issues/869)\n- Explicit array example in README.md incorrect [\\#867](https://github.com/nlohmann/json/issues/867)\n- why don't you release this from Feb. ? [\\#865](https://github.com/nlohmann/json/issues/865)\n- json::parse throws std::invalid\\_argument when processing string generated by json::dump\\(\\) [\\#863](https://github.com/nlohmann/json/issues/863)\n- code analysis: potential bug? [\\#859](https://github.com/nlohmann/json/issues/859)\n- MSVC2017, 15.5 new issues.   [\\#857](https://github.com/nlohmann/json/issues/857)\n- very basic: fetching string value/content without quotes [\\#853](https://github.com/nlohmann/json/issues/853)\n- Ambiguous function call to get with pointer type and constant json object in VS2015 \\(15.4.4\\) [\\#852](https://github.com/nlohmann/json/issues/852)\n- How to put  object in the array as a member? [\\#850](https://github.com/nlohmann/json/issues/850)\n- misclick, please ignore [\\#849](https://github.com/nlohmann/json/issues/849)\n- Make XML great again. [\\#847](https://github.com/nlohmann/json/issues/847)\n- Converting to array not working [\\#843](https://github.com/nlohmann/json/issues/843)\n- Iteration weirdness [\\#842](https://github.com/nlohmann/json/issues/842)\n- Use reference or pointer as Object value [\\#841](https://github.com/nlohmann/json/issues/841)\n- Ambiguity in parsing nested maps [\\#840](https://github.com/nlohmann/json/issues/840)\n- could not find from\\_json\\(\\) method in T's namespace [\\#839](https://github.com/nlohmann/json/issues/839)\n- Incorrect parse error with binary data in keys? [\\#838](https://github.com/nlohmann/json/issues/838)\n- using dump\\(\\) when std::wstring is StringType with VS2017 [\\#836](https://github.com/nlohmann/json/issues/836)\n- Show the path of the currently parsed value when an error occurs [\\#835](https://github.com/nlohmann/json/issues/835)\n- Repetitive data type while reading [\\#833](https://github.com/nlohmann/json/issues/833)\n- Storing multiple types inside map [\\#831](https://github.com/nlohmann/json/issues/831)\n- Application terminating [\\#830](https://github.com/nlohmann/json/issues/830)\n- Missing CMake hunter package? [\\#828](https://github.com/nlohmann/json/issues/828)\n- std::map\\<std::string, std::string\\> from json object yields C2665: 'std::pair\\<const \\_Kty,\\_Ty\\>::pair': none of the 2 overloads could convert all the argument types [\\#827](https://github.com/nlohmann/json/issues/827)\n- object.dump gives quoted string, want to use .dump\\(\\) to generate javascripts. [\\#826](https://github.com/nlohmann/json/issues/826)\n- Assertion failed on \\[\"NoExistKey\"\\] of an not existing key of const json& [\\#825](https://github.com/nlohmann/json/issues/825)\n- vs2015 error : static member will remain uninitialized at runtime but use in constant-expressions is supported [\\#824](https://github.com/nlohmann/json/issues/824)\n- Code Checking Warnings from json.hpp on VS2017 Community [\\#821](https://github.com/nlohmann/json/issues/821)\n- Missing iostream in try online [\\#820](https://github.com/nlohmann/json/issues/820)\n- Floating point value loses decimal point during dump [\\#818](https://github.com/nlohmann/json/issues/818)\n- Conan package for the library [\\#817](https://github.com/nlohmann/json/issues/817)\n- stream error  [\\#815](https://github.com/nlohmann/json/issues/815)\n- Link error when using find\\(\\) on the latest commit [\\#814](https://github.com/nlohmann/json/issues/814)\n- ABI issue with json object between 2 shared libraries [\\#813](https://github.com/nlohmann/json/issues/813)\n- scan\\_string\\(\\) return token\\_type::parse\\_error; when parse ansi file [\\#812](https://github.com/nlohmann/json/issues/812)\n- segfault when using fifo\\_map with json [\\#810](https://github.com/nlohmann/json/issues/810)\n- This shit is shit  [\\#809](https://github.com/nlohmann/json/issues/809)\n- \\_finite and \\_isnan are no members of \"std\" [\\#808](https://github.com/nlohmann/json/issues/808)\n- how to print out the line which causing exception? [\\#806](https://github.com/nlohmann/json/issues/806)\n- {} uses copy constructor, while = does not [\\#805](https://github.com/nlohmann/json/issues/805)\n- json.hpp:8955: multiple definition of function that is not defined twice or more. [\\#804](https://github.com/nlohmann/json/issues/804)\n- \\[question\\] to\\_json for base and derived class [\\#803](https://github.com/nlohmann/json/issues/803)\n- Misleading error message - unexpected '\"' - on incorrect utf-8 symbol [\\#802](https://github.com/nlohmann/json/issues/802)\n- json data = std::string\\_view\\(\"hi\"\\); doesn't work? [\\#801](https://github.com/nlohmann/json/issues/801)\n- Thread safety of parse\\(\\) [\\#800](https://github.com/nlohmann/json/issues/800)\n- Numbers as strings [\\#799](https://github.com/nlohmann/json/issues/799)\n- Tests failing on arm [\\#797](https://github.com/nlohmann/json/issues/797)\n- Using your library \\(without modification\\) in another library [\\#796](https://github.com/nlohmann/json/issues/796)\n- Iterating over sub-object [\\#794](https://github.com/nlohmann/json/issues/794)\n- how to get the json object again from which printed by the method of dump\\(\\) [\\#792](https://github.com/nlohmann/json/issues/792)\n- ppa to include source [\\#791](https://github.com/nlohmann/json/issues/791)\n- Different include paths in macOS and Ubuntu [\\#790](https://github.com/nlohmann/json/issues/790)\n- Missing break after line 12886 in switch/case [\\#789](https://github.com/nlohmann/json/issues/789)\n- All unit tests fail? [\\#787](https://github.com/nlohmann/json/issues/787)\n- More use of move semantics in deserialization [\\#786](https://github.com/nlohmann/json/issues/786)\n- warning C4706 - Visual Studio 2017 \\(/W4\\) [\\#784](https://github.com/nlohmann/json/issues/784)\n- Compile error in clang 5.0 [\\#782](https://github.com/nlohmann/json/issues/782)\n- Error Installing appium\\_lib with Ruby v2.4.2 Due to JSON [\\#781](https://github.com/nlohmann/json/issues/781)\n- ::get\\<int\\>\\(\\) fails in new\\(er\\) release \\[MSVC\\] [\\#780](https://github.com/nlohmann/json/issues/780)\n- Type Conversion [\\#779](https://github.com/nlohmann/json/issues/779)\n- Segfault on nested parsing [\\#778](https://github.com/nlohmann/json/issues/778)\n- Build warnings: shadowing exception id [\\#776](https://github.com/nlohmann/json/issues/776)\n- multi-level JSON support. [\\#775](https://github.com/nlohmann/json/issues/775)\n- SIGABRT on dump\\(\\) [\\#773](https://github.com/nlohmann/json/issues/773)\n- \\[Question\\] Custom StringType template parameter \\(possibility for a KeyType template parameter\\) [\\#772](https://github.com/nlohmann/json/issues/772)\n- constexpr ALL the Things! [\\#771](https://github.com/nlohmann/json/issues/771)\n- error: ‘BasicJsonType’ in namespace ‘::’ does not name a type [\\#770](https://github.com/nlohmann/json/issues/770)\n- Program calls abort function [\\#769](https://github.com/nlohmann/json/issues/769)\n- \\[Question\\] Floating point resolution config during dump\\(\\) ? [\\#768](https://github.com/nlohmann/json/issues/768)\n- make check - no test ran [\\#767](https://github.com/nlohmann/json/issues/767)\n- The library cannot work properly with custom allocator based containers [\\#766](https://github.com/nlohmann/json/issues/766)\n- Documentation or feature request. [\\#763](https://github.com/nlohmann/json/issues/763)\n- warnings in msvc about mix/max macro while windows.h is used in the project [\\#762](https://github.com/nlohmann/json/issues/762)\n- std::signbit ambiguous [\\#761](https://github.com/nlohmann/json/issues/761)\n- How to use value for std::experimental::optional type? [\\#760](https://github.com/nlohmann/json/issues/760)\n- Cannot load json file properly [\\#759](https://github.com/nlohmann/json/issues/759)\n- Compilation error with unordered\\_map\\< int, int \\> [\\#758](https://github.com/nlohmann/json/issues/758)\n- CBOR string [\\#757](https://github.com/nlohmann/json/issues/757)\n- Proposal: out\\_of\\_range should be a subclass of std::out\\_of\\_range [\\#756](https://github.com/nlohmann/json/issues/756)\n- Compiling with icpc [\\#755](https://github.com/nlohmann/json/issues/755)\n- Getter is setting the value to null if the key does not exist [\\#754](https://github.com/nlohmann/json/issues/754)\n- parsing works sometimes and crashes others [\\#752](https://github.com/nlohmann/json/issues/752)\n- Static\\_assert failed \"incompatible pointer type\" with Xcode [\\#751](https://github.com/nlohmann/json/issues/751)\n- user-defined literal operator not found [\\#750](https://github.com/nlohmann/json/issues/750)\n- getting clean string from it.key\\(\\) [\\#748](https://github.com/nlohmann/json/issues/748)\n- Best method for exploring and obtaining values of nested json objects when the names are not known beforehand? [\\#747](https://github.com/nlohmann/json/issues/747)\n- null char at the end of string [\\#746](https://github.com/nlohmann/json/issues/746)\n- Incorrect sample for operator \\>\\> in docs [\\#745](https://github.com/nlohmann/json/issues/745)\n- User-friendly documentation [\\#744](https://github.com/nlohmann/json/issues/744)\n- Retrieve all values that match a json path [\\#743](https://github.com/nlohmann/json/issues/743)\n- Compilation issue with gcc 7.2 [\\#742](https://github.com/nlohmann/json/issues/742)\n- CMake target nlohmann\\_json does not have src into its interface includes [\\#741](https://github.com/nlohmann/json/issues/741)\n- Error when serializing empty json: type must be string, but is object [\\#740](https://github.com/nlohmann/json/issues/740)\n- Conversion error for std::map\\<int, std::string\\>  [\\#739](https://github.com/nlohmann/json/issues/739)\n- Dumping Json to file as array [\\#738](https://github.com/nlohmann/json/issues/738)\n- nesting json objects [\\#737](https://github.com/nlohmann/json/issues/737)\n- where to find general help? [\\#736](https://github.com/nlohmann/json/issues/736)\n- Compilation Error on Clang 5.0 Upgrade [\\#735](https://github.com/nlohmann/json/issues/735)\n- Compilation error with std::map\\<std::string, std::string\\> on vs 2015 [\\#734](https://github.com/nlohmann/json/issues/734)\n- Benchmarks for Binary formats [\\#733](https://github.com/nlohmann/json/issues/733)\n- Move test blobs to a submodule? [\\#732](https://github.com/nlohmann/json/issues/732)\n- Support \\n symbols in json string. [\\#731](https://github.com/nlohmann/json/issues/731)\n- Project's name is too generic and hard to search for [\\#730](https://github.com/nlohmann/json/issues/730)\n- Visual Studio 2015 IntelliTrace problems [\\#729](https://github.com/nlohmann/json/issues/729)\n- How to erase nested objects inside other objects? [\\#728](https://github.com/nlohmann/json/issues/728)\n- How to prevent alphabetical sorting of data? [\\#727](https://github.com/nlohmann/json/issues/727)\n- Serialization for CBOR [\\#726](https://github.com/nlohmann/json/issues/726)\n- Using json Object as value in a map [\\#725](https://github.com/nlohmann/json/issues/725)\n- std::regex and nlohmann::json value [\\#724](https://github.com/nlohmann/json/issues/724)\n- Warnings when compiling with VisualStudio 2015 [\\#723](https://github.com/nlohmann/json/issues/723)\n- Has this lib the unicode \\(wstring\\) support? [\\#722](https://github.com/nlohmann/json/issues/722)\n- When will be 3.0 in master? [\\#721](https://github.com/nlohmann/json/issues/721)\n- Determine the type from error message. [\\#720](https://github.com/nlohmann/json/issues/720)\n- Compile-Error C2100 \\(MS VS2015\\) in line 887 json.hpp [\\#719](https://github.com/nlohmann/json/issues/719)\n- from\\_json not working for boost::optional example [\\#718](https://github.com/nlohmann/json/issues/718)\n- about from\\_json and to\\_json function [\\#717](https://github.com/nlohmann/json/issues/717)\n- How to deserialize array with derived objects [\\#716](https://github.com/nlohmann/json/issues/716)\n- How to detect parse failure? [\\#715](https://github.com/nlohmann/json/issues/715)\n- Parse throw std::ios\\_base::failure exception when failbit set to true [\\#714](https://github.com/nlohmann/json/issues/714)\n- Is there a way of format just making a pretty print without changing the key's orders ? [\\#713](https://github.com/nlohmann/json/issues/713)\n- Serialization of array of not same model items [\\#712](https://github.com/nlohmann/json/issues/712)\n- pointer to json parse vector [\\#711](https://github.com/nlohmann/json/issues/711)\n- Gtest SEH Exception [\\#709](https://github.com/nlohmann/json/issues/709)\n- broken from\\_json implementation for pair and tuple  [\\#707](https://github.com/nlohmann/json/issues/707)\n- Unevaluated lambda in assert breaks gcc 7 build [\\#705](https://github.com/nlohmann/json/issues/705)\n- Issues when adding values to firebase database [\\#704](https://github.com/nlohmann/json/issues/704)\n- Floating point equality - revisited [\\#703](https://github.com/nlohmann/json/issues/703)\n- Conversion from valarray\\<double\\> to json fails to build [\\#702](https://github.com/nlohmann/json/issues/702)\n- internal compiler error \\(gcc7\\)  [\\#701](https://github.com/nlohmann/json/issues/701)\n- One build system to rule them all [\\#698](https://github.com/nlohmann/json/issues/698)\n- Generated nlohmann\\_jsonConfig.cmake does not set JSON\\_INCLUDE\\_DIR [\\#695](https://github.com/nlohmann/json/issues/695)\n- support the Chinese language in json string [\\#694](https://github.com/nlohmann/json/issues/694)\n- NaN problem within develop branch [\\#693](https://github.com/nlohmann/json/issues/693)\n- Please post example of specialization for boost::filesystem [\\#692](https://github.com/nlohmann/json/issues/692)\n- Impossible to do an array of composite objects [\\#691](https://github.com/nlohmann/json/issues/691)\n- How to save json to file? [\\#690](https://github.com/nlohmann/json/issues/690)\n- my simple json parser [\\#689](https://github.com/nlohmann/json/issues/689)\n- problem with new struct parsing syntax [\\#688](https://github.com/nlohmann/json/issues/688)\n- Parse error while parse the json string contains  UTF 8 encoded document bytes string [\\#684](https://github.com/nlohmann/json/issues/684)\n- \\[question\\] how to get a string value by pointer [\\#683](https://github.com/nlohmann/json/issues/683)\n- create json object from string variable [\\#681](https://github.com/nlohmann/json/issues/681)\n- adl\\_serializer and CRTP [\\#680](https://github.com/nlohmann/json/issues/680)\n- Is there a way to control the precision of serialized floating point numbers? [\\#677](https://github.com/nlohmann/json/issues/677)\n- Is there a way to get the path of a value? [\\#676](https://github.com/nlohmann/json/issues/676)\n- Could the parser locate errors to line? [\\#675](https://github.com/nlohmann/json/issues/675)\n- There is performance inefficiency found by coverity tool json2.1.1/include/nlohmann/json.hpp [\\#673](https://github.com/nlohmann/json/issues/673)\n- include problem, when cmake on osx [\\#672](https://github.com/nlohmann/json/issues/672)\n- Operator= ambiguous in C++1z and GCC 7.1.1 [\\#670](https://github.com/nlohmann/json/issues/670)\n- should't the cmake install target be to nlohman/json.hpp [\\#668](https://github.com/nlohmann/json/issues/668)\n- deserialise from `std::vector` [\\#667](https://github.com/nlohmann/json/issues/667)\n- How to iterate? [\\#665](https://github.com/nlohmann/json/issues/665)\n- could this json lib work on windows? [\\#664](https://github.com/nlohmann/json/issues/664)\n- How does from\\_json work? [\\#662](https://github.com/nlohmann/json/issues/662)\n- insert\\(or merge\\) object should replace same key , not ignore [\\#661](https://github.com/nlohmann/json/issues/661)\n- Why is an object ordering values by Alphabetical Order?  [\\#660](https://github.com/nlohmann/json/issues/660)\n- Parse method doesn't handle newlines. [\\#659](https://github.com/nlohmann/json/issues/659)\n- Compilation \"note\" on GCC 6 ARM [\\#658](https://github.com/nlohmann/json/issues/658)\n- Adding additional push\\_back/operator+= rvalue overloads for JSON object [\\#657](https://github.com/nlohmann/json/issues/657)\n- dump's parameter \"ensure\\_ascii\" creates too long sequences [\\#656](https://github.com/nlohmann/json/issues/656)\n- Question: parsing `void \\*` [\\#655](https://github.com/nlohmann/json/issues/655)\n- how should I check a string is valid JSON string ? [\\#653](https://github.com/nlohmann/json/issues/653)\n- Question: thread safety of read only accesses [\\#651](https://github.com/nlohmann/json/issues/651)\n- Eclipse: Method 'size' could not be resolved [\\#649](https://github.com/nlohmann/json/issues/649)\n- Update/Add object fields [\\#648](https://github.com/nlohmann/json/issues/648)\n- No exception raised for Out Of Range input of numbers [\\#647](https://github.com/nlohmann/json/issues/647)\n- Package Name [\\#646](https://github.com/nlohmann/json/issues/646)\n- What is the meaning of operator\\[\\]\\(T\\* key\\) [\\#645](https://github.com/nlohmann/json/issues/645)\n- Which is the correct way to json objects as parameters to functions? [\\#644](https://github.com/nlohmann/json/issues/644)\n- Method to get string representations of values [\\#642](https://github.com/nlohmann/json/issues/642)\n-  CBOR serialization of a given JSON value does not serialize [\\#641](https://github.com/nlohmann/json/issues/641)\n- Are we forced to use \"-fexceptions\" flag in android ndk project [\\#640](https://github.com/nlohmann/json/issues/640)\n- Comparison of objects containing floats [\\#639](https://github.com/nlohmann/json/issues/639)\n- 'localeconv' is not supported by NDK for SDK  \\<=20 [\\#638](https://github.com/nlohmann/json/issues/638)\n- \\[Question\\] cLion integration [\\#637](https://github.com/nlohmann/json/issues/637)\n- How to construct an iteratable usage in nlohmann json? [\\#636](https://github.com/nlohmann/json/issues/636)\n- \\[Question\\] copy assign json-container to vector [\\#635](https://github.com/nlohmann/json/issues/635)\n- Get size without .dump\\(\\) [\\#634](https://github.com/nlohmann/json/issues/634)\n- Segmentation fault when parsing invalid json file [\\#633](https://github.com/nlohmann/json/issues/633)\n- How to serialize from json to vector\\<customType\\>? [\\#632](https://github.com/nlohmann/json/issues/632)\n- no member named 'thousands\\_sep' in 'lconv' [\\#631](https://github.com/nlohmann/json/issues/631)\n- \\[Question\\] Any fork for \\(the unsupported\\) Visual Studio 2012 version? [\\#628](https://github.com/nlohmann/json/issues/628)\n- Dependency injection in serializer [\\#627](https://github.com/nlohmann/json/issues/627)\n- from\\_json for std::array [\\#625](https://github.com/nlohmann/json/issues/625)\n- Discussion: How to structure the parsing function families [\\#623](https://github.com/nlohmann/json/issues/623)\n- Question: How to erase subtree [\\#622](https://github.com/nlohmann/json/issues/622)\n- Insertion into nested json field [\\#621](https://github.com/nlohmann/json/issues/621)\n- \\[Question\\] When using this as git submodule, will it clone the whole thing include test data and benchmark? [\\#620](https://github.com/nlohmann/json/issues/620)\n- Question: return static json object from function [\\#618](https://github.com/nlohmann/json/issues/618)\n- icc16 error [\\#617](https://github.com/nlohmann/json/issues/617)\n- \\[-Wdeprecated-declarations\\] in row `j \\>\\> ss;` in file `json.hpp:7405:26` and FAILED unit tests with MinGWx64! [\\#616](https://github.com/nlohmann/json/issues/616)\n- to\\_json for pairs, tuples [\\#614](https://github.com/nlohmann/json/issues/614)\n- Using uninitialized memory 'buf' in line 11173 v2.1.1? [\\#613](https://github.com/nlohmann/json/issues/613)\n- How to parse multiple same Keys of JSON and save them? [\\#612](https://github.com/nlohmann/json/issues/612)\n- \"Multiple declarations\" error when using types defined with `typedef` [\\#611](https://github.com/nlohmann/json/issues/611)\n- 2.1.1+ breaks compilation of shared\\_ptr\\<json\\> == 0 [\\#610](https://github.com/nlohmann/json/issues/610)\n- a bug of inheritance ?  [\\#608](https://github.com/nlohmann/json/issues/608)\n- std::map key conversion with to\\_json [\\#607](https://github.com/nlohmann/json/issues/607)\n- json.hpp:6384:62: error: wrong number of template arguments \\(1, should be 2\\) [\\#606](https://github.com/nlohmann/json/issues/606)\n- Incremental parsing: Where's the push version? [\\#605](https://github.com/nlohmann/json/issues/605)\n- Is there a way to validate the structure of a json object ? [\\#604](https://github.com/nlohmann/json/issues/604)\n- \\[Question\\] Issue when using Appveyor when compiling library [\\#603](https://github.com/nlohmann/json/issues/603)\n- BOM not skipped when using json:parse\\(iterator\\) [\\#602](https://github.com/nlohmann/json/issues/602)\n- Use of the binary type in CBOR and Message Pack [\\#601](https://github.com/nlohmann/json/issues/601)\n- Newbie issue: how does one convert a map in Json back to std::map? [\\#600](https://github.com/nlohmann/json/issues/600)\n- Plugin system [\\#599](https://github.com/nlohmann/json/issues/599)\n- Feature request: Comments [\\#597](https://github.com/nlohmann/json/issues/597)\n- Using custom types for scalars? [\\#596](https://github.com/nlohmann/json/issues/596)\n- Issues with the arithmetic in iterator and reverse iterator [\\#593](https://github.com/nlohmann/json/issues/593)\n- not enough examples [\\#592](https://github.com/nlohmann/json/issues/592)\n- in-class initialization for type 'const T' is not yet implemented [\\#591](https://github.com/nlohmann/json/issues/591)\n- compiling with gcc 7 -\\> error on bool operator \\< [\\#590](https://github.com/nlohmann/json/issues/590)\n- Parsing from stream leads to an array [\\#589](https://github.com/nlohmann/json/issues/589)\n- Buggy support for binary string data [\\#587](https://github.com/nlohmann/json/issues/587)\n- C++17's ambiguous conversion [\\#586](https://github.com/nlohmann/json/issues/586)\n- How does the messagepack encoding/decoding compare to msgpack-cpp in terms of performance? [\\#585](https://github.com/nlohmann/json/issues/585)\n- is it possible to check existence of a value deep in hierarchy? [\\#584](https://github.com/nlohmann/json/issues/584)\n- loading from a stream and exceptions [\\#582](https://github.com/nlohmann/json/issues/582)\n- Visual Studio seems not to have all min\\(\\) function versions [\\#581](https://github.com/nlohmann/json/issues/581)\n- Supporting of the json schema [\\#580](https://github.com/nlohmann/json/issues/580)\n- Stack-overflow \\(OSS-Fuzz 1444\\) [\\#577](https://github.com/nlohmann/json/issues/577)\n- Heap-buffer-overflow \\(OSS-Fuzz 1400\\) [\\#575](https://github.com/nlohmann/json/issues/575)\n- JSON escape quotes [\\#574](https://github.com/nlohmann/json/issues/574)\n- error: static\\_assert failed [\\#573](https://github.com/nlohmann/json/issues/573)\n- Storing floats, and round trip serialisation/deserialisation diffs [\\#572](https://github.com/nlohmann/json/issues/572)\n- JSON.getLong produces inconsistent results [\\#571](https://github.com/nlohmann/json/issues/571)\n- Request: Object.at\\(\\) with default return value [\\#570](https://github.com/nlohmann/json/issues/570)\n- Internal structure gets corrupted while parsing [\\#569](https://github.com/nlohmann/json/issues/569)\n- create template \\<typename Iter\\> basic\\_json from\\_cbor\\(Iter begin, Iter end\\) [\\#568](https://github.com/nlohmann/json/issues/568)\n- Need to improve ignores.. [\\#567](https://github.com/nlohmann/json/issues/567)\n- Conan.io [\\#566](https://github.com/nlohmann/json/issues/566)\n- contradictory documentation regarding json::find [\\#565](https://github.com/nlohmann/json/issues/565)\n- Unexpected '\\\"' in middle of array [\\#564](https://github.com/nlohmann/json/issues/564)\n- Support parse std::pair to Json object [\\#563](https://github.com/nlohmann/json/issues/563)\n- json and Microsoft Visual c++ Compiler Nov 2012 CTP [\\#562](https://github.com/nlohmann/json/issues/562)\n- from\\_json declaration order and exceptions [\\#561](https://github.com/nlohmann/json/issues/561)\n- Tip: Don't upgrade to VS2017 if using json initializer list constructs [\\#559](https://github.com/nlohmann/json/issues/559)\n- parse error - unexpected end of input [\\#558](https://github.com/nlohmann/json/issues/558)\n- Cant modify existing numbers inside a json object [\\#557](https://github.com/nlohmann/json/issues/557)\n- Minimal repository \\(current size very large\\) [\\#556](https://github.com/nlohmann/json/issues/556)\n- Better support for SAX style serialize and deserialize in new version? [\\#554](https://github.com/nlohmann/json/issues/554)\n- Cannot convert from json array to std::array [\\#553](https://github.com/nlohmann/json/issues/553)\n- Do not define an unnamed namespace in a header file \\(DCL59-CPP\\) [\\#552](https://github.com/nlohmann/json/issues/552)\n- Parse error on known good json file [\\#551](https://github.com/nlohmann/json/issues/551)\n- Warning on Intel compiler \\(icc 17\\) [\\#550](https://github.com/nlohmann/json/issues/550)\n- multiple versions of 'vsnprintf' [\\#549](https://github.com/nlohmann/json/issues/549)\n- illegal indirection [\\#548](https://github.com/nlohmann/json/issues/548)\n- Ambiguous compare operators with clang-5.0 [\\#547](https://github.com/nlohmann/json/issues/547)\n- Using tsl::ordered\\_map [\\#546](https://github.com/nlohmann/json/issues/546)\n- Compiler support errors are inconvenient [\\#544](https://github.com/nlohmann/json/issues/544)\n- Head Elements Sorting [\\#543](https://github.com/nlohmann/json/issues/543)\n- Duplicate symbols error happens while to\\_json/from\\_json method implemented inside entity definition header file [\\#542](https://github.com/nlohmann/json/issues/542)\n- consider adding a bool json::is\\_valid\\(std::string const&\\) non-member function [\\#541](https://github.com/nlohmann/json/issues/541)\n- Help request [\\#539](https://github.com/nlohmann/json/issues/539)\n- How to deal with missing keys in `from\\_json`? [\\#538](https://github.com/nlohmann/json/issues/538)\n- recursive from\\_msgpack implementation will stack overflow [\\#537](https://github.com/nlohmann/json/issues/537)\n- Exception objects must be nothrow copy constructible \\(ERR60-CPP\\) [\\#531](https://github.com/nlohmann/json/issues/531)\n- Support for multiple root elements [\\#529](https://github.com/nlohmann/json/issues/529)\n- Port has\\_shape from dropbox/json11 [\\#528](https://github.com/nlohmann/json/issues/528)\n- dump\\_float: truncation from ptrdiff\\_t to long [\\#527](https://github.com/nlohmann/json/issues/527)\n- Make exception base class visible in basic\\_json [\\#525](https://github.com/nlohmann/json/issues/525)\n- msgpack unit test failures on ppc64 arch [\\#524](https://github.com/nlohmann/json/issues/524)\n- How about split the implementation out, and only leave the interface? [\\#523](https://github.com/nlohmann/json/issues/523)\n- VC++2017 not enough actual parameters for macro 'max' [\\#522](https://github.com/nlohmann/json/issues/522)\n- crash on empty ifstream [\\#521](https://github.com/nlohmann/json/issues/521)\n- Suggestion: Support tabs for indentation when serializing to stream. [\\#520](https://github.com/nlohmann/json/issues/520)\n- Abrt in get\\_number \\(OSS-Fuzz 885\\) [\\#519](https://github.com/nlohmann/json/issues/519)\n- Abrt on unknown address \\(OSS-Fuzz 884\\) [\\#518](https://github.com/nlohmann/json/issues/518)\n- Stack-overflow \\(OSS-Fuzz 869\\) [\\#517](https://github.com/nlohmann/json/issues/517)\n- Assertion error \\(OSS-Fuzz 868\\) [\\#516](https://github.com/nlohmann/json/issues/516)\n- NaN to json and back [\\#515](https://github.com/nlohmann/json/issues/515)\n- Comparison of NaN [\\#514](https://github.com/nlohmann/json/issues/514)\n- why it's not possible to serialize c++11 enums directly [\\#513](https://github.com/nlohmann/json/issues/513)\n- clang compile error: use of overloaded operator '\\<=' is ambiguous   with \\(nlohmann::json{{\"a\", 5}}\\)\\[\"a\"\\] \\<= 10 [\\#512](https://github.com/nlohmann/json/issues/512)\n- Why not also look inside the type for \\(static\\) to\\_json and from\\_json funtions? [\\#511](https://github.com/nlohmann/json/issues/511)\n- Parser issues [\\#509](https://github.com/nlohmann/json/issues/509)\n- I may not understand [\\#507](https://github.com/nlohmann/json/issues/507)\n- VS2017 min / max problem for 2.1.1 [\\#506](https://github.com/nlohmann/json/issues/506)\n- CBOR/MessagePack is not read until the end [\\#505](https://github.com/nlohmann/json/issues/505)\n- Assertion error \\(OSS-Fuzz 856\\) [\\#504](https://github.com/nlohmann/json/issues/504)\n- Return position in parse error exceptions [\\#503](https://github.com/nlohmann/json/issues/503)\n- conversion from/to C array is not supported [\\#502](https://github.com/nlohmann/json/issues/502)\n- error C2338: could not find to\\_json\\(\\) method in T's namespace [\\#501](https://github.com/nlohmann/json/issues/501)\n- Test suite fails in en\\_GB.UTF-8 [\\#500](https://github.com/nlohmann/json/issues/500)\n- cannot use operator\\[\\] with number [\\#499](https://github.com/nlohmann/json/issues/499)\n- consider using \\_\\_cpp\\_exceptions and/or \\_\\_EXCEPTIONS to disable/enable exception support [\\#498](https://github.com/nlohmann/json/issues/498)\n- Stack-overflow \\(OSS-Fuzz issue 814\\) [\\#497](https://github.com/nlohmann/json/issues/497)\n- Using in Unreal Engine - handling custom types conversion [\\#495](https://github.com/nlohmann/json/issues/495)\n- Conversion from vector\\<bool\\> to json fails to build [\\#494](https://github.com/nlohmann/json/issues/494)\n- fill\\_line\\_buffer incorrectly tests m\\_stream for eof but not fail or bad bits [\\#493](https://github.com/nlohmann/json/issues/493)\n- Compiling with \\_GLIBCXX\\_DEBUG yields iterator-comparison warnings during tests [\\#492](https://github.com/nlohmann/json/issues/492)\n- crapy interface [\\#491](https://github.com/nlohmann/json/issues/491)\n- Fix Visual Studo 2013 builds. [\\#490](https://github.com/nlohmann/json/issues/490)\n- Failed to compile with -D\\_GLIBCXX\\_PARALLEL [\\#489](https://github.com/nlohmann/json/issues/489)\n- Input several field with the same name [\\#488](https://github.com/nlohmann/json/issues/488)\n- read in .json file yields strange sizes [\\#487](https://github.com/nlohmann/json/issues/487)\n- json::value\\_t can't be a map's key type in VC++ 2015 [\\#486](https://github.com/nlohmann/json/issues/486)\n- Using fifo\\_map [\\#485](https://github.com/nlohmann/json/issues/485)\n- Cannot get float pointer for value stored as `0` [\\#484](https://github.com/nlohmann/json/issues/484)\n- byte string support [\\#483](https://github.com/nlohmann/json/issues/483)\n- For a header-only library you have to clone 214MB [\\#482](https://github.com/nlohmann/json/issues/482)\n- https://github.com/nlohmann/json\\#execute-unit-tests [\\#481](https://github.com/nlohmann/json/issues/481)\n- Remove deprecated constructor basic\\_json\\(std::istream&\\) [\\#480](https://github.com/nlohmann/json/issues/480)\n- writing the binary json file? [\\#479](https://github.com/nlohmann/json/issues/479)\n- CBOR/MessagePack from uint8\\_t \\* and size [\\#478](https://github.com/nlohmann/json/issues/478)\n- Streaming binary representations  [\\#477](https://github.com/nlohmann/json/issues/477)\n- Reuse memory in to\\_cbor and to\\_msgpack functions [\\#476](https://github.com/nlohmann/json/issues/476)\n- Error Using JSON Library with arrays C++ [\\#475](https://github.com/nlohmann/json/issues/475)\n- Moving forward to version 3.0.0 [\\#474](https://github.com/nlohmann/json/issues/474)\n- Inconsistent behavior in conversion to array type [\\#473](https://github.com/nlohmann/json/issues/473)\n- Create a \\[key:member\\_pointer\\] map to ease parsing custom types [\\#471](https://github.com/nlohmann/json/issues/471)\n- MSVC 2015 update 2 [\\#469](https://github.com/nlohmann/json/issues/469)\n- VS2017 implicit to std::string conversion fix. [\\#464](https://github.com/nlohmann/json/issues/464)\n- How to make sure a string or string literal is a valid JSON? [\\#458](https://github.com/nlohmann/json/issues/458)\n- basic\\_json templated on a \"policy\" class [\\#456](https://github.com/nlohmann/json/issues/456)\n- json::value\\(const json\\_pointer&, ValueType\\) requires exceptions to return the default value. [\\#440](https://github.com/nlohmann/json/issues/440)\n- is it possible merge two json object [\\#428](https://github.com/nlohmann/json/issues/428)\n- Is it possible to turn this into a shared library? [\\#420](https://github.com/nlohmann/json/issues/420)\n- Further thoughts on performance improvements [\\#418](https://github.com/nlohmann/json/issues/418)\n- nan number stored as null [\\#388](https://github.com/nlohmann/json/issues/388)\n- Behavior of operator\\>\\> should more closely resemble that of built-in overloads. [\\#367](https://github.com/nlohmann/json/issues/367)\n- Request: range-based-for over a json-object to expose .first/.second [\\#350](https://github.com/nlohmann/json/issues/350)\n- feature wish: JSONPath [\\#343](https://github.com/nlohmann/json/issues/343)\n- UTF-8/Unicode escape and dump [\\#330](https://github.com/nlohmann/json/issues/330)\n- Serialized value not always can be parsed. [\\#329](https://github.com/nlohmann/json/issues/329)\n- Is there a way to forward declare nlohmann::json? [\\#314](https://github.com/nlohmann/json/issues/314)\n- Exception line [\\#301](https://github.com/nlohmann/json/issues/301)\n- Do not throw exception when default\\_value's type does not match the actual type [\\#278](https://github.com/nlohmann/json/issues/278)\n- dump\\(\\) method doesn't work with a custom allocator [\\#268](https://github.com/nlohmann/json/issues/268)\n- Readme documentation enhancements [\\#248](https://github.com/nlohmann/json/issues/248)\n- Use user-defined exceptions [\\#244](https://github.com/nlohmann/json/issues/244)\n- Incorrect C++11 allocator model support [\\#161](https://github.com/nlohmann/json/issues/161)\n\n- :white\\_check\\_mark: re-added tests for algorithms [\\#879](https://github.com/nlohmann/json/pull/879) ([nlohmann](https://github.com/nlohmann))\n- Overworked library toward 3.0.0 release [\\#875](https://github.com/nlohmann/json/pull/875) ([nlohmann](https://github.com/nlohmann))\n- :rotating\\_light: remove C4996 warnings \\#872 [\\#873](https://github.com/nlohmann/json/pull/873) ([nlohmann](https://github.com/nlohmann))\n- :boom: throwing an exception in case dump encounters a non-UTF-8 string \\#838 [\\#870](https://github.com/nlohmann/json/pull/870) ([nlohmann](https://github.com/nlohmann))\n- :memo: fixing documentation \\#867 [\\#868](https://github.com/nlohmann/json/pull/868) ([nlohmann](https://github.com/nlohmann))\n- iter\\_impl template conformance with C++17 [\\#860](https://github.com/nlohmann/json/pull/860) ([bogemic](https://github.com/bogemic))\n- Std allocator conformance cpp17 [\\#856](https://github.com/nlohmann/json/pull/856) ([bogemic](https://github.com/bogemic))\n- cmake: use BUILD\\_INTERFACE/INSTALL\\_INTERFACE [\\#855](https://github.com/nlohmann/json/pull/855) ([theodelrieu](https://github.com/theodelrieu))\n- to/from\\_json: add a MSVC-specific static\\_assert to force a stacktrace [\\#854](https://github.com/nlohmann/json/pull/854) ([theodelrieu](https://github.com/theodelrieu))\n- Add .natvis for MSVC debug view [\\#844](https://github.com/nlohmann/json/pull/844) ([TinyTinni](https://github.com/TinyTinni))\n- Updated hunter package links [\\#829](https://github.com/nlohmann/json/pull/829) ([jowr](https://github.com/jowr))\n- Typos README [\\#811](https://github.com/nlohmann/json/pull/811) ([Itja](https://github.com/Itja))\n- add forwarding references to json\\_ref constructor [\\#807](https://github.com/nlohmann/json/pull/807) ([theodelrieu](https://github.com/theodelrieu))\n- Add transparent comparator and perfect forwarding support to find\\(\\) and count\\(\\) [\\#795](https://github.com/nlohmann/json/pull/795) ([jseward](https://github.com/jseward))\n- Error : 'identifier \"size\\_t\" is undefined' in linux [\\#793](https://github.com/nlohmann/json/pull/793) ([sonulohani](https://github.com/sonulohani))\n- Fix Visual Studio 2017 warnings [\\#788](https://github.com/nlohmann/json/pull/788) ([jseward](https://github.com/jseward))\n- Fix warning C4706 on Visual Studio 2017 [\\#785](https://github.com/nlohmann/json/pull/785) ([jseward](https://github.com/jseward))\n- Set GENERATE\\_TAGFILE in Doxyfile [\\#783](https://github.com/nlohmann/json/pull/783) ([eld00d](https://github.com/eld00d))\n- using more CMake [\\#765](https://github.com/nlohmann/json/pull/765) ([nlohmann](https://github.com/nlohmann))\n- Simplified istream handing \\#367 [\\#764](https://github.com/nlohmann/json/pull/764) ([pjkundert](https://github.com/pjkundert))\n- Add info for the vcpkg package. [\\#753](https://github.com/nlohmann/json/pull/753) ([gregmarr](https://github.com/gregmarr))\n- fix from\\_json implementation for pair/tuple [\\#708](https://github.com/nlohmann/json/pull/708) ([theodelrieu](https://github.com/theodelrieu))\n- Update json.hpp [\\#686](https://github.com/nlohmann/json/pull/686) ([GoWebProd](https://github.com/GoWebProd))\n- Remove duplicate word [\\#685](https://github.com/nlohmann/json/pull/685) ([daixtrose](https://github.com/daixtrose))\n- To fix compilation issue for intel OSX compiler [\\#682](https://github.com/nlohmann/json/pull/682) ([kbthomp1](https://github.com/kbthomp1))\n- Digraph warning [\\#679](https://github.com/nlohmann/json/pull/679) ([traits](https://github.com/traits))\n- massage -\\> message [\\#678](https://github.com/nlohmann/json/pull/678) ([DmitryKuk](https://github.com/DmitryKuk))\n- Fix \"not constraint\" grammar in docs [\\#674](https://github.com/nlohmann/json/pull/674) ([wincent](https://github.com/wincent))\n- Add documentation for integration with CMake and hunter [\\#671](https://github.com/nlohmann/json/pull/671) ([dan-42](https://github.com/dan-42))\n- REFACTOR: rewrite CMakeLists.txt for better inlcude and reuse [\\#669](https://github.com/nlohmann/json/pull/669) ([dan-42](https://github.com/dan-42))\n- enable\\_testing only if the JSON\\_BuildTests is ON [\\#666](https://github.com/nlohmann/json/pull/666) ([effolkronium](https://github.com/effolkronium))\n- Support moving from rvalues in std::initializer\\_list [\\#663](https://github.com/nlohmann/json/pull/663) ([himikof](https://github.com/himikof))\n- add ensure\\_ascii parameter to dump. \\#330 [\\#654](https://github.com/nlohmann/json/pull/654) ([ryanjmulder](https://github.com/ryanjmulder))\n- Rename BuildTests to JSON\\_BuildTests [\\#652](https://github.com/nlohmann/json/pull/652) ([olegendo](https://github.com/olegendo))\n- Don't include \\<iostream\\>, use std::make\\_shared [\\#650](https://github.com/nlohmann/json/pull/650) ([olegendo](https://github.com/olegendo))\n- Refacto/split basic json [\\#643](https://github.com/nlohmann/json/pull/643) ([theodelrieu](https://github.com/theodelrieu))\n- fix typo in operator\\_\\_notequal example [\\#630](https://github.com/nlohmann/json/pull/630) ([Chocobo1](https://github.com/Chocobo1))\n- Fix MSVC warning C4819 [\\#629](https://github.com/nlohmann/json/pull/629) ([Chocobo1](https://github.com/Chocobo1))\n- \\[BugFix\\] Add parentheses around std::min [\\#626](https://github.com/nlohmann/json/pull/626) ([koemeet](https://github.com/koemeet))\n- add pair/tuple conversions [\\#624](https://github.com/nlohmann/json/pull/624) ([theodelrieu](https://github.com/theodelrieu))\n- remove std::pair support [\\#615](https://github.com/nlohmann/json/pull/615) ([theodelrieu](https://github.com/theodelrieu))\n- Add pair support, fix CompatibleObject conversions \\(fixes \\#600\\) [\\#609](https://github.com/nlohmann/json/pull/609) ([theodelrieu](https://github.com/theodelrieu))\n- \\#550 Fix iterator related compiling issues for Intel icc [\\#598](https://github.com/nlohmann/json/pull/598) ([HenryRLee](https://github.com/HenryRLee))\n- Issue \\#593 Fix the arithmetic operators in the iterator and reverse iterator [\\#595](https://github.com/nlohmann/json/pull/595) ([HenryRLee](https://github.com/HenryRLee))\n- fix doxygen error of basic\\_json::get\\(\\) [\\#583](https://github.com/nlohmann/json/pull/583) ([zhaohuaxishi](https://github.com/zhaohuaxishi))\n- Fixing assignement for iterator wrapper second, and adding unit test [\\#579](https://github.com/nlohmann/json/pull/579) ([Type1J](https://github.com/Type1J))\n- Adding first and second properties to iteration\\_proxy\\_internal [\\#578](https://github.com/nlohmann/json/pull/578) ([Type1J](https://github.com/Type1J))\n- Adding support for Meson. [\\#576](https://github.com/nlohmann/json/pull/576) ([Type1J](https://github.com/Type1J))\n- add enum class default conversions [\\#545](https://github.com/nlohmann/json/pull/545) ([theodelrieu](https://github.com/theodelrieu))\n- Properly pop diagnostics [\\#540](https://github.com/nlohmann/json/pull/540) ([tinloaf](https://github.com/tinloaf))\n- Add Visual Studio 17 image to appveyor build matrix [\\#536](https://github.com/nlohmann/json/pull/536) ([vpetrigo](https://github.com/vpetrigo))\n- UTF8 encoding enhancement [\\#534](https://github.com/nlohmann/json/pull/534) ([TedLyngmo](https://github.com/TedLyngmo))\n- Fix typo [\\#530](https://github.com/nlohmann/json/pull/530) ([berkus](https://github.com/berkus))\n- Make exception base class visible in basic\\_json [\\#526](https://github.com/nlohmann/json/pull/526) ([krzysztofwos](https://github.com/krzysztofwos))\n- :art: Namespace `uint8\\_t` from the C++ stdlib [\\#510](https://github.com/nlohmann/json/pull/510) ([alex-weej](https://github.com/alex-weej))\n- add to\\_json method for C arrays [\\#508](https://github.com/nlohmann/json/pull/508) ([theodelrieu](https://github.com/theodelrieu))\n- Fix -Weffc++ warnings \\(GNU 6.3.1\\) [\\#496](https://github.com/nlohmann/json/pull/496) ([TedLyngmo](https://github.com/TedLyngmo))\n\n## [v2.1.1](https://github.com/nlohmann/json/releases/tag/v2.1.1) (2017-02-25)\n[Full Changelog](https://github.com/nlohmann/json/compare/v2.1.0...v2.1.1)\n\n- warning in the library [\\#472](https://github.com/nlohmann/json/issues/472)\n- How to create an array of Objects? [\\#470](https://github.com/nlohmann/json/issues/470)\n- \\[Bug?\\] Cannot get int pointer, but int64\\_t works [\\#468](https://github.com/nlohmann/json/issues/468)\n- Illegal indirection [\\#467](https://github.com/nlohmann/json/issues/467)\n- in vs can't find linkageId   [\\#466](https://github.com/nlohmann/json/issues/466)\n- Roundtrip error while parsing \"1000000000000000010E5\" [\\#465](https://github.com/nlohmann/json/issues/465)\n- C4996 error and warning with Visual Studio [\\#463](https://github.com/nlohmann/json/issues/463)\n- Support startIndex for from\\_cbor/from\\_msgpack [\\#462](https://github.com/nlohmann/json/issues/462)\n- question: monospace font used in feature slideshow? [\\#460](https://github.com/nlohmann/json/issues/460)\n- Object.keys\\(\\) [\\#459](https://github.com/nlohmann/json/issues/459)\n- Use “, “ as delimiter for json-objects. [\\#457](https://github.com/nlohmann/json/issues/457)\n- Enum -\\> string during serialization and vice versa [\\#455](https://github.com/nlohmann/json/issues/455)\n- doubles are printed as integers [\\#454](https://github.com/nlohmann/json/issues/454)\n- Warnings with Visual Studio c++ \\(VS2015 Update 3\\) [\\#453](https://github.com/nlohmann/json/issues/453)\n- Heap-buffer-overflow \\(OSS-Fuzz issue 585\\) [\\#452](https://github.com/nlohmann/json/issues/452)\n- use of undeclared identifier 'UINT8\\_MAX' [\\#451](https://github.com/nlohmann/json/issues/451)\n- Question on the lifetime managment of objects at the lower levels [\\#449](https://github.com/nlohmann/json/issues/449)\n- Json should not be constructible with 'json\\*' [\\#448](https://github.com/nlohmann/json/issues/448)\n- Move value\\_t to namespace scope [\\#447](https://github.com/nlohmann/json/issues/447)\n- Typo in README.md [\\#446](https://github.com/nlohmann/json/issues/446)\n- make check compilation is unneccesarily slow [\\#445](https://github.com/nlohmann/json/issues/445)\n- Problem in dump\\(\\) in json.h caused by ss.imbue [\\#444](https://github.com/nlohmann/json/issues/444)\n- I want to create Windows Application in Visual Studio 2015 c++, and i have a problem [\\#443](https://github.com/nlohmann/json/issues/443)\n- Implicit conversion issues [\\#442](https://github.com/nlohmann/json/issues/442)\n- Parsing of floats locale dependent [\\#302](https://github.com/nlohmann/json/issues/302)\n\n- Speedup CI builds using cotire [\\#461](https://github.com/nlohmann/json/pull/461) ([tusharpm](https://github.com/tusharpm))\n- TurpentineDistillery feature/locale independent str to num [\\#450](https://github.com/nlohmann/json/pull/450) ([nlohmann](https://github.com/nlohmann))\n- README: adjust boost::optional example [\\#439](https://github.com/nlohmann/json/pull/439) ([jaredgrubb](https://github.com/jaredgrubb))\n- fix \\#414 - comparing to 0 literal [\\#415](https://github.com/nlohmann/json/pull/415) ([stanmihai4](https://github.com/stanmihai4))\n\n## [v2.1.0](https://github.com/nlohmann/json/releases/tag/v2.1.0) (2017-01-28)\n[Full Changelog](https://github.com/nlohmann/json/compare/v2.0.10...v2.1.0)\n\n- Parsing multiple JSON objects from a string or stream [\\#438](https://github.com/nlohmann/json/issues/438)\n- Use-of-uninitialized-value \\(OSS-Fuzz issue 477\\) [\\#437](https://github.com/nlohmann/json/issues/437)\n- add `reserve` function for array to reserve memory before adding json values into it [\\#436](https://github.com/nlohmann/json/issues/436)\n- Typo in examples page [\\#434](https://github.com/nlohmann/json/issues/434)\n- avoid malformed json [\\#433](https://github.com/nlohmann/json/issues/433)\n- How to add json objects to a map? [\\#432](https://github.com/nlohmann/json/issues/432)\n- create json instance from raw json \\(unsigned char\\*\\) [\\#431](https://github.com/nlohmann/json/issues/431)\n- Getting std::invalid\\_argument: stream error when following example [\\#429](https://github.com/nlohmann/json/issues/429)\n- Forward declare-only header? [\\#427](https://github.com/nlohmann/json/issues/427)\n- Implicit conversion from array to object [\\#425](https://github.com/nlohmann/json/issues/425)\n- Automatic ordered JSON [\\#424](https://github.com/nlohmann/json/issues/424)\n- error C4996: 'strerror' when reading file [\\#422](https://github.com/nlohmann/json/issues/422)\n- Get an error - JSON pointer must be empty or begin with '/' [\\#421](https://github.com/nlohmann/json/issues/421)\n- size parameter for parse\\(\\) [\\#419](https://github.com/nlohmann/json/issues/419)\n- json.hpp forcibly defines GCC\\_VERSION [\\#417](https://github.com/nlohmann/json/issues/417)\n- Use-of-uninitialized-value \\(OSS-Fuzz issue 377\\) [\\#416](https://github.com/nlohmann/json/issues/416)\n- comparing to 0 literal [\\#414](https://github.com/nlohmann/json/issues/414)\n- Single char converted to ASCII code instead of string [\\#413](https://github.com/nlohmann/json/issues/413)\n- How to know if a string  was parsed as utf-8? [\\#406](https://github.com/nlohmann/json/issues/406)\n- Overloaded += to add objects to an array makes no sense? [\\#404](https://github.com/nlohmann/json/issues/404)\n- Finding a value in an array [\\#399](https://github.com/nlohmann/json/issues/399)\n- add release information in static function [\\#397](https://github.com/nlohmann/json/issues/397)\n- Optimize memory usage of json objects in combination with binary serialization [\\#373](https://github.com/nlohmann/json/issues/373)\n- Conversion operators not considered [\\#369](https://github.com/nlohmann/json/issues/369)\n- Append \".0\" to serialized floating\\_point values that are digits-only. [\\#362](https://github.com/nlohmann/json/issues/362)\n- Add a customization point for user-defined types [\\#328](https://github.com/nlohmann/json/issues/328)\n- Conformance report for reference [\\#307](https://github.com/nlohmann/json/issues/307)\n- Document the best way to serialize/deserialize user defined types to json [\\#298](https://github.com/nlohmann/json/issues/298)\n- Add StringView template typename to basic\\_json [\\#297](https://github.com/nlohmann/json/issues/297)\n- \\[Improvement\\] Add option to remove exceptions [\\#296](https://github.com/nlohmann/json/issues/296)\n- Performance in miloyip/nativejson-benchmark [\\#202](https://github.com/nlohmann/json/issues/202)\n\n- conversion from/to user-defined types [\\#435](https://github.com/nlohmann/json/pull/435) ([nlohmann](https://github.com/nlohmann))\n- Fix documentation error [\\#430](https://github.com/nlohmann/json/pull/430) ([vjon](https://github.com/vjon))\n- locale-independent num-to-str [\\#378](https://github.com/nlohmann/json/pull/378) ([TurpentineDistillery](https://github.com/TurpentineDistillery))\n\n## [v2.0.10](https://github.com/nlohmann/json/releases/tag/v2.0.10) (2017-01-02)\n[Full Changelog](https://github.com/nlohmann/json/compare/v2.0.9...v2.0.10)\n\n- Heap-buffer-overflow \\(OSS-Fuzz issue 367\\) [\\#412](https://github.com/nlohmann/json/issues/412)\n- Heap-buffer-overflow \\(OSS-Fuzz issue 366\\) [\\#411](https://github.com/nlohmann/json/issues/411)\n- Use-of-uninitialized-value \\(OSS-Fuzz issue 347\\) [\\#409](https://github.com/nlohmann/json/issues/409)\n- Heap-buffer-overflow \\(OSS-Fuzz issue 344\\) [\\#408](https://github.com/nlohmann/json/issues/408)\n- Heap-buffer-overflow \\(OSS-Fuzz issue 343\\) [\\#407](https://github.com/nlohmann/json/issues/407)\n- Heap-buffer-overflow \\(OSS-Fuzz issue 342\\) [\\#405](https://github.com/nlohmann/json/issues/405)\n- strerror throwing error in compiler VS2015 [\\#403](https://github.com/nlohmann/json/issues/403)\n- json::parse of std::string being underlined by Visual Studio [\\#402](https://github.com/nlohmann/json/issues/402)\n- Explicitly getting string without .dump\\(\\)  [\\#401](https://github.com/nlohmann/json/issues/401)\n- Possible to speed up json::parse? [\\#398](https://github.com/nlohmann/json/issues/398)\n- the alphabetic order in the code influence console\\_output. [\\#396](https://github.com/nlohmann/json/issues/396)\n- Execute tests with clang sanitizers [\\#394](https://github.com/nlohmann/json/issues/394)\n- Check if library can be used with ETL [\\#361](https://github.com/nlohmann/json/issues/361)\n\n- Feature/clang sanitize [\\#410](https://github.com/nlohmann/json/pull/410) ([Daniel599](https://github.com/Daniel599))\n- Add Doozer build badge [\\#400](https://github.com/nlohmann/json/pull/400) ([andoma](https://github.com/andoma))\n\n## [v2.0.9](https://github.com/nlohmann/json/releases/tag/v2.0.9) (2016-12-16)\n[Full Changelog](https://github.com/nlohmann/json/compare/v2.0.8...v2.0.9)\n\n- \\#pragma GCC diagnostic ignored \"-Wdocumentation\" [\\#393](https://github.com/nlohmann/json/issues/393)\n- How to parse this json file and write separate sub object as json files? [\\#392](https://github.com/nlohmann/json/issues/392)\n- Integer-overflow \\(OSS-Fuzz issue 267\\) [\\#389](https://github.com/nlohmann/json/issues/389)\n- Implement indefinite-length types from RFC 7049 [\\#387](https://github.com/nlohmann/json/issues/387)\n- template parameter \"T\" is not used in declaring the parameter types of function template [\\#386](https://github.com/nlohmann/json/issues/386)\n- Serializing json instances containing already serialized string values without escaping [\\#385](https://github.com/nlohmann/json/issues/385)\n- Add test cases from RFC 7049 [\\#384](https://github.com/nlohmann/json/issues/384)\n- Add a table of contents to the README file [\\#383](https://github.com/nlohmann/json/issues/383)\n- Update FAQ section in the guidelines for contributing [\\#382](https://github.com/nlohmann/json/issues/382)\n- Allow for forward declaring nlohmann::json [\\#381](https://github.com/nlohmann/json/issues/381)\n- Bug in overflow detection when parsing integers [\\#380](https://github.com/nlohmann/json/issues/380)\n- A unique name to mention the library? [\\#377](https://github.com/nlohmann/json/issues/377)\n- Support for comments. [\\#376](https://github.com/nlohmann/json/issues/376)\n- Non-unique keys in objects. [\\#375](https://github.com/nlohmann/json/issues/375)\n- Request: binary serialization/deserialization [\\#358](https://github.com/nlohmann/json/issues/358)\n\n- Replace class iterator and const\\_iterator by using a single template class to reduce code. [\\#395](https://github.com/nlohmann/json/pull/395) ([Bosswestfalen](https://github.com/Bosswestfalen))\n- Clang: quiet a warning [\\#391](https://github.com/nlohmann/json/pull/391) ([jaredgrubb](https://github.com/jaredgrubb))\n- Fix issue \\#380: Signed integer overflow check [\\#390](https://github.com/nlohmann/json/pull/390) ([qwename](https://github.com/qwename))\n\n## [v2.0.8](https://github.com/nlohmann/json/releases/tag/v2.0.8) (2016-12-02)\n[Full Changelog](https://github.com/nlohmann/json/compare/v2.0.7...v2.0.8)\n\n- Reading from file [\\#374](https://github.com/nlohmann/json/issues/374)\n- Compiler warnings? [\\#372](https://github.com/nlohmann/json/issues/372)\n- docs: how to release a json object in memory? [\\#371](https://github.com/nlohmann/json/issues/371)\n- crash in dump [\\#370](https://github.com/nlohmann/json/issues/370)\n- Coverity issue \\(FORWARD\\_NULL\\) in lexer\\(std::istream& s\\) [\\#368](https://github.com/nlohmann/json/issues/368)\n- json::parse on failed stream gets stuck [\\#366](https://github.com/nlohmann/json/issues/366)\n- Performance improvements [\\#365](https://github.com/nlohmann/json/issues/365)\n- 'to\\_string' is not a member of 'std'  [\\#364](https://github.com/nlohmann/json/issues/364)\n- Optional comment support. [\\#363](https://github.com/nlohmann/json/issues/363)\n- Crash in dump\\(\\) from a static object [\\#359](https://github.com/nlohmann/json/issues/359)\n- json::parse\\(...\\) vs json j; j.parse\\(...\\) [\\#357](https://github.com/nlohmann/json/issues/357)\n- Hi, is there any method to dump  json to string with the insert order rather than alphabets [\\#356](https://github.com/nlohmann/json/issues/356)\n- Provide an example of reading from an json with only a key that has an array of strings. [\\#354](https://github.com/nlohmann/json/issues/354)\n- Request: access with default value. [\\#353](https://github.com/nlohmann/json/issues/353)\n- {} and \\[\\] causes parser error. [\\#352](https://github.com/nlohmann/json/issues/352)\n- Reading a JSON file into a JSON object [\\#351](https://github.com/nlohmann/json/issues/351)\n- Request: 'emplace\\_back' [\\#349](https://github.com/nlohmann/json/issues/349)\n- Is it possible to stream data through the json parser without storing everything in memory? [\\#347](https://github.com/nlohmann/json/issues/347)\n- pure virtual conversion operator [\\#346](https://github.com/nlohmann/json/issues/346)\n- Floating point precision lost [\\#345](https://github.com/nlohmann/json/issues/345)\n- unit-conversions SIGSEGV on armv7hl [\\#303](https://github.com/nlohmann/json/issues/303)\n- Coverity scan fails [\\#299](https://github.com/nlohmann/json/issues/299)\n- Using QString as string type [\\#274](https://github.com/nlohmann/json/issues/274)\n\n## [v2.0.7](https://github.com/nlohmann/json/releases/tag/v2.0.7) (2016-11-02)\n[Full Changelog](https://github.com/nlohmann/json/compare/v2.0.6...v2.0.7)\n\n- JSON5 [\\#348](https://github.com/nlohmann/json/issues/348)\n- Check \"Parsing JSON is a Minefield\" [\\#344](https://github.com/nlohmann/json/issues/344)\n- Allow hex numbers [\\#342](https://github.com/nlohmann/json/issues/342)\n- Convert strings to numbers [\\#341](https://github.com/nlohmann/json/issues/341)\n- \"\"-operators ignore the length parameter [\\#340](https://github.com/nlohmann/json/issues/340)\n- JSON into std::tuple [\\#339](https://github.com/nlohmann/json/issues/339)\n- JSON into vector [\\#335](https://github.com/nlohmann/json/issues/335)\n- Installing with Homebrew on Mac Errors \\(El Capitan\\) [\\#331](https://github.com/nlohmann/json/issues/331)\n- g++ make check results in error [\\#312](https://github.com/nlohmann/json/issues/312)\n- Cannot convert from 'json' to 'char' [\\#276](https://github.com/nlohmann/json/issues/276)\n- Please add a Pretty-Print option for arrays to stay always in one line [\\#229](https://github.com/nlohmann/json/issues/229)\n- Conversion to STL map\\<string, vector\\<int\\>\\> gives error [\\#220](https://github.com/nlohmann/json/issues/220)\n- std::unorderd\\_map cannot be used as ObjectType [\\#164](https://github.com/nlohmann/json/issues/164)\n\n- fix minor grammar/style issue in README.md [\\#336](https://github.com/nlohmann/json/pull/336) ([seeekr](https://github.com/seeekr))\n\n## [v2.0.6](https://github.com/nlohmann/json/releases/tag/v2.0.6) (2016-10-15)\n[Full Changelog](https://github.com/nlohmann/json/compare/v2.0.5...v2.0.6)\n\n- How to handle json files? [\\#333](https://github.com/nlohmann/json/issues/333)\n- This file requires compiler and library support .... [\\#332](https://github.com/nlohmann/json/issues/332)\n- Segmentation fault on saving json to file [\\#326](https://github.com/nlohmann/json/issues/326)\n- parse error - unexpected \\<uninitialized\\> with 2.0.5 [\\#325](https://github.com/nlohmann/json/issues/325)\n- Add nested object capability to pointers [\\#323](https://github.com/nlohmann/json/issues/323)\n- Fix usage examples' comments for std::multiset [\\#322](https://github.com/nlohmann/json/issues/322)\n- json\\_unit runs forever when executed in build directory [\\#319](https://github.com/nlohmann/json/issues/319)\n- Visual studio 2015 update3 true != TRUE [\\#317](https://github.com/nlohmann/json/issues/317)\n- releasing single header file in compressed format [\\#316](https://github.com/nlohmann/json/issues/316)\n- json object from std::ifstream [\\#315](https://github.com/nlohmann/json/issues/315)\n\n- make has\\_mapped\\_type struct friendly [\\#324](https://github.com/nlohmann/json/pull/324) ([vpetrigo](https://github.com/vpetrigo))\n- Fix usage examples' comments for std::multiset [\\#321](https://github.com/nlohmann/json/pull/321) ([vasild](https://github.com/vasild))\n- Include dir relocation [\\#318](https://github.com/nlohmann/json/pull/318) ([ChristophJud](https://github.com/ChristophJud))\n- trivial documentation fix [\\#313](https://github.com/nlohmann/json/pull/313) ([5tefan](https://github.com/5tefan))\n\n## [v2.0.5](https://github.com/nlohmann/json/releases/tag/v2.0.5) (2016-09-14)\n[Full Changelog](https://github.com/nlohmann/json/compare/v2.0.4...v2.0.5)\n\n- \\[feature request\\]: schema validator and comments [\\#311](https://github.com/nlohmann/json/issues/311)\n- make json\\_benchmarks no longer working in 2.0.4 [\\#310](https://github.com/nlohmann/json/issues/310)\n- Segmentation fault \\(core dumped\\) [\\#309](https://github.com/nlohmann/json/issues/309)\n- No matching member function for call to 'get\\_impl' [\\#308](https://github.com/nlohmann/json/issues/308)\n\n## [v2.0.4](https://github.com/nlohmann/json/releases/tag/v2.0.4) (2016-09-11)\n[Full Changelog](https://github.com/nlohmann/json/compare/v2.0.3...v2.0.4)\n\n- Parsing fails without space at end of file [\\#306](https://github.com/nlohmann/json/issues/306)\n- json schema validator [\\#305](https://github.com/nlohmann/json/issues/305)\n- Unused variable warning [\\#304](https://github.com/nlohmann/json/issues/304)\n\n## [v2.0.3](https://github.com/nlohmann/json/releases/tag/v2.0.3) (2016-08-31)\n[Full Changelog](https://github.com/nlohmann/json/compare/v2.0.2...v2.0.3)\n\n- warning C4706: assignment within conditional expression [\\#295](https://github.com/nlohmann/json/issues/295)\n- Strip comments / Minify [\\#294](https://github.com/nlohmann/json/issues/294)\n- Q: Is it possible to build json tree from already UTF8 encoded values? [\\#293](https://github.com/nlohmann/json/issues/293)\n- Equality operator results in array when assigned object [\\#292](https://github.com/nlohmann/json/issues/292)\n- Support for integers not from the range \\[-\\(2\\*\\*53\\)+1, \\(2\\*\\*53\\)-1\\] in parser [\\#291](https://github.com/nlohmann/json/issues/291)\n- Support for iterator-range parsing [\\#290](https://github.com/nlohmann/json/issues/290)\n- Horribly inconsistent behavior between const/non-const reference in operator \\[\\] \\(\\) [\\#289](https://github.com/nlohmann/json/issues/289)\n- Silently get numbers into smaller types [\\#288](https://github.com/nlohmann/json/issues/288)\n- Incorrect parsing of large int64\\_t numbers [\\#287](https://github.com/nlohmann/json/issues/287)\n- \\[question\\]: macro to disable floating point support [\\#284](https://github.com/nlohmann/json/issues/284)\n\n- unit-constructor1.cpp: Fix floating point truncation warning [\\#300](https://github.com/nlohmann/json/pull/300) ([t-b](https://github.com/t-b))\n\n## [v2.0.2](https://github.com/nlohmann/json/releases/tag/v2.0.2) (2016-07-31)\n[Full Changelog](https://github.com/nlohmann/json/compare/v2.0.1...v2.0.2)\n\n- can function dump\\(\\)  return string in the order I push in the json object ? [\\#286](https://github.com/nlohmann/json/issues/286)\n- Error on the Mac: Undefined symbols for architecture x86\\_64 [\\#285](https://github.com/nlohmann/json/issues/285)\n- value\\(\\) does not work with \\_json\\_pointer types [\\#283](https://github.com/nlohmann/json/issues/283)\n- Build error for std::int64 [\\#282](https://github.com/nlohmann/json/issues/282)\n- strings can't be accessed after dump\\(\\)-\\>parse\\(\\) - type is lost [\\#281](https://github.com/nlohmann/json/issues/281)\n- Easy serialization of classes [\\#280](https://github.com/nlohmann/json/issues/280)\n- recursive data structures [\\#277](https://github.com/nlohmann/json/issues/277)\n- hexify\\(\\) function emits conversion warning [\\#270](https://github.com/nlohmann/json/issues/270)\n\n- let the makefile choose the correct sed [\\#279](https://github.com/nlohmann/json/pull/279) ([murinicanor](https://github.com/murinicanor))\n- Update hexify to use array lookup instead of ternary \\(\\#270\\) [\\#275](https://github.com/nlohmann/json/pull/275) ([dtoma](https://github.com/dtoma))\n\n## [v2.0.1](https://github.com/nlohmann/json/releases/tag/v2.0.1) (2016-06-28)\n[Full Changelog](https://github.com/nlohmann/json/compare/v2.0.0...v2.0.1)\n\n- Compilation error. [\\#273](https://github.com/nlohmann/json/issues/273)\n- dump\\(\\) performance degradation in v2 [\\#272](https://github.com/nlohmann/json/issues/272)\n\n- fixed a tiny typo [\\#271](https://github.com/nlohmann/json/pull/271) ([feroldi](https://github.com/feroldi))\n\n## [v2.0.0](https://github.com/nlohmann/json/releases/tag/v2.0.0) (2016-06-23)\n[Full Changelog](https://github.com/nlohmann/json/compare/v1.1.0...v2.0.0)\n\n- json::diff generates incorrect patch when removing multiple array elements. [\\#269](https://github.com/nlohmann/json/issues/269)\n- Docs - What does Json\\[key\\] return? [\\#267](https://github.com/nlohmann/json/issues/267)\n- Compiler Errors With JSON.hpp [\\#265](https://github.com/nlohmann/json/issues/265)\n- Ambiguous push\\_back and operator+= overloads [\\#263](https://github.com/nlohmann/json/issues/263)\n- Preseving order of items in json [\\#262](https://github.com/nlohmann/json/issues/262)\n- '\\' char problem in strings [\\#261](https://github.com/nlohmann/json/issues/261)\n- VS2015 compile fail [\\#260](https://github.com/nlohmann/json/issues/260)\n- -Wconversion warning [\\#259](https://github.com/nlohmann/json/issues/259)\n- Maybe a bug [\\#258](https://github.com/nlohmann/json/issues/258)\n- Few tests failed on Visual C++ 2015 [\\#257](https://github.com/nlohmann/json/issues/257)\n- Access keys when iteration with new for loop C++11 [\\#256](https://github.com/nlohmann/json/issues/256)\n- multiline text values [\\#255](https://github.com/nlohmann/json/issues/255)\n- Error when using json in g++ [\\#254](https://github.com/nlohmann/json/issues/254)\n- is the release 2.0? [\\#253](https://github.com/nlohmann/json/issues/253)\n- concatenate objects [\\#252](https://github.com/nlohmann/json/issues/252)\n- Encoding [\\#251](https://github.com/nlohmann/json/issues/251)\n- Unable to build example for constructing json object with stringstreams [\\#250](https://github.com/nlohmann/json/issues/250)\n- Hexadecimal support [\\#249](https://github.com/nlohmann/json/issues/249)\n- Update long-term goals [\\#246](https://github.com/nlohmann/json/issues/246)\n- Contribution To This Json Project [\\#245](https://github.com/nlohmann/json/issues/245)\n- Trouble using parser with initial dictionary [\\#243](https://github.com/nlohmann/json/issues/243)\n- Unit test fails when doing a CMake out-of-tree build [\\#241](https://github.com/nlohmann/json/issues/241)\n- -Wconversion warnings [\\#239](https://github.com/nlohmann/json/issues/239)\n- Additional integration options [\\#237](https://github.com/nlohmann/json/issues/237)\n- .get\\<std::string\\>\\(\\) works for non spaced string but returns as array for spaced/longer strings [\\#236](https://github.com/nlohmann/json/issues/236)\n- ambiguous overload for 'push\\_back' and 'operator+=' [\\#235](https://github.com/nlohmann/json/issues/235)\n- Can't use basic\\_json::iterator as a base iterator for std::move\\_iterator [\\#233](https://github.com/nlohmann/json/issues/233)\n- json object's creation can freezes execution [\\#231](https://github.com/nlohmann/json/issues/231)\n- Incorrect dumping of parsed numbers with exponents, but without decimal places [\\#230](https://github.com/nlohmann/json/issues/230)\n- double values are serialized with commas as decimal points [\\#228](https://github.com/nlohmann/json/issues/228)\n- Move semantics with std::initializer\\_list [\\#225](https://github.com/nlohmann/json/issues/225)\n- replace emplace [\\#224](https://github.com/nlohmann/json/issues/224)\n- abort during getline in yyfill [\\#223](https://github.com/nlohmann/json/issues/223)\n- free\\(\\): invalid pointer error in GCC 5.2.1 [\\#221](https://github.com/nlohmann/json/issues/221)\n- Error compile Android NDK  error: 'strtof' is not a member of 'std' [\\#219](https://github.com/nlohmann/json/issues/219)\n- Wrong link in the README.md [\\#217](https://github.com/nlohmann/json/issues/217)\n- Wide character strings not supported [\\#216](https://github.com/nlohmann/json/issues/216)\n- Memory allocations using range-based for loops [\\#214](https://github.com/nlohmann/json/issues/214)\n- would you like to support gcc 4.8.1?  [\\#211](https://github.com/nlohmann/json/issues/211)\n- Reading concatenated json's from an istream [\\#210](https://github.com/nlohmann/json/issues/210)\n- Conflicting typedef of ssize\\_t on Windows 32 bit when using Boost.Python [\\#204](https://github.com/nlohmann/json/issues/204)\n- Inconsistency between operator\\[\\] and push\\_back [\\#203](https://github.com/nlohmann/json/issues/203)\n- Small bugs in json.hpp \\(get\\_number\\) and unit.cpp \\(non-standard integer type test\\) [\\#199](https://github.com/nlohmann/json/issues/199)\n- GCC/clang floating point parsing bug in strtod\\(\\) [\\#195](https://github.com/nlohmann/json/issues/195)\n- What is within scope? [\\#192](https://github.com/nlohmann/json/issues/192)\n- Bugs in miloyip/nativejson-benchmark: roundtrips [\\#187](https://github.com/nlohmann/json/issues/187)\n- Floating point exceptions [\\#181](https://github.com/nlohmann/json/issues/181)\n- Integer conversion to unsigned [\\#178](https://github.com/nlohmann/json/issues/178)\n- map string string fails to compile [\\#176](https://github.com/nlohmann/json/issues/176)\n- In basic\\_json::basic\\_json\\(const CompatibleArrayType& val\\), the requirement of CompatibleArrayType is not strict enough. [\\#174](https://github.com/nlohmann/json/issues/174)\n- Provide a FAQ [\\#163](https://github.com/nlohmann/json/issues/163)\n- Implicit assignment to std::string fails [\\#144](https://github.com/nlohmann/json/issues/144)\n\n- Fix Issue \\#265 [\\#266](https://github.com/nlohmann/json/pull/266) ([06needhamt](https://github.com/06needhamt))\n- Define CMake/CTest tests [\\#247](https://github.com/nlohmann/json/pull/247) ([robertmrk](https://github.com/robertmrk))\n- Out of tree builds and a few other miscellaneous CMake cleanups. [\\#242](https://github.com/nlohmann/json/pull/242) ([ChrisKitching](https://github.com/ChrisKitching))\n- Implement additional integration options [\\#238](https://github.com/nlohmann/json/pull/238) ([robertmrk](https://github.com/robertmrk))\n- make serialization locale-independent [\\#232](https://github.com/nlohmann/json/pull/232) ([nlohmann](https://github.com/nlohmann))\n- fixes \\#223 by updating README.md [\\#227](https://github.com/nlohmann/json/pull/227) ([kevin--](https://github.com/kevin--))\n- Use namespace std for int64\\_t and uint64\\_t [\\#226](https://github.com/nlohmann/json/pull/226) ([lv-zheng](https://github.com/lv-zheng))\n- Added missing cerrno header to fix ERANGE compile error on android [\\#222](https://github.com/nlohmann/json/pull/222) ([Teemperor](https://github.com/Teemperor))\n- Corrected readme [\\#218](https://github.com/nlohmann/json/pull/218) ([Annihil](https://github.com/Annihil))\n- Create PULL\\_REQUEST\\_TEMPLATE.md [\\#213](https://github.com/nlohmann/json/pull/213) ([whackashoe](https://github.com/whackashoe))\n- fixed noexcept; added constexpr [\\#208](https://github.com/nlohmann/json/pull/208) ([nlohmann](https://github.com/nlohmann))\n- Add support for afl-fuzz testing [\\#207](https://github.com/nlohmann/json/pull/207) ([mykter](https://github.com/mykter))\n- replaced ssize\\_t occurrences with auto \\(addresses \\#204\\) [\\#205](https://github.com/nlohmann/json/pull/205) ([nlohmann](https://github.com/nlohmann))\n- Fixed issue \\#199 - Small bugs in json.hpp \\(get\\_number\\) and unit.cpp \\(non-standard integer type test\\) [\\#200](https://github.com/nlohmann/json/pull/200) ([twelsby](https://github.com/twelsby))\n- Fix broken link [\\#197](https://github.com/nlohmann/json/pull/197) ([vog](https://github.com/vog))\n- Issue \\#195 - update Travis to Trusty due to gcc/clang strtod\\(\\) bug [\\#196](https://github.com/nlohmann/json/pull/196) ([twelsby](https://github.com/twelsby))\n- Issue \\#178 - Extending support to full uint64\\_t/int64\\_t range and unsigned type \\(updated\\) [\\#193](https://github.com/nlohmann/json/pull/193) ([twelsby](https://github.com/twelsby))\n\n## [v1.1.0](https://github.com/nlohmann/json/releases/tag/v1.1.0) (2016-01-24)\n[Full Changelog](https://github.com/nlohmann/json/compare/v1.0.0...v1.1.0)\n\n- Small error in pull \\#185 [\\#194](https://github.com/nlohmann/json/issues/194)\n- Bugs in miloyip/nativejson-benchmark: floating-point parsing [\\#186](https://github.com/nlohmann/json/issues/186)\n- Floating point equality [\\#185](https://github.com/nlohmann/json/issues/185)\n- Unused variables in catch [\\#180](https://github.com/nlohmann/json/issues/180)\n- Typo in documentation [\\#179](https://github.com/nlohmann/json/issues/179)\n- JSON performance benchmark comparision [\\#177](https://github.com/nlohmann/json/issues/177)\n- Since re2c is often ignored in pull requests, it may make sense to make a contributing.md file [\\#175](https://github.com/nlohmann/json/issues/175)\n- Question about exceptions [\\#173](https://github.com/nlohmann/json/issues/173)\n- Android? [\\#172](https://github.com/nlohmann/json/issues/172)\n- Cannot index by key of type static constexpr const char\\* [\\#171](https://github.com/nlohmann/json/issues/171)\n- Add assertions [\\#168](https://github.com/nlohmann/json/issues/168)\n- MSVC 2015 build fails when attempting to compare object\\_t [\\#167](https://github.com/nlohmann/json/issues/167)\n- Member detector is not portable [\\#166](https://github.com/nlohmann/json/issues/166)\n- Unnecessary const\\_cast [\\#162](https://github.com/nlohmann/json/issues/162)\n- Question about get\\_ref\\(\\) [\\#128](https://github.com/nlohmann/json/issues/128)\n- range based for loop for objects [\\#83](https://github.com/nlohmann/json/issues/83)\n- Consider submitting this to the Boost Library Incubator [\\#66](https://github.com/nlohmann/json/issues/66)\n\n- Fixed Issue \\#186 - add strto\\(f|d|ld\\) overload wrappers, \"-0.0\" special case and FP trailing zero [\\#191](https://github.com/nlohmann/json/pull/191) ([twelsby](https://github.com/twelsby))\n- Issue \\#185 - remove approx\\(\\) and use \\#pragma to kill warnings [\\#190](https://github.com/nlohmann/json/pull/190) ([twelsby](https://github.com/twelsby))\n- Fixed Issue \\#171 - added two extra template overloads of operator\\[\\] for T\\* arguments [\\#189](https://github.com/nlohmann/json/pull/189) ([twelsby](https://github.com/twelsby))\n- Fixed issue \\#167 - removed operator ValueType\\(\\) condition for VS2015 [\\#188](https://github.com/nlohmann/json/pull/188) ([twelsby](https://github.com/twelsby))\n- Implementation of get\\_ref\\(\\) [\\#184](https://github.com/nlohmann/json/pull/184) ([dariomt](https://github.com/dariomt))\n- Fixed some typos in CONTRIBUTING.md [\\#182](https://github.com/nlohmann/json/pull/182) ([nibroc](https://github.com/nibroc))\n\n## [v1.0.0](https://github.com/nlohmann/json/releases/tag/v1.0.0) (2015-12-27)\n[Full Changelog](https://github.com/nlohmann/json/compare/v1.0.0-rc1...v1.0.0)\n\n- add key name to exception [\\#160](https://github.com/nlohmann/json/issues/160)\n- Getting member discarding qualifyer [\\#159](https://github.com/nlohmann/json/issues/159)\n- basic\\_json::iterator::value\\(\\) output includes quotes while basic\\_json::iterator::key\\(\\) doesn't [\\#158](https://github.com/nlohmann/json/issues/158)\n- Indexing `const basic\\_json\\<\\>` with `const basic\\_string\\<char\\>` [\\#157](https://github.com/nlohmann/json/issues/157)\n- token\\_type\\_name\\(token\\_type t\\): not all control paths return a value [\\#156](https://github.com/nlohmann/json/issues/156)\n- prevent json.hpp from emitting compiler warnings [\\#154](https://github.com/nlohmann/json/issues/154)\n- json::parse\\(string\\) does not check utf8 bom [\\#152](https://github.com/nlohmann/json/issues/152)\n- unsigned 64bit values output as signed [\\#151](https://github.com/nlohmann/json/issues/151)\n- Wish feature: json5 [\\#150](https://github.com/nlohmann/json/issues/150)\n- Unable to compile on MSVC 2015 with SDL checking enabled: This function or variable may be unsafe. [\\#149](https://github.com/nlohmann/json/issues/149)\n- \"Json Object\" type does not keep object order [\\#148](https://github.com/nlohmann/json/issues/148)\n- dump\\(\\)  convert strings encoded by utf-8 to shift-jis on windows 10.  [\\#147](https://github.com/nlohmann/json/issues/147)\n- Unable to get field names in a json object [\\#145](https://github.com/nlohmann/json/issues/145)\n- Question: Is the use of incomplete type correct? [\\#138](https://github.com/nlohmann/json/issues/138)\n- json.hpp:5746:32: error: 'to\\_string' is not a member of 'std' [\\#136](https://github.com/nlohmann/json/issues/136)\n- Bug in basic\\_json::operator\\[\\] const overload [\\#135](https://github.com/nlohmann/json/issues/135)\n- wrong enable\\_if for const pointer \\(instead of pointer-to-const\\) [\\#134](https://github.com/nlohmann/json/issues/134)\n- overload of at\\(\\) with default value [\\#133](https://github.com/nlohmann/json/issues/133)\n- Splitting source [\\#132](https://github.com/nlohmann/json/issues/132)\n- Question about get\\_ptr\\(\\) [\\#127](https://github.com/nlohmann/json/issues/127)\n- Visual Studio 14 Debug assertion failed [\\#125](https://github.com/nlohmann/json/issues/125)\n- Memory leak in face of exceptions [\\#118](https://github.com/nlohmann/json/issues/118)\n- Find and Count for arrays [\\#117](https://github.com/nlohmann/json/issues/117)\n- dynamically constructing an arbitrarily nested object [\\#114](https://github.com/nlohmann/json/issues/114)\n- Returning any data type [\\#113](https://github.com/nlohmann/json/issues/113)\n- Compile error with g++ 4.9.3 cygwin 64-bit [\\#112](https://github.com/nlohmann/json/issues/112)\n- insert json array issue with gcc4.8.2 [\\#110](https://github.com/nlohmann/json/issues/110)\n- error: unterminated raw string [\\#109](https://github.com/nlohmann/json/issues/109)\n- vector\\<json\\> copy constructor really weird [\\#108](https://github.com/nlohmann/json/issues/108)\n- \\[clang-3.6.2\\] string/sstream with number to json issue [\\#107](https://github.com/nlohmann/json/issues/107)\n- maintaining order of keys during iteration [\\#106](https://github.com/nlohmann/json/issues/106)\n- object field accessors [\\#103](https://github.com/nlohmann/json/issues/103)\n- v8pp and json [\\#95](https://github.com/nlohmann/json/issues/95)\n- Wishlist [\\#65](https://github.com/nlohmann/json/issues/65)\n- Windows/Visual Studio \\(through 2013\\) is unsupported [\\#62](https://github.com/nlohmann/json/issues/62)\n\n- Replace sprintf with hex function, this fixes \\#149 [\\#153](https://github.com/nlohmann/json/pull/153) ([whackashoe](https://github.com/whackashoe))\n- Fix character skipping after a surrogate pair [\\#146](https://github.com/nlohmann/json/pull/146) ([robertmrk](https://github.com/robertmrk))\n- Detect correctly pointer-to-const [\\#137](https://github.com/nlohmann/json/pull/137) ([dariomt](https://github.com/dariomt))\n- disabled \"CopyAssignable\" test for MSVC in Debug mode, see \\#125 [\\#131](https://github.com/nlohmann/json/pull/131) ([dariomt](https://github.com/dariomt))\n- removed stream operator for iterator, resolution for \\#125 [\\#130](https://github.com/nlohmann/json/pull/130) ([dariomt](https://github.com/dariomt))\n- fixed typos in comments for examples [\\#129](https://github.com/nlohmann/json/pull/129) ([dariomt](https://github.com/dariomt))\n- Remove superfluous inefficiency [\\#126](https://github.com/nlohmann/json/pull/126) ([d-frey](https://github.com/d-frey))\n- remove invalid parameter '-stdlib=libc++' in CMakeLists.txt [\\#124](https://github.com/nlohmann/json/pull/124) ([emvivre](https://github.com/emvivre))\n- exception-safe object creation, fixes \\#118 [\\#122](https://github.com/nlohmann/json/pull/122) ([d-frey](https://github.com/d-frey))\n- Fix small oversight. [\\#121](https://github.com/nlohmann/json/pull/121) ([ColinH](https://github.com/ColinH))\n- Overload parse\\(\\) to accept an rvalue reference [\\#120](https://github.com/nlohmann/json/pull/120) ([silverweed](https://github.com/silverweed))\n- Use the right variable name in doc string [\\#115](https://github.com/nlohmann/json/pull/115) ([whoshuu](https://github.com/whoshuu))\n\n## [v1.0.0-rc1](https://github.com/nlohmann/json/releases/tag/v1.0.0-rc1) (2015-07-26)\n- Finish documenting the public interface in Doxygen [\\#102](https://github.com/nlohmann/json/issues/102)\n- Binary string causes numbers to be dumped as hex [\\#101](https://github.com/nlohmann/json/issues/101)\n- failed to iterator json object with reverse\\_iterator [\\#100](https://github.com/nlohmann/json/issues/100)\n- 'noexcept' : unknown override specifier [\\#99](https://github.com/nlohmann/json/issues/99)\n- json float parsing problem [\\#98](https://github.com/nlohmann/json/issues/98)\n- Adjust wording to JSON RFC [\\#97](https://github.com/nlohmann/json/issues/97)\n- 17 MB / 90 MB repo size!? [\\#96](https://github.com/nlohmann/json/issues/96)\n- static analysis warnings [\\#94](https://github.com/nlohmann/json/issues/94)\n- reverse\\_iterator operator inheritance problem [\\#93](https://github.com/nlohmann/json/issues/93)\n- init error [\\#92](https://github.com/nlohmann/json/issues/92)\n- access by \\(const\\) reference [\\#91](https://github.com/nlohmann/json/issues/91)\n- is\\_integer and is\\_float tests [\\#90](https://github.com/nlohmann/json/issues/90)\n- Nonstandard integer type [\\#89](https://github.com/nlohmann/json/issues/89)\n- static library build [\\#84](https://github.com/nlohmann/json/issues/84)\n- lexer::get\\_number return NAN [\\#82](https://github.com/nlohmann/json/issues/82)\n- MinGW have no std::to\\_string [\\#80](https://github.com/nlohmann/json/issues/80)\n- Incorrect behaviour of basic\\_json::count method [\\#78](https://github.com/nlohmann/json/issues/78)\n- Invoking is\\_array\\(\\) function creates \"null\" value [\\#77](https://github.com/nlohmann/json/issues/77)\n- dump\\(\\) / parse\\(\\) not idempotent [\\#76](https://github.com/nlohmann/json/issues/76)\n- Handle infinity and NaN cases [\\#70](https://github.com/nlohmann/json/issues/70)\n- errors in g++-4.8.1 [\\#68](https://github.com/nlohmann/json/issues/68)\n- Keys when iterating over objects [\\#67](https://github.com/nlohmann/json/issues/67)\n- Compilation results in tons of warnings [\\#64](https://github.com/nlohmann/json/issues/64)\n- Complete brief documentation [\\#61](https://github.com/nlohmann/json/issues/61)\n- Double quotation mark is not parsed correctly [\\#60](https://github.com/nlohmann/json/issues/60)\n- Get coverage back to 100% [\\#58](https://github.com/nlohmann/json/issues/58)\n- erase elements using iterators [\\#57](https://github.com/nlohmann/json/issues/57)\n- Removing item from array [\\#56](https://github.com/nlohmann/json/issues/56)\n- Serialize/Deserialize like PHP? [\\#55](https://github.com/nlohmann/json/issues/55)\n- Numbers as keys [\\#54](https://github.com/nlohmann/json/issues/54)\n- Why are elements alphabetized on key while iterating? [\\#53](https://github.com/nlohmann/json/issues/53)\n- Document erase, count, and iterators key and value [\\#52](https://github.com/nlohmann/json/issues/52)\n- Do not use std::to\\_string [\\#51](https://github.com/nlohmann/json/issues/51)\n- Supported compilers [\\#50](https://github.com/nlohmann/json/issues/50)\n- Confused about iterating through json objects [\\#49](https://github.com/nlohmann/json/issues/49)\n- Use non-member begin/end [\\#48](https://github.com/nlohmann/json/issues/48)\n- Erase key [\\#47](https://github.com/nlohmann/json/issues/47)\n- Key iterator [\\#46](https://github.com/nlohmann/json/issues/46)\n- Add count member function [\\#45](https://github.com/nlohmann/json/issues/45)\n- Problem getting vector \\(array\\) of strings [\\#44](https://github.com/nlohmann/json/issues/44)\n- Compilation error due to assuming that private=public [\\#43](https://github.com/nlohmann/json/issues/43)\n- Use of deprecated implicit copy constructor [\\#42](https://github.com/nlohmann/json/issues/42)\n- Printing attribute names [\\#39](https://github.com/nlohmann/json/issues/39)\n- dumping a small number\\_float just outputs 0.000000 [\\#37](https://github.com/nlohmann/json/issues/37)\n- find is error [\\#32](https://github.com/nlohmann/json/issues/32)\n- Avoid using spaces when encoding without pretty print [\\#31](https://github.com/nlohmann/json/issues/31)\n- Cannot encode long numbers [\\#30](https://github.com/nlohmann/json/issues/30)\n- segmentation fault when iterating over empty arrays/objects [\\#28](https://github.com/nlohmann/json/issues/28)\n- Creating an empty array [\\#27](https://github.com/nlohmann/json/issues/27)\n- Custom allocator support [\\#25](https://github.com/nlohmann/json/issues/25)\n- make the type of the used string container customizable [\\#20](https://github.com/nlohmann/json/issues/20)\n- Improper parsing of JSON string \"\\\\\" [\\#17](https://github.com/nlohmann/json/issues/17)\n- create a header-only version [\\#16](https://github.com/nlohmann/json/issues/16)\n- Don't return \"const values\" [\\#15](https://github.com/nlohmann/json/issues/15)\n- Add to\\_string overload for indentation [\\#13](https://github.com/nlohmann/json/issues/13)\n- string parser does not recognize uncompliant strings [\\#12](https://github.com/nlohmann/json/issues/12)\n- possible double-free in find function [\\#11](https://github.com/nlohmann/json/issues/11)\n- UTF-8 encoding/deconding/testing [\\#10](https://github.com/nlohmann/json/issues/10)\n- move code into namespace [\\#9](https://github.com/nlohmann/json/issues/9)\n- free functions for explicit objects and arrays in initializer lists [\\#8](https://github.com/nlohmann/json/issues/8)\n- unique\\_ptr for ownership [\\#7](https://github.com/nlohmann/json/issues/7)\n- Add unit tests [\\#4](https://github.com/nlohmann/json/issues/4)\n- Drop C++98 support [\\#3](https://github.com/nlohmann/json/issues/3)\n- Test case coverage [\\#2](https://github.com/nlohmann/json/issues/2)\n- Runtime error in Travis job [\\#1](https://github.com/nlohmann/json/issues/1)\n\n- Keyword 'inline' is useless when member functions are defined in headers [\\#87](https://github.com/nlohmann/json/pull/87) ([ahamez](https://github.com/ahamez))\n- Remove useless typename [\\#86](https://github.com/nlohmann/json/pull/86) ([ahamez](https://github.com/ahamez))\n- Avoid warning with Xcode's clang [\\#85](https://github.com/nlohmann/json/pull/85) ([ahamez](https://github.com/ahamez))\n-  Fix typos [\\#73](https://github.com/nlohmann/json/pull/73) ([aqnouch](https://github.com/aqnouch))\n- Replace `default\\_callback` function with `nullptr` and check for null… [\\#72](https://github.com/nlohmann/json/pull/72) ([aburgh](https://github.com/aburgh))\n- support enum [\\#71](https://github.com/nlohmann/json/pull/71) ([likebeta](https://github.com/likebeta))\n- Fix performance regression introduced with the parsing callback feature. [\\#69](https://github.com/nlohmann/json/pull/69) ([aburgh](https://github.com/aburgh))\n- Improve the implementations of the comparission-operators [\\#63](https://github.com/nlohmann/json/pull/63) ([Florianjw](https://github.com/Florianjw))\n- Fix compilation of json\\_unit with GCC 5 [\\#59](https://github.com/nlohmann/json/pull/59) ([dkopecek](https://github.com/dkopecek))\n- Parse streams incrementally. [\\#40](https://github.com/nlohmann/json/pull/40) ([aburgh](https://github.com/aburgh))\n- Feature/small float serialization [\\#38](https://github.com/nlohmann/json/pull/38) ([jrandall](https://github.com/jrandall))\n- template version with re2c scanner [\\#36](https://github.com/nlohmann/json/pull/36) ([nlohmann](https://github.com/nlohmann))\n- more descriptive documentation in example [\\#33](https://github.com/nlohmann/json/pull/33) ([luxe](https://github.com/luxe))\n- Fix string conversion under Clang [\\#26](https://github.com/nlohmann/json/pull/26) ([wancw](https://github.com/wancw))\n- Fixed dumping of strings [\\#24](https://github.com/nlohmann/json/pull/24) ([Teemperor](https://github.com/Teemperor))\n- Added a remark to the readme that coverage is GCC only for now [\\#23](https://github.com/nlohmann/json/pull/23) ([Teemperor](https://github.com/Teemperor))\n- Unicode escaping [\\#22](https://github.com/nlohmann/json/pull/22) ([Teemperor](https://github.com/Teemperor))\n- Implemented the JSON spec for string parsing for everything but the \\uXXXX escaping [\\#21](https://github.com/nlohmann/json/pull/21) ([Teemperor](https://github.com/Teemperor))\n- add the std iterator typedefs to iterator and const\\_iterator [\\#19](https://github.com/nlohmann/json/pull/19) ([kirkshoop](https://github.com/kirkshoop))\n- Fixed escaped quotes [\\#18](https://github.com/nlohmann/json/pull/18) ([Teemperor](https://github.com/Teemperor))\n- Fix double delete on std::bad\\_alloc exception [\\#14](https://github.com/nlohmann/json/pull/14) ([elliotgoodrich](https://github.com/elliotgoodrich))\n- Added CMake and lcov [\\#6](https://github.com/nlohmann/json/pull/6) ([Teemperor](https://github.com/Teemperor))\n- Version 2.0 [\\#5](https://github.com/nlohmann/json/pull/5) ([nlohmann](https://github.com/nlohmann))\n\n\n\n\\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)*"
  },
  {
    "path": "nlohmann_json/LICENSE.MIT",
    "content": "MIT License \n\nCopyright (c) 2013-2018 Niels Lohmann\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "nlohmann_json/Makefile",
    "content": "# CMAKE generated file: DO NOT EDIT!\n# Generated by \"Unix Makefiles\" Generator, CMake Version 3.10\n\n# Default target executed when no arguments are given to make.\ndefault_target: all\n\n.PHONY : default_target\n\n# Allow only one \"make -f Makefile2\" at a time, but pass parallelism.\n.NOTPARALLEL:\n\n\n#=============================================================================\n# Special targets provided by cmake.\n\n# Disable implicit rules so canonical targets will work.\n.SUFFIXES:\n\n\n# Remove some rules from gmake that .SUFFIXES does not remove.\nSUFFIXES =\n\n.SUFFIXES: .hpux_make_needs_suffix_list\n\n\n# Suppress display of executed commands.\n$(VERBOSE).SILENT:\n\n\n# A target that is always out of date.\ncmake_force:\n\n.PHONY : cmake_force\n\n#=============================================================================\n# Set environment variables for the build.\n\n# The shell in which to execute make rules.\nSHELL = /bin/sh\n\n# The CMake executable.\nCMAKE_COMMAND = /usr/bin/cmake\n\n# The command to remove a file.\nRM = /usr/bin/cmake -E remove -f\n\n# Escaping for special characters.\nEQUALS = =\n\n# The top-level source directory on which CMake was run.\nCMAKE_SOURCE_DIR = /home/zhuangyan/Projects/CPP/da4qi4\n\n# The top-level build directory on which CMake was run.\nCMAKE_BINARY_DIR = /home/zhuangyan/Projects/CPP/da4qi4\n\n#=============================================================================\n# Targets provided globally by CMake.\n\n# Special rule for the target rebuild_cache\nrebuild_cache:\n\t@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan \"Running CMake to regenerate build system...\"\n\t/usr/bin/cmake -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)\n.PHONY : rebuild_cache\n\n# Special rule for the target rebuild_cache\nrebuild_cache/fast: rebuild_cache\n\n.PHONY : rebuild_cache/fast\n\n# Special rule for the target install/strip\ninstall/strip: preinstall\n\t@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan \"Installing the project stripped...\"\n\t/usr/bin/cmake -DCMAKE_INSTALL_DO_STRIP=1 -P cmake_install.cmake\n.PHONY : install/strip\n\n# Special rule for the target install/strip\ninstall/strip/fast: preinstall/fast\n\t@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan \"Installing the project stripped...\"\n\t/usr/bin/cmake -DCMAKE_INSTALL_DO_STRIP=1 -P cmake_install.cmake\n.PHONY : install/strip/fast\n\n# Special rule for the target list_install_components\nlist_install_components:\n\t@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan \"Available install components are: \\\"Unspecified\\\"\"\n.PHONY : list_install_components\n\n# Special rule for the target list_install_components\nlist_install_components/fast: list_install_components\n\n.PHONY : list_install_components/fast\n\n# Special rule for the target install/local\ninstall/local: preinstall\n\t@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan \"Installing only the local directory...\"\n\t/usr/bin/cmake -DCMAKE_INSTALL_LOCAL_ONLY=1 -P cmake_install.cmake\n.PHONY : install/local\n\n# Special rule for the target install/local\ninstall/local/fast: preinstall/fast\n\t@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan \"Installing only the local directory...\"\n\t/usr/bin/cmake -DCMAKE_INSTALL_LOCAL_ONLY=1 -P cmake_install.cmake\n.PHONY : install/local/fast\n\n# Special rule for the target edit_cache\nedit_cache:\n\t@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan \"No interactive CMake dialog available...\"\n\t/usr/bin/cmake -E echo No\\ interactive\\ CMake\\ dialog\\ available.\n.PHONY : edit_cache\n\n# Special rule for the target edit_cache\nedit_cache/fast: edit_cache\n\n.PHONY : edit_cache/fast\n\n# Special rule for the target install\ninstall: preinstall\n\t@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan \"Install the project...\"\n\t/usr/bin/cmake -P cmake_install.cmake\n.PHONY : install\n\n# Special rule for the target install\ninstall/fast: preinstall/fast\n\t@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan \"Install the project...\"\n\t/usr/bin/cmake -P cmake_install.cmake\n.PHONY : install/fast\n\n# The main all target\nall: cmake_check_build_system\n\tcd /home/zhuangyan/Projects/CPP/da4qi4 && $(CMAKE_COMMAND) -E cmake_progress_start /home/zhuangyan/Projects/CPP/da4qi4/CMakeFiles /home/zhuangyan/Projects/CPP/da4qi4/nlohmann_json/CMakeFiles/progress.marks\n\tcd /home/zhuangyan/Projects/CPP/da4qi4 && $(MAKE) -f CMakeFiles/Makefile2 nlohmann_json/all\n\t$(CMAKE_COMMAND) -E cmake_progress_start /home/zhuangyan/Projects/CPP/da4qi4/CMakeFiles 0\n.PHONY : all\n\n# The main clean target\nclean:\n\tcd /home/zhuangyan/Projects/CPP/da4qi4 && $(MAKE) -f CMakeFiles/Makefile2 nlohmann_json/clean\n.PHONY : clean\n\n# The main clean target\nclean/fast: clean\n\n.PHONY : clean/fast\n\n# Prepare targets for installation.\npreinstall: all\n\tcd /home/zhuangyan/Projects/CPP/da4qi4 && $(MAKE) -f CMakeFiles/Makefile2 nlohmann_json/preinstall\n.PHONY : preinstall\n\n# Prepare targets for installation.\npreinstall/fast:\n\tcd /home/zhuangyan/Projects/CPP/da4qi4 && $(MAKE) -f CMakeFiles/Makefile2 nlohmann_json/preinstall\n.PHONY : preinstall/fast\n\n# clear depends\ndepend:\n\tcd /home/zhuangyan/Projects/CPP/da4qi4 && $(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 1\n.PHONY : depend\n\n# Convenience name for target.\nnlohmann_json/CMakeFiles/ContinuousSubmit.dir/rule:\n\tcd /home/zhuangyan/Projects/CPP/da4qi4 && $(MAKE) -f CMakeFiles/Makefile2 nlohmann_json/CMakeFiles/ContinuousSubmit.dir/rule\n.PHONY : nlohmann_json/CMakeFiles/ContinuousSubmit.dir/rule\n\n# Convenience name for target.\nContinuousSubmit: nlohmann_json/CMakeFiles/ContinuousSubmit.dir/rule\n\n.PHONY : ContinuousSubmit\n\n# fast build rule for target.\nContinuousSubmit/fast:\n\tcd /home/zhuangyan/Projects/CPP/da4qi4 && $(MAKE) -f nlohmann_json/CMakeFiles/ContinuousSubmit.dir/build.make nlohmann_json/CMakeFiles/ContinuousSubmit.dir/build\n.PHONY : ContinuousSubmit/fast\n\n# Convenience name for target.\nnlohmann_json/CMakeFiles/ContinuousMemCheck.dir/rule:\n\tcd /home/zhuangyan/Projects/CPP/da4qi4 && $(MAKE) -f CMakeFiles/Makefile2 nlohmann_json/CMakeFiles/ContinuousMemCheck.dir/rule\n.PHONY : nlohmann_json/CMakeFiles/ContinuousMemCheck.dir/rule\n\n# Convenience name for target.\nContinuousMemCheck: nlohmann_json/CMakeFiles/ContinuousMemCheck.dir/rule\n\n.PHONY : ContinuousMemCheck\n\n# fast build rule for target.\nContinuousMemCheck/fast:\n\tcd /home/zhuangyan/Projects/CPP/da4qi4 && $(MAKE) -f nlohmann_json/CMakeFiles/ContinuousMemCheck.dir/build.make nlohmann_json/CMakeFiles/ContinuousMemCheck.dir/build\n.PHONY : ContinuousMemCheck/fast\n\n# Convenience name for target.\nnlohmann_json/CMakeFiles/ContinuousConfigure.dir/rule:\n\tcd /home/zhuangyan/Projects/CPP/da4qi4 && $(MAKE) -f CMakeFiles/Makefile2 nlohmann_json/CMakeFiles/ContinuousConfigure.dir/rule\n.PHONY : nlohmann_json/CMakeFiles/ContinuousConfigure.dir/rule\n\n# Convenience name for target.\nContinuousConfigure: nlohmann_json/CMakeFiles/ContinuousConfigure.dir/rule\n\n.PHONY : ContinuousConfigure\n\n# fast build rule for target.\nContinuousConfigure/fast:\n\tcd /home/zhuangyan/Projects/CPP/da4qi4 && $(MAKE) -f nlohmann_json/CMakeFiles/ContinuousConfigure.dir/build.make nlohmann_json/CMakeFiles/ContinuousConfigure.dir/build\n.PHONY : ContinuousConfigure/fast\n\n# Convenience name for target.\nnlohmann_json/CMakeFiles/ExperimentalSubmit.dir/rule:\n\tcd /home/zhuangyan/Projects/CPP/da4qi4 && $(MAKE) -f CMakeFiles/Makefile2 nlohmann_json/CMakeFiles/ExperimentalSubmit.dir/rule\n.PHONY : nlohmann_json/CMakeFiles/ExperimentalSubmit.dir/rule\n\n# Convenience name for target.\nExperimentalSubmit: nlohmann_json/CMakeFiles/ExperimentalSubmit.dir/rule\n\n.PHONY : ExperimentalSubmit\n\n# fast build rule for target.\nExperimentalSubmit/fast:\n\tcd /home/zhuangyan/Projects/CPP/da4qi4 && $(MAKE) -f nlohmann_json/CMakeFiles/ExperimentalSubmit.dir/build.make nlohmann_json/CMakeFiles/ExperimentalSubmit.dir/build\n.PHONY : ExperimentalSubmit/fast\n\n# Convenience name for target.\nnlohmann_json/CMakeFiles/ExperimentalMemCheck.dir/rule:\n\tcd /home/zhuangyan/Projects/CPP/da4qi4 && $(MAKE) -f CMakeFiles/Makefile2 nlohmann_json/CMakeFiles/ExperimentalMemCheck.dir/rule\n.PHONY : nlohmann_json/CMakeFiles/ExperimentalMemCheck.dir/rule\n\n# Convenience name for target.\nExperimentalMemCheck: nlohmann_json/CMakeFiles/ExperimentalMemCheck.dir/rule\n\n.PHONY : ExperimentalMemCheck\n\n# fast build rule for target.\nExperimentalMemCheck/fast:\n\tcd /home/zhuangyan/Projects/CPP/da4qi4 && $(MAKE) -f nlohmann_json/CMakeFiles/ExperimentalMemCheck.dir/build.make nlohmann_json/CMakeFiles/ExperimentalMemCheck.dir/build\n.PHONY : ExperimentalMemCheck/fast\n\n# Convenience name for target.\nnlohmann_json/CMakeFiles/ExperimentalTest.dir/rule:\n\tcd /home/zhuangyan/Projects/CPP/da4qi4 && $(MAKE) -f CMakeFiles/Makefile2 nlohmann_json/CMakeFiles/ExperimentalTest.dir/rule\n.PHONY : nlohmann_json/CMakeFiles/ExperimentalTest.dir/rule\n\n# Convenience name for target.\nExperimentalTest: nlohmann_json/CMakeFiles/ExperimentalTest.dir/rule\n\n.PHONY : ExperimentalTest\n\n# fast build rule for target.\nExperimentalTest/fast:\n\tcd /home/zhuangyan/Projects/CPP/da4qi4 && $(MAKE) -f nlohmann_json/CMakeFiles/ExperimentalTest.dir/build.make nlohmann_json/CMakeFiles/ExperimentalTest.dir/build\n.PHONY : ExperimentalTest/fast\n\n# Convenience name for target.\nnlohmann_json/CMakeFiles/ContinuousTest.dir/rule:\n\tcd /home/zhuangyan/Projects/CPP/da4qi4 && $(MAKE) -f CMakeFiles/Makefile2 nlohmann_json/CMakeFiles/ContinuousTest.dir/rule\n.PHONY : nlohmann_json/CMakeFiles/ContinuousTest.dir/rule\n\n# Convenience name for target.\nContinuousTest: nlohmann_json/CMakeFiles/ContinuousTest.dir/rule\n\n.PHONY : ContinuousTest\n\n# fast build rule for target.\nContinuousTest/fast:\n\tcd /home/zhuangyan/Projects/CPP/da4qi4 && $(MAKE) -f nlohmann_json/CMakeFiles/ContinuousTest.dir/build.make nlohmann_json/CMakeFiles/ContinuousTest.dir/build\n.PHONY : ContinuousTest/fast\n\n# Convenience name for target.\nnlohmann_json/CMakeFiles/ContinuousUpdate.dir/rule:\n\tcd /home/zhuangyan/Projects/CPP/da4qi4 && $(MAKE) -f CMakeFiles/Makefile2 nlohmann_json/CMakeFiles/ContinuousUpdate.dir/rule\n.PHONY : nlohmann_json/CMakeFiles/ContinuousUpdate.dir/rule\n\n# Convenience name for target.\nContinuousUpdate: nlohmann_json/CMakeFiles/ContinuousUpdate.dir/rule\n\n.PHONY : ContinuousUpdate\n\n# fast build rule for target.\nContinuousUpdate/fast:\n\tcd /home/zhuangyan/Projects/CPP/da4qi4 && $(MAKE) -f nlohmann_json/CMakeFiles/ContinuousUpdate.dir/build.make nlohmann_json/CMakeFiles/ContinuousUpdate.dir/build\n.PHONY : ContinuousUpdate/fast\n\n# Convenience name for target.\nnlohmann_json/CMakeFiles/ExperimentalBuild.dir/rule:\n\tcd /home/zhuangyan/Projects/CPP/da4qi4 && $(MAKE) -f CMakeFiles/Makefile2 nlohmann_json/CMakeFiles/ExperimentalBuild.dir/rule\n.PHONY : nlohmann_json/CMakeFiles/ExperimentalBuild.dir/rule\n\n# Convenience name for target.\nExperimentalBuild: nlohmann_json/CMakeFiles/ExperimentalBuild.dir/rule\n\n.PHONY : ExperimentalBuild\n\n# fast build rule for target.\nExperimentalBuild/fast:\n\tcd /home/zhuangyan/Projects/CPP/da4qi4 && $(MAKE) -f nlohmann_json/CMakeFiles/ExperimentalBuild.dir/build.make nlohmann_json/CMakeFiles/ExperimentalBuild.dir/build\n.PHONY : ExperimentalBuild/fast\n\n# Convenience name for target.\nnlohmann_json/CMakeFiles/NightlyMemoryCheck.dir/rule:\n\tcd /home/zhuangyan/Projects/CPP/da4qi4 && $(MAKE) -f CMakeFiles/Makefile2 nlohmann_json/CMakeFiles/NightlyMemoryCheck.dir/rule\n.PHONY : nlohmann_json/CMakeFiles/NightlyMemoryCheck.dir/rule\n\n# Convenience name for target.\nNightlyMemoryCheck: nlohmann_json/CMakeFiles/NightlyMemoryCheck.dir/rule\n\n.PHONY : NightlyMemoryCheck\n\n# fast build rule for target.\nNightlyMemoryCheck/fast:\n\tcd /home/zhuangyan/Projects/CPP/da4qi4 && $(MAKE) -f nlohmann_json/CMakeFiles/NightlyMemoryCheck.dir/build.make nlohmann_json/CMakeFiles/NightlyMemoryCheck.dir/build\n.PHONY : NightlyMemoryCheck/fast\n\n# Convenience name for target.\nnlohmann_json/CMakeFiles/NightlyBuild.dir/rule:\n\tcd /home/zhuangyan/Projects/CPP/da4qi4 && $(MAKE) -f CMakeFiles/Makefile2 nlohmann_json/CMakeFiles/NightlyBuild.dir/rule\n.PHONY : nlohmann_json/CMakeFiles/NightlyBuild.dir/rule\n\n# Convenience name for target.\nNightlyBuild: nlohmann_json/CMakeFiles/NightlyBuild.dir/rule\n\n.PHONY : NightlyBuild\n\n# fast build rule for target.\nNightlyBuild/fast:\n\tcd /home/zhuangyan/Projects/CPP/da4qi4 && $(MAKE) -f nlohmann_json/CMakeFiles/NightlyBuild.dir/build.make nlohmann_json/CMakeFiles/NightlyBuild.dir/build\n.PHONY : NightlyBuild/fast\n\n# Convenience name for target.\nnlohmann_json/CMakeFiles/ExperimentalUpdate.dir/rule:\n\tcd /home/zhuangyan/Projects/CPP/da4qi4 && $(MAKE) -f CMakeFiles/Makefile2 nlohmann_json/CMakeFiles/ExperimentalUpdate.dir/rule\n.PHONY : nlohmann_json/CMakeFiles/ExperimentalUpdate.dir/rule\n\n# Convenience name for target.\nExperimentalUpdate: nlohmann_json/CMakeFiles/ExperimentalUpdate.dir/rule\n\n.PHONY : ExperimentalUpdate\n\n# fast build rule for target.\nExperimentalUpdate/fast:\n\tcd /home/zhuangyan/Projects/CPP/da4qi4 && $(MAKE) -f nlohmann_json/CMakeFiles/ExperimentalUpdate.dir/build.make nlohmann_json/CMakeFiles/ExperimentalUpdate.dir/build\n.PHONY : ExperimentalUpdate/fast\n\n# Convenience name for target.\nnlohmann_json/CMakeFiles/ContinuousBuild.dir/rule:\n\tcd /home/zhuangyan/Projects/CPP/da4qi4 && $(MAKE) -f CMakeFiles/Makefile2 nlohmann_json/CMakeFiles/ContinuousBuild.dir/rule\n.PHONY : nlohmann_json/CMakeFiles/ContinuousBuild.dir/rule\n\n# Convenience name for target.\nContinuousBuild: nlohmann_json/CMakeFiles/ContinuousBuild.dir/rule\n\n.PHONY : ContinuousBuild\n\n# fast build rule for target.\nContinuousBuild/fast:\n\tcd /home/zhuangyan/Projects/CPP/da4qi4 && $(MAKE) -f nlohmann_json/CMakeFiles/ContinuousBuild.dir/build.make nlohmann_json/CMakeFiles/ContinuousBuild.dir/build\n.PHONY : ContinuousBuild/fast\n\n# Convenience name for target.\nnlohmann_json/CMakeFiles/Continuous.dir/rule:\n\tcd /home/zhuangyan/Projects/CPP/da4qi4 && $(MAKE) -f CMakeFiles/Makefile2 nlohmann_json/CMakeFiles/Continuous.dir/rule\n.PHONY : nlohmann_json/CMakeFiles/Continuous.dir/rule\n\n# Convenience name for target.\nContinuous: nlohmann_json/CMakeFiles/Continuous.dir/rule\n\n.PHONY : Continuous\n\n# fast build rule for target.\nContinuous/fast:\n\tcd /home/zhuangyan/Projects/CPP/da4qi4 && $(MAKE) -f nlohmann_json/CMakeFiles/Continuous.dir/build.make nlohmann_json/CMakeFiles/Continuous.dir/build\n.PHONY : Continuous/fast\n\n# Convenience name for target.\nnlohmann_json/CMakeFiles/Experimental.dir/rule:\n\tcd /home/zhuangyan/Projects/CPP/da4qi4 && $(MAKE) -f CMakeFiles/Makefile2 nlohmann_json/CMakeFiles/Experimental.dir/rule\n.PHONY : nlohmann_json/CMakeFiles/Experimental.dir/rule\n\n# Convenience name for target.\nExperimental: nlohmann_json/CMakeFiles/Experimental.dir/rule\n\n.PHONY : Experimental\n\n# fast build rule for target.\nExperimental/fast:\n\tcd /home/zhuangyan/Projects/CPP/da4qi4 && $(MAKE) -f nlohmann_json/CMakeFiles/Experimental.dir/build.make nlohmann_json/CMakeFiles/Experimental.dir/build\n.PHONY : Experimental/fast\n\n# Convenience name for target.\nnlohmann_json/CMakeFiles/ExperimentalConfigure.dir/rule:\n\tcd /home/zhuangyan/Projects/CPP/da4qi4 && $(MAKE) -f CMakeFiles/Makefile2 nlohmann_json/CMakeFiles/ExperimentalConfigure.dir/rule\n.PHONY : nlohmann_json/CMakeFiles/ExperimentalConfigure.dir/rule\n\n# Convenience name for target.\nExperimentalConfigure: nlohmann_json/CMakeFiles/ExperimentalConfigure.dir/rule\n\n.PHONY : ExperimentalConfigure\n\n# fast build rule for target.\nExperimentalConfigure/fast:\n\tcd /home/zhuangyan/Projects/CPP/da4qi4 && $(MAKE) -f nlohmann_json/CMakeFiles/ExperimentalConfigure.dir/build.make nlohmann_json/CMakeFiles/ExperimentalConfigure.dir/build\n.PHONY : ExperimentalConfigure/fast\n\n# Convenience name for target.\nnlohmann_json/CMakeFiles/NightlyStart.dir/rule:\n\tcd /home/zhuangyan/Projects/CPP/da4qi4 && $(MAKE) -f CMakeFiles/Makefile2 nlohmann_json/CMakeFiles/NightlyStart.dir/rule\n.PHONY : nlohmann_json/CMakeFiles/NightlyStart.dir/rule\n\n# Convenience name for target.\nNightlyStart: nlohmann_json/CMakeFiles/NightlyStart.dir/rule\n\n.PHONY : NightlyStart\n\n# fast build rule for target.\nNightlyStart/fast:\n\tcd /home/zhuangyan/Projects/CPP/da4qi4 && $(MAKE) -f nlohmann_json/CMakeFiles/NightlyStart.dir/build.make nlohmann_json/CMakeFiles/NightlyStart.dir/build\n.PHONY : NightlyStart/fast\n\n# Convenience name for target.\nnlohmann_json/CMakeFiles/NightlyTest.dir/rule:\n\tcd /home/zhuangyan/Projects/CPP/da4qi4 && $(MAKE) -f CMakeFiles/Makefile2 nlohmann_json/CMakeFiles/NightlyTest.dir/rule\n.PHONY : nlohmann_json/CMakeFiles/NightlyTest.dir/rule\n\n# Convenience name for target.\nNightlyTest: nlohmann_json/CMakeFiles/NightlyTest.dir/rule\n\n.PHONY : NightlyTest\n\n# fast build rule for target.\nNightlyTest/fast:\n\tcd /home/zhuangyan/Projects/CPP/da4qi4 && $(MAKE) -f nlohmann_json/CMakeFiles/NightlyTest.dir/build.make nlohmann_json/CMakeFiles/NightlyTest.dir/build\n.PHONY : NightlyTest/fast\n\n# Convenience name for target.\nnlohmann_json/CMakeFiles/NightlyUpdate.dir/rule:\n\tcd /home/zhuangyan/Projects/CPP/da4qi4 && $(MAKE) -f CMakeFiles/Makefile2 nlohmann_json/CMakeFiles/NightlyUpdate.dir/rule\n.PHONY : nlohmann_json/CMakeFiles/NightlyUpdate.dir/rule\n\n# Convenience name for target.\nNightlyUpdate: nlohmann_json/CMakeFiles/NightlyUpdate.dir/rule\n\n.PHONY : NightlyUpdate\n\n# fast build rule for target.\nNightlyUpdate/fast:\n\tcd /home/zhuangyan/Projects/CPP/da4qi4 && $(MAKE) -f nlohmann_json/CMakeFiles/NightlyUpdate.dir/build.make nlohmann_json/CMakeFiles/NightlyUpdate.dir/build\n.PHONY : NightlyUpdate/fast\n\n# Convenience name for target.\nnlohmann_json/CMakeFiles/ContinuousCoverage.dir/rule:\n\tcd /home/zhuangyan/Projects/CPP/da4qi4 && $(MAKE) -f CMakeFiles/Makefile2 nlohmann_json/CMakeFiles/ContinuousCoverage.dir/rule\n.PHONY : nlohmann_json/CMakeFiles/ContinuousCoverage.dir/rule\n\n# Convenience name for target.\nContinuousCoverage: nlohmann_json/CMakeFiles/ContinuousCoverage.dir/rule\n\n.PHONY : ContinuousCoverage\n\n# fast build rule for target.\nContinuousCoverage/fast:\n\tcd /home/zhuangyan/Projects/CPP/da4qi4 && $(MAKE) -f nlohmann_json/CMakeFiles/ContinuousCoverage.dir/build.make nlohmann_json/CMakeFiles/ContinuousCoverage.dir/build\n.PHONY : ContinuousCoverage/fast\n\n# Convenience name for target.\nnlohmann_json/CMakeFiles/ExperimentalStart.dir/rule:\n\tcd /home/zhuangyan/Projects/CPP/da4qi4 && $(MAKE) -f CMakeFiles/Makefile2 nlohmann_json/CMakeFiles/ExperimentalStart.dir/rule\n.PHONY : nlohmann_json/CMakeFiles/ExperimentalStart.dir/rule\n\n# Convenience name for target.\nExperimentalStart: nlohmann_json/CMakeFiles/ExperimentalStart.dir/rule\n\n.PHONY : ExperimentalStart\n\n# fast build rule for target.\nExperimentalStart/fast:\n\tcd /home/zhuangyan/Projects/CPP/da4qi4 && $(MAKE) -f nlohmann_json/CMakeFiles/ExperimentalStart.dir/build.make nlohmann_json/CMakeFiles/ExperimentalStart.dir/build\n.PHONY : ExperimentalStart/fast\n\n# Convenience name for target.\nnlohmann_json/CMakeFiles/Nightly.dir/rule:\n\tcd /home/zhuangyan/Projects/CPP/da4qi4 && $(MAKE) -f CMakeFiles/Makefile2 nlohmann_json/CMakeFiles/Nightly.dir/rule\n.PHONY : nlohmann_json/CMakeFiles/Nightly.dir/rule\n\n# Convenience name for target.\nNightly: nlohmann_json/CMakeFiles/Nightly.dir/rule\n\n.PHONY : Nightly\n\n# fast build rule for target.\nNightly/fast:\n\tcd /home/zhuangyan/Projects/CPP/da4qi4 && $(MAKE) -f nlohmann_json/CMakeFiles/Nightly.dir/build.make nlohmann_json/CMakeFiles/Nightly.dir/build\n.PHONY : Nightly/fast\n\n# Convenience name for target.\nnlohmann_json/CMakeFiles/NightlyConfigure.dir/rule:\n\tcd /home/zhuangyan/Projects/CPP/da4qi4 && $(MAKE) -f CMakeFiles/Makefile2 nlohmann_json/CMakeFiles/NightlyConfigure.dir/rule\n.PHONY : nlohmann_json/CMakeFiles/NightlyConfigure.dir/rule\n\n# Convenience name for target.\nNightlyConfigure: nlohmann_json/CMakeFiles/NightlyConfigure.dir/rule\n\n.PHONY : NightlyConfigure\n\n# fast build rule for target.\nNightlyConfigure/fast:\n\tcd /home/zhuangyan/Projects/CPP/da4qi4 && $(MAKE) -f nlohmann_json/CMakeFiles/NightlyConfigure.dir/build.make nlohmann_json/CMakeFiles/NightlyConfigure.dir/build\n.PHONY : NightlyConfigure/fast\n\n# Convenience name for target.\nnlohmann_json/CMakeFiles/NightlyCoverage.dir/rule:\n\tcd /home/zhuangyan/Projects/CPP/da4qi4 && $(MAKE) -f CMakeFiles/Makefile2 nlohmann_json/CMakeFiles/NightlyCoverage.dir/rule\n.PHONY : nlohmann_json/CMakeFiles/NightlyCoverage.dir/rule\n\n# Convenience name for target.\nNightlyCoverage: nlohmann_json/CMakeFiles/NightlyCoverage.dir/rule\n\n.PHONY : NightlyCoverage\n\n# fast build rule for target.\nNightlyCoverage/fast:\n\tcd /home/zhuangyan/Projects/CPP/da4qi4 && $(MAKE) -f nlohmann_json/CMakeFiles/NightlyCoverage.dir/build.make nlohmann_json/CMakeFiles/NightlyCoverage.dir/build\n.PHONY : NightlyCoverage/fast\n\n# Convenience name for target.\nnlohmann_json/CMakeFiles/ExperimentalCoverage.dir/rule:\n\tcd /home/zhuangyan/Projects/CPP/da4qi4 && $(MAKE) -f CMakeFiles/Makefile2 nlohmann_json/CMakeFiles/ExperimentalCoverage.dir/rule\n.PHONY : nlohmann_json/CMakeFiles/ExperimentalCoverage.dir/rule\n\n# Convenience name for target.\nExperimentalCoverage: nlohmann_json/CMakeFiles/ExperimentalCoverage.dir/rule\n\n.PHONY : ExperimentalCoverage\n\n# fast build rule for target.\nExperimentalCoverage/fast:\n\tcd /home/zhuangyan/Projects/CPP/da4qi4 && $(MAKE) -f nlohmann_json/CMakeFiles/ExperimentalCoverage.dir/build.make nlohmann_json/CMakeFiles/ExperimentalCoverage.dir/build\n.PHONY : ExperimentalCoverage/fast\n\n# Convenience name for target.\nnlohmann_json/CMakeFiles/NightlyMemCheck.dir/rule:\n\tcd /home/zhuangyan/Projects/CPP/da4qi4 && $(MAKE) -f CMakeFiles/Makefile2 nlohmann_json/CMakeFiles/NightlyMemCheck.dir/rule\n.PHONY : nlohmann_json/CMakeFiles/NightlyMemCheck.dir/rule\n\n# Convenience name for target.\nNightlyMemCheck: nlohmann_json/CMakeFiles/NightlyMemCheck.dir/rule\n\n.PHONY : NightlyMemCheck\n\n# fast build rule for target.\nNightlyMemCheck/fast:\n\tcd /home/zhuangyan/Projects/CPP/da4qi4 && $(MAKE) -f nlohmann_json/CMakeFiles/NightlyMemCheck.dir/build.make nlohmann_json/CMakeFiles/NightlyMemCheck.dir/build\n.PHONY : NightlyMemCheck/fast\n\n# Convenience name for target.\nnlohmann_json/CMakeFiles/ContinuousStart.dir/rule:\n\tcd /home/zhuangyan/Projects/CPP/da4qi4 && $(MAKE) -f CMakeFiles/Makefile2 nlohmann_json/CMakeFiles/ContinuousStart.dir/rule\n.PHONY : nlohmann_json/CMakeFiles/ContinuousStart.dir/rule\n\n# Convenience name for target.\nContinuousStart: nlohmann_json/CMakeFiles/ContinuousStart.dir/rule\n\n.PHONY : ContinuousStart\n\n# fast build rule for target.\nContinuousStart/fast:\n\tcd /home/zhuangyan/Projects/CPP/da4qi4 && $(MAKE) -f nlohmann_json/CMakeFiles/ContinuousStart.dir/build.make nlohmann_json/CMakeFiles/ContinuousStart.dir/build\n.PHONY : ContinuousStart/fast\n\n# Convenience name for target.\nnlohmann_json/CMakeFiles/NightlySubmit.dir/rule:\n\tcd /home/zhuangyan/Projects/CPP/da4qi4 && $(MAKE) -f CMakeFiles/Makefile2 nlohmann_json/CMakeFiles/NightlySubmit.dir/rule\n.PHONY : nlohmann_json/CMakeFiles/NightlySubmit.dir/rule\n\n# Convenience name for target.\nNightlySubmit: nlohmann_json/CMakeFiles/NightlySubmit.dir/rule\n\n.PHONY : NightlySubmit\n\n# fast build rule for target.\nNightlySubmit/fast:\n\tcd /home/zhuangyan/Projects/CPP/da4qi4 && $(MAKE) -f nlohmann_json/CMakeFiles/NightlySubmit.dir/build.make nlohmann_json/CMakeFiles/NightlySubmit.dir/build\n.PHONY : NightlySubmit/fast\n\n# Help Target\nhelp:\n\t@echo \"The following are some of the valid targets for this Makefile:\"\n\t@echo \"... all (the default if no target is provided)\"\n\t@echo \"... clean\"\n\t@echo \"... depend\"\n\t@echo \"... rebuild_cache\"\n\t@echo \"... ContinuousSubmit\"\n\t@echo \"... ContinuousMemCheck\"\n\t@echo \"... ContinuousConfigure\"\n\t@echo \"... ExperimentalSubmit\"\n\t@echo \"... ExperimentalMemCheck\"\n\t@echo \"... install/strip\"\n\t@echo \"... ExperimentalTest\"\n\t@echo \"... list_install_components\"\n\t@echo \"... ContinuousTest\"\n\t@echo \"... ContinuousUpdate\"\n\t@echo \"... ExperimentalBuild\"\n\t@echo \"... NightlyMemoryCheck\"\n\t@echo \"... NightlyBuild\"\n\t@echo \"... ExperimentalUpdate\"\n\t@echo \"... ContinuousBuild\"\n\t@echo \"... Continuous\"\n\t@echo \"... Experimental\"\n\t@echo \"... ExperimentalConfigure\"\n\t@echo \"... install/local\"\n\t@echo \"... NightlyStart\"\n\t@echo \"... edit_cache\"\n\t@echo \"... NightlyTest\"\n\t@echo \"... NightlyUpdate\"\n\t@echo \"... ContinuousCoverage\"\n\t@echo \"... ExperimentalStart\"\n\t@echo \"... Nightly\"\n\t@echo \"... NightlyConfigure\"\n\t@echo \"... NightlyCoverage\"\n\t@echo \"... install\"\n\t@echo \"... ExperimentalCoverage\"\n\t@echo \"... NightlyMemCheck\"\n\t@echo \"... ContinuousStart\"\n\t@echo \"... NightlySubmit\"\n.PHONY : help\n\n\n\n#=============================================================================\n# Special targets to cleanup operation of make.\n\n# Special rule to run CMake to check the build system integrity.\n# No rule that depends on this can have commands that come from listfiles\n# because they might be regenerated.\ncmake_check_build_system:\n\tcd /home/zhuangyan/Projects/CPP/da4qi4 && $(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0\n.PHONY : cmake_check_build_system\n\n"
  },
  {
    "path": "nlohmann_json/README.md",
    "content": "[![JSON for Modern C++](https://raw.githubusercontent.com/nlohmann/json/master/doc/json.gif)](https://github.com/nlohmann/json/releases)\n\n[![Build Status](https://travis-ci.org/nlohmann/json.svg?branch=master)](https://travis-ci.org/nlohmann/json)\n[![Build Status](https://ci.appveyor.com/api/projects/status/1acb366xfyg3qybk/branch/develop?svg=true)](https://ci.appveyor.com/project/nlohmann/json)\n[![Coverage Status](https://img.shields.io/coveralls/nlohmann/json.svg)](https://coveralls.io/r/nlohmann/json)\n[![Coverity Scan Build Status](https://scan.coverity.com/projects/5550/badge.svg)](https://scan.coverity.com/projects/nlohmann-json)\n[![Codacy Badge](https://api.codacy.com/project/badge/Grade/f3732b3327e34358a0e9d1fe9f661f08)](https://www.codacy.com/app/nlohmann/json?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=nlohmann/json&amp;utm_campaign=Badge_Grade)\n[![Language grade: C/C++](https://img.shields.io/lgtm/grade/cpp/g/nlohmann/json.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/nlohmann/json/context:cpp)\n[![Try online](https://img.shields.io/badge/try-online-blue.svg)](https://wandbox.org/permlink/TarF5pPn9NtHQjhf)\n[![Documentation](https://img.shields.io/badge/docs-doxygen-blue.svg)](http://nlohmann.github.io/json)\n[![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/nlohmann/json/master/LICENSE.MIT)\n[![GitHub Releases](https://img.shields.io/github/release/nlohmann/json.svg)](https://github.com/nlohmann/json/releases)\n[![GitHub Issues](https://img.shields.io/github/issues/nlohmann/json.svg)](http://github.com/nlohmann/json/issues)\n[![Average time to resolve an issue](http://isitmaintained.com/badge/resolution/nlohmann/json.svg)](http://isitmaintained.com/project/nlohmann/json \"Average time to resolve an issue\")\n[![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/289/badge)](https://bestpractices.coreinfrastructure.org/projects/289)\n\n- [Design goals](#design-goals)\n- [Integration](#integration)\n  - [CMake](#cmake)\n  - [Package Managers](#package-managers)\n- [Examples](#examples)\n  - [JSON as first-class data type](#json-as-first-class-data-type)\n  - [Serialization / Deserialization](#serialization--deserialization)\n  - [STL-like access](#stl-like-access)\n  - [Conversion from STL containers](#conversion-from-stl-containers)\n  - [JSON Pointer and JSON Patch](#json-pointer-and-json-patch)\n  - [JSON Merge Patch](#json-merge-patch)\n  - [Implicit conversions](#implicit-conversions)\n  - [Conversions to/from arbitrary types](#arbitrary-types-conversions)\n  - [Specializing enum conversion](#specializing-enum-conversion)\n  - [Binary formats (BSON, CBOR, MessagePack, and UBJSON)](#binary-formats-bson-cbor-messagepack-and-ubjson)\n- [Supported compilers](#supported-compilers)\n- [License](#license)\n- [Contact](#contact)\n- [Thanks](#thanks)\n- [Used third-party tools](#used-third-party-tools)\n- [Projects using JSON for Modern C++](#projects-using-json-for-modern-c)\n- [Notes](#notes)\n- [Execute unit tests](#execute-unit-tests)\n\n## Design goals\n\nThere are myriads of [JSON](http://json.org) libraries out there, and each may even have its reason to exist. Our class had these design goals:\n\n- **Intuitive syntax**. In languages such as Python, JSON feels like a first class data type. We used all the operator magic of modern C++ to achieve the same feeling in your code. Check out the [examples below](#examples) and you'll know what I mean.\n\n- **Trivial integration**. Our whole code consists of a single header file [`json.hpp`](https://github.com/nlohmann/json/blob/develop/single_include/nlohmann/json.hpp). That's it. No library, no subproject, no dependencies, no complex build system. The class is written in vanilla C++11. All in all, everything should require no adjustment of your compiler flags or project settings.\n\n- **Serious testing**. Our class is heavily [unit-tested](https://github.com/nlohmann/json/tree/develop/test/src) and covers [100%](https://coveralls.io/r/nlohmann/json) of the code, including all exceptional behavior. Furthermore, we checked with [Valgrind](http://valgrind.org) and the [Clang Sanitizers](https://clang.llvm.org/docs/index.html) that there are no memory leaks. [Google OSS-Fuzz](https://github.com/google/oss-fuzz/tree/master/projects/json) additionally runs fuzz tests against all parsers 24/7, effectively executing billions of tests so far. To maintain high quality, the project is following the [Core Infrastructure Initiative (CII) best practices](https://bestpractices.coreinfrastructure.org/projects/289).\n\nOther aspects were not so important to us:\n\n- **Memory efficiency**. Each JSON object has an overhead of one pointer (the maximal size of a union) and one enumeration element (1 byte). The default generalization uses the following C++ data types: `std::string` for strings, `int64_t`, `uint64_t` or `double` for numbers, `std::map` for objects, `std::vector` for arrays, and `bool` for Booleans. However, you can template the generalized class `basic_json` to your needs.\n\n- **Speed**. There are certainly [faster JSON libraries](https://github.com/miloyip/nativejson-benchmark#parsing-time) out there. However, if your goal is to speed up your development by adding JSON support with a single header, then this library is the way to go. If you know how to use a `std::vector` or `std::map`, you are already set.\n\nSee the [contribution guidelines](https://github.com/nlohmann/json/blob/master/.github/CONTRIBUTING.md#please-dont) for more information.\n\n\n## Integration\n\n[`json.hpp`](https://github.com/nlohmann/json/blob/develop/single_include/nlohmann/json.hpp) is the single required file in `single_include/nlohmann` or [released here](https://github.com/nlohmann/json/releases). You need to add\n\n```cpp\n#include <nlohmann/json.hpp>\n\n// for convenience\nusing json = nlohmann::json;\n```\n\nto the files you want to process JSON and set the necessary switches to enable C++11 (e.g., `-std=c++11` for GCC and Clang).\n\nYou can further use file [`include/nlohmann/json_fwd.hpp`](https://github.com/nlohmann/json/blob/develop/include/nlohmann/json_fwd.hpp) for forward-declarations. The installation of json_fwd.hpp (as part of cmake's install step), can be achieved by setting `-DJSON_MultipleHeaders=ON`.\n\n### CMake\n\nYou can also use the `nlohmann_json::nlohmann_json` interface target in CMake.  This target populates the appropriate usage requirements for `INTERFACE_INCLUDE_DIRECTORIES` to point to the appropriate include directories and `INTERFACE_COMPILE_FEATURES` for the necessary C++11 flags.\n\n#### External\n\nTo use this library from a CMake project, you can locate it directly with `find_package()` and use the namespaced imported target from the generated package configuration:\n\n```cmake\n# CMakeLists.txt\nfind_package(nlohmann_json 3.2.0 REQUIRED)\n...\nadd_library(foo ...)\n...\ntarget_link_libraries(foo PRIVATE nlohmann_json::nlohmann_json)\n```\n\nThe package configuration file, `nlohmann_jsonConfig.cmake`, can be used either from an install tree or directly out of the build tree.\n\n#### Embedded\n\nTo embed the library directly into an existing CMake project, place the entire source tree in a subdirectory and call `add_subdirectory()` in your `CMakeLists.txt` file:\n\n```cmake\n# Typically you don't care so much for a third party library's tests to be\n# run from your own project's code.\nset(JSON_BuildTests OFF CACHE INTERNAL \"\")\n\n# Don't use include(nlohmann_json/CMakeLists.txt) since that carries with it\n# inintended consequences that will break the build.  It's generally\n# discouraged (although not necessarily well documented as such) to use\n# include(...) for pulling in other CMake projects anyways.\nadd_subdirectory(nlohmann_json)\n...\nadd_library(foo ...)\n...\ntarget_link_libraries(foo PRIVATE nlohmann_json::nlohmann_json)\n```\n\n#### Supporting Both\n\nTo allow your project to support either an externally supplied or an embedded JSON library, you can use a pattern akin to the following:\n\n``` cmake\n# Top level CMakeLists.txt\nproject(FOO)\n...\noption(FOO_USE_EXTERNAL_JSON \"Use an external JSON library\" OFF)\n...\nadd_subdirectory(thirdparty)\n...\nadd_library(foo ...)\n...\n# Note that the namespaced target will always be available regardless of the\n# import method\ntarget_link_libraries(foo PRIVATE nlohmann_json::nlohmann_json)\n```\n```cmake\n# thirdparty/CMakeLists.txt\n...\nif(FOO_USE_EXTERNAL_JSON)\n  find_package(nlohmann_json 3.2.0 REQUIRED)\nelse()\n  set(JSON_BuildTests OFF CACHE INTERNAL \"\")\n  add_subdirectory(nlohmann_json)\nendif()\n...\n```\n\n`thirdparty/nlohmann_json` is then a complete copy of this source tree.\n\n### Package Managers\n\n:beer: If you are using OS X and [Homebrew](http://brew.sh), just type `brew tap nlohmann/json` and `brew install nlohmann_json` and you're set. If you want the bleeding edge rather than the latest release, use `brew install nlohmann_json --HEAD`.\n\nIf you are using the [Meson Build System](http://mesonbuild.com), then you can get a wrap file by downloading it from [Meson WrapDB](https://wrapdb.mesonbuild.com/nlohmann_json), or simply use `meson wrap install nlohmann_json`.\n\nIf you are using [Conan](https://www.conan.io/) to manage your dependencies, merely add `jsonformoderncpp/x.y.z@vthiery/stable` to your `conanfile.py`'s requires, where `x.y.z` is the release version you want to use. Please file issues [here](https://github.com/vthiery/conan-jsonformoderncpp/issues) if you experience problems with the packages.\n\nIf you are using [Spack](https://www.spack.io/) to manage your dependencies, you can use the `nlohmann_json` package. Please see the [spack project](https://github.com/spack/spack) for any issues regarding the packaging.\n\nIf you are using [hunter](https://github.com/ruslo/hunter/) on your project for external dependencies, then you can use the [nlohmann_json package](https://docs.hunter.sh/en/latest/packages/pkg/nlohmann_json.html). Please see the hunter project for any issues regarding the packaging.\n\nIf you are using [Buckaroo](https://buckaroo.pm), you can install this library's module with `buckaroo install nlohmann/json`. Please file issues [here](https://github.com/LoopPerfect/buckaroo-recipes/issues/new?title=nlohmann/nlohmann/json).\n\nIf you are using [vcpkg](https://github.com/Microsoft/vcpkg/) on your project for external dependencies, then you can use the [nlohmann-json package](https://github.com/Microsoft/vcpkg/tree/master/ports/nlohmann-json). Please see the vcpkg project for any issues regarding the packaging.\n\nIf you are using [cget](http://cget.readthedocs.io/en/latest/), you can install the latest development version with `cget install nlohmann/json`. A specific version can be installed with `cget install nlohmann/json@v3.1.0`. Also, the multiple header version can be installed by adding the `-DJSON_MultipleHeaders=ON` flag (i.e., `cget install nlohmann/json -DJSON_MultipleHeaders=ON`).\n\nIf you are using [CocoaPods](https://cocoapods.org), you can use the library by adding pod `\"nlohmann_json\", '~>3.1.2'` to your podfile (see [an example](https://bitbucket.org/benman/nlohmann_json-cocoapod/src/master/)). Please file issues [here](https://bitbucket.org/benman/nlohmann_json-cocoapod/issues?status=new&status=open).\n\n## Examples\n\nBeside the examples below, you may want to check the [documentation](https://nlohmann.github.io/json/) where each function contains a separate code example (e.g., check out [`emplace()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a5338e282d1d02bed389d852dd670d98d.html#a5338e282d1d02bed389d852dd670d98d)). All [example files](https://github.com/nlohmann/json/tree/develop/doc/examples) can be compiled and executed on their own (e.g., file [emplace.cpp](https://github.com/nlohmann/json/blob/develop/doc/examples/emplace.cpp)).\n\n### JSON as first-class data type\n\nHere are some examples to give you an idea how to use the class.\n\nAssume you want to create the JSON object\n\n```json\n{\n  \"pi\": 3.141,\n  \"happy\": true,\n  \"name\": \"Niels\",\n  \"nothing\": null,\n  \"answer\": {\n    \"everything\": 42\n  },\n  \"list\": [1, 0, 2],\n  \"object\": {\n    \"currency\": \"USD\",\n    \"value\": 42.99\n  }\n}\n```\n\nWith this library, you could write:\n\n```cpp\n// create an empty structure (null)\njson j;\n\n// add a number that is stored as double (note the implicit conversion of j to an object)\nj[\"pi\"] = 3.141;\n\n// add a Boolean that is stored as bool\nj[\"happy\"] = true;\n\n// add a string that is stored as std::string\nj[\"name\"] = \"Niels\";\n\n// add another null object by passing nullptr\nj[\"nothing\"] = nullptr;\n\n// add an object inside the object\nj[\"answer\"][\"everything\"] = 42;\n\n// add an array that is stored as std::vector (using an initializer list)\nj[\"list\"] = { 1, 0, 2 };\n\n// add another object (using an initializer list of pairs)\nj[\"object\"] = { {\"currency\", \"USD\"}, {\"value\", 42.99} };\n\n// instead, you could also write (which looks very similar to the JSON above)\njson j2 = {\n  {\"pi\", 3.141},\n  {\"happy\", true},\n  {\"name\", \"Niels\"},\n  {\"nothing\", nullptr},\n  {\"answer\", {\n    {\"everything\", 42}\n  }},\n  {\"list\", {1, 0, 2}},\n  {\"object\", {\n    {\"currency\", \"USD\"},\n    {\"value\", 42.99}\n  }}\n};\n```\n\nNote that in all these cases, you never need to \"tell\" the compiler which JSON value type you want to use. If you want to be explicit or express some edge cases, the functions [`json::array`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_aa80485befaffcadaa39965494e0b4d2e.html#aa80485befaffcadaa39965494e0b4d2e) and [`json::object`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_aa13f7c0615867542ce80337cbcf13ada.html#aa13f7c0615867542ce80337cbcf13ada) will help:\n\n```cpp\n// a way to express the empty array []\njson empty_array_explicit = json::array();\n\n// ways to express the empty object {}\njson empty_object_implicit = json({});\njson empty_object_explicit = json::object();\n\n// a way to express an _array_ of key/value pairs [[\"currency\", \"USD\"], [\"value\", 42.99]]\njson array_not_object = json::array({ {\"currency\", \"USD\"}, {\"value\", 42.99} });\n```\n\n### Serialization / Deserialization\n\n#### To/from strings\n\nYou can create a JSON value (deserialization) by appending `_json` to a string literal:\n\n```cpp\n// create object from string literal\njson j = \"{ \\\"happy\\\": true, \\\"pi\\\": 3.141 }\"_json;\n\n// or even nicer with a raw string literal\nauto j2 = R\"(\n  {\n    \"happy\": true,\n    \"pi\": 3.141\n  }\n)\"_json;\n```\n\nNote that without appending the `_json` suffix, the passed string literal is not parsed, but just used as JSON string value. That is, `json j = \"{ \\\"happy\\\": true, \\\"pi\\\": 3.141 }\"` would just store the string `\"{ \"happy\": true, \"pi\": 3.141 }\"` rather than parsing the actual object.\n\nThe above example can also be expressed explicitly using [`json::parse()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_aa9676414f2e36383c4b181fe856aa3c0.html#aa9676414f2e36383c4b181fe856aa3c0):\n\n```cpp\n// parse explicitly\nauto j3 = json::parse(\"{ \\\"happy\\\": true, \\\"pi\\\": 3.141 }\");\n```\n\nYou can also get a string representation of a JSON value (serialize):\n\n```cpp\n// explicit conversion to string\nstd::string s = j.dump();    // {\\\"happy\\\":true,\\\"pi\\\":3.141}\n\n// serialization with pretty printing\n// pass in the amount of spaces to indent\nstd::cout << j.dump(4) << std::endl;\n// {\n//     \"happy\": true,\n//     \"pi\": 3.141\n// }\n```\n\nNote the difference between serialization and assignment:\n\n```cpp\n// store a string in a JSON value\njson j_string = \"this is a string\";\n\n// retrieve the string value\nauto cpp_string = j_string.get<std::string>();\n// retrieve the string value (alternative when an variable already exists)\nstd::string cpp_string2;\nj_string.get_to(cpp_string2);\n\n// retrieve the serialized value (explicit JSON serialization)\nstd::string serialized_string = j_string.dump();\n\n// output of original string\nstd::cout << cpp_string << \" == \" << cpp_string2 << \" == \" << j_string.get<std::string>() << '\\n';\n// output of serialized value\nstd::cout << j_string << \" == \" << serialized_string << std::endl;\n```\n\n[`.dump()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a50ec80b02d0f3f51130d4abb5d1cfdc5.html#a50ec80b02d0f3f51130d4abb5d1cfdc5) always returns the serialized value, and [`.get<std::string>()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a16f9445f7629f634221a42b967cdcd43.html#a16f9445f7629f634221a42b967cdcd43) returns the originally stored string value.\n\nNote the library only supports UTF-8. When you store strings with different encodings in the library, calling [`dump()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a50ec80b02d0f3f51130d4abb5d1cfdc5.html#a50ec80b02d0f3f51130d4abb5d1cfdc5) may throw an exception unless `json::error_handler_t::replace` or `json::error_handler_t::ignore` are used as error handlers.\n\n#### To/from streams (e.g. files, string streams)\n\nYou can also use streams to serialize and deserialize:\n\n```cpp\n// deserialize from standard input\njson j;\nstd::cin >> j;\n\n// serialize to standard output\nstd::cout << j;\n\n// the setw manipulator was overloaded to set the indentation for pretty printing\nstd::cout << std::setw(4) << j << std::endl;\n```\n\nThese operators work for any subclasses of `std::istream` or `std::ostream`. Here is the same example with files:\n\n```cpp\n// read a JSON file\nstd::ifstream i(\"file.json\");\njson j;\ni >> j;\n\n// write prettified JSON to another file\nstd::ofstream o(\"pretty.json\");\no << std::setw(4) << j << std::endl;\n```\n\nPlease note that setting the exception bit for `failbit` is inappropriate for this use case. It will result in program termination due to the `noexcept` specifier in use.\n\n#### Read from iterator range\n\nYou can also parse JSON from an iterator range; that is, from any container accessible by iterators whose content is stored as contiguous byte sequence, for instance a `std::vector<std::uint8_t>`:\n\n```cpp\nstd::vector<std::uint8_t> v = {'t', 'r', 'u', 'e'};\njson j = json::parse(v.begin(), v.end());\n```\n\nYou may leave the iterators for the range [begin, end):\n\n```cpp\nstd::vector<std::uint8_t> v = {'t', 'r', 'u', 'e'};\njson j = json::parse(v);\n```\n\n#### SAX interface\n\nThe library uses a SAX-like interface with the following functions:\n\n```cpp\n// called when null is parsed\nbool null();\n\n// called when a boolean is parsed; value is passed\nbool boolean(bool val);\n\n// called when a signed or unsigned integer number is parsed; value is passed\nbool number_integer(number_integer_t val);\nbool number_unsigned(number_unsigned_t val);\n\n// called when a floating-point number is parsed; value and original string is passed\nbool number_float(number_float_t val, const string_t& s);\n\n// called when a string is parsed; value is passed and can be safely moved away\nbool string(string_t& val);\n\n// called when an object or array begins or ends, resp. The number of elements is passed (or -1 if not known)\nbool start_object(std::size_t elements);\nbool end_object();\nbool start_array(std::size_t elements);\nbool end_array();\n// called when an object key is parsed; value is passed and can be safely moved away\nbool key(string_t& val);\n\n// called when a parse error occurs; byte position, the last token, and an exception is passed\nbool parse_error(std::size_t position, const std::string& last_token, const detail::exception& ex);\n```\n\nThe return value of each function determines whether parsing should proceed.\n\nTo implement your own SAX handler, proceed as follows:\n\n1. Implement the SAX interface in a class. You can use class `nlohmann::json_sax<json>` as base class, but you can also use any class where the functions described above are implemented and public.\n2. Create an object of your SAX interface class, e.g. `my_sax`.\n3. Call `bool json::sax_parse(input, &my_sax)`; where the first parameter can be any input like a string or an input stream and the second parameter is a pointer to your SAX interface.\n\nNote the `sax_parse` function only returns a `bool` indicating the result of the last executed SAX event. It does not return a  `json` value - it is up to you to decide what to do with the SAX events. Furthermore, no exceptions are thrown in case of a parse error - it is up to you what to do with the exception object passed to your `parse_error` implementation. Internally, the SAX interface is used for the DOM parser (class `json_sax_dom_parser`) as well as the acceptor (`json_sax_acceptor`), see file [`json_sax.hpp`](https://github.com/nlohmann/json/blob/develop/include/nlohmann/detail/input/json_sax.hpp).\n\n### STL-like access\n\nWe designed the JSON class to behave just like an STL container. In fact, it satisfies the [**ReversibleContainer**](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer) requirement.\n\n```cpp\n// create an array using push_back\njson j;\nj.push_back(\"foo\");\nj.push_back(1);\nj.push_back(true);\n\n// also use emplace_back\nj.emplace_back(1.78);\n\n// iterate the array\nfor (json::iterator it = j.begin(); it != j.end(); ++it) {\n  std::cout << *it << '\\n';\n}\n\n// range-based for\nfor (auto& element : j) {\n  std::cout << element << '\\n';\n}\n\n// getter/setter\nconst auto tmp = j[0].get<std::string>();\nj[1] = 42;\nbool foo = j.at(2);\n\n// comparison\nj == \"[\\\"foo\\\", 1, true]\"_json;  // true\n\n// other stuff\nj.size();     // 3 entries\nj.empty();    // false\nj.type();     // json::value_t::array\nj.clear();    // the array is empty again\n\n// convenience type checkers\nj.is_null();\nj.is_boolean();\nj.is_number();\nj.is_object();\nj.is_array();\nj.is_string();\n\n// create an object\njson o;\no[\"foo\"] = 23;\no[\"bar\"] = false;\no[\"baz\"] = 3.141;\n\n// also use emplace\no.emplace(\"weather\", \"sunny\");\n\n// special iterator member functions for objects\nfor (json::iterator it = o.begin(); it != o.end(); ++it) {\n  std::cout << it.key() << \" : \" << it.value() << \"\\n\";\n}\n\n// the same code as range for\nfor (auto& el : o.items()) {\n  std::cout << el.key() << \" : \" << el.value() << \"\\n\";\n}\n\n// even easier with structured bindings (C++17)\nfor (auto& [key, value] : o.items()) {\n  std::cout << key << \" : \" << value << \"\\n\";\n}\n\n// find an entry\nif (o.find(\"foo\") != o.end()) {\n  // there is an entry with key \"foo\"\n}\n\n// or simpler using count()\nint foo_present = o.count(\"foo\"); // 1\nint fob_present = o.count(\"fob\"); // 0\n\n// delete an entry\no.erase(\"foo\");\n```\n\n\n### Conversion from STL containers\n\nAny sequence container (`std::array`, `std::vector`, `std::deque`, `std::forward_list`, `std::list`) whose values can be used to construct JSON values (e.g., integers, floating point numbers, Booleans, string types, or again STL containers described in this section) can be used to create a JSON array. The same holds for similar associative containers (`std::set`, `std::multiset`, `std::unordered_set`, `std::unordered_multiset`), but in these cases the order of the elements of the array depends on how the elements are ordered in the respective STL container.\n\n```cpp\nstd::vector<int> c_vector {1, 2, 3, 4};\njson j_vec(c_vector);\n// [1, 2, 3, 4]\n\nstd::deque<double> c_deque {1.2, 2.3, 3.4, 5.6};\njson j_deque(c_deque);\n// [1.2, 2.3, 3.4, 5.6]\n\nstd::list<bool> c_list {true, true, false, true};\njson j_list(c_list);\n// [true, true, false, true]\n\nstd::forward_list<int64_t> c_flist {12345678909876, 23456789098765, 34567890987654, 45678909876543};\njson j_flist(c_flist);\n// [12345678909876, 23456789098765, 34567890987654, 45678909876543]\n\nstd::array<unsigned long, 4> c_array {{1, 2, 3, 4}};\njson j_array(c_array);\n// [1, 2, 3, 4]\n\nstd::set<std::string> c_set {\"one\", \"two\", \"three\", \"four\", \"one\"};\njson j_set(c_set); // only one entry for \"one\" is used\n// [\"four\", \"one\", \"three\", \"two\"]\n\nstd::unordered_set<std::string> c_uset {\"one\", \"two\", \"three\", \"four\", \"one\"};\njson j_uset(c_uset); // only one entry for \"one\" is used\n// maybe [\"two\", \"three\", \"four\", \"one\"]\n\nstd::multiset<std::string> c_mset {\"one\", \"two\", \"one\", \"four\"};\njson j_mset(c_mset); // both entries for \"one\" are used\n// maybe [\"one\", \"two\", \"one\", \"four\"]\n\nstd::unordered_multiset<std::string> c_umset {\"one\", \"two\", \"one\", \"four\"};\njson j_umset(c_umset); // both entries for \"one\" are used\n// maybe [\"one\", \"two\", \"one\", \"four\"]\n```\n\nLikewise, any associative key-value containers (`std::map`, `std::multimap`, `std::unordered_map`, `std::unordered_multimap`) whose keys can construct an `std::string` and whose values can be used to construct JSON values (see examples above) can be used to create a JSON object. Note that in case of multimaps only one key is used in the JSON object and the value depends on the internal order of the STL container.\n\n```cpp\nstd::map<std::string, int> c_map { {\"one\", 1}, {\"two\", 2}, {\"three\", 3} };\njson j_map(c_map);\n// {\"one\": 1, \"three\": 3, \"two\": 2 }\n\nstd::unordered_map<const char*, double> c_umap { {\"one\", 1.2}, {\"two\", 2.3}, {\"three\", 3.4} };\njson j_umap(c_umap);\n// {\"one\": 1.2, \"two\": 2.3, \"three\": 3.4}\n\nstd::multimap<std::string, bool> c_mmap { {\"one\", true}, {\"two\", true}, {\"three\", false}, {\"three\", true} };\njson j_mmap(c_mmap); // only one entry for key \"three\" is used\n// maybe {\"one\": true, \"two\": true, \"three\": true}\n\nstd::unordered_multimap<std::string, bool> c_ummap { {\"one\", true}, {\"two\", true}, {\"three\", false}, {\"three\", true} };\njson j_ummap(c_ummap); // only one entry for key \"three\" is used\n// maybe {\"one\": true, \"two\": true, \"three\": true}\n```\n\n### JSON Pointer and JSON Patch\n\nThe library supports **JSON Pointer** ([RFC 6901](https://tools.ietf.org/html/rfc6901)) as alternative means to address structured values. On top of this, **JSON Patch** ([RFC 6902](https://tools.ietf.org/html/rfc6902)) allows to describe differences between two JSON values - effectively allowing patch and diff operations known from Unix.\n\n```cpp\n// a JSON value\njson j_original = R\"({\n  \"baz\": [\"one\", \"two\", \"three\"],\n  \"foo\": \"bar\"\n})\"_json;\n\n// access members with a JSON pointer (RFC 6901)\nj_original[\"/baz/1\"_json_pointer];\n// \"two\"\n\n// a JSON patch (RFC 6902)\njson j_patch = R\"([\n  { \"op\": \"replace\", \"path\": \"/baz\", \"value\": \"boo\" },\n  { \"op\": \"add\", \"path\": \"/hello\", \"value\": [\"world\"] },\n  { \"op\": \"remove\", \"path\": \"/foo\"}\n])\"_json;\n\n// apply the patch\njson j_result = j_original.patch(j_patch);\n// {\n//    \"baz\": \"boo\",\n//    \"hello\": [\"world\"]\n// }\n\n// calculate a JSON patch from two JSON values\njson::diff(j_result, j_original);\n// [\n//   { \"op\":\" replace\", \"path\": \"/baz\", \"value\": [\"one\", \"two\", \"three\"] },\n//   { \"op\": \"remove\",\"path\": \"/hello\" },\n//   { \"op\": \"add\", \"path\": \"/foo\", \"value\": \"bar\" }\n// ]\n```\n\n### JSON Merge Patch\n\nThe library supports **JSON Merge Patch** ([RFC 7386](https://tools.ietf.org/html/rfc7386)) as a patch format. Instead of using JSON Pointer (see above) to specify values to be manipulated, it describes the changes using a syntax that closely mimics the document being modified.\n\n```cpp\n// a JSON value\njson j_document = R\"({\n  \"a\": \"b\",\n  \"c\": {\n    \"d\": \"e\",\n    \"f\": \"g\"\n  }\n})\"_json;\n\n// a patch\njson j_patch = R\"({\n  \"a\":\"z\",\n  \"c\": {\n    \"f\": null\n  }\n})\"_json;\n\n// apply the patch\nj_original.merge_patch(j_patch);\n// {\n//  \"a\": \"z\",\n//  \"c\": {\n//    \"d\": \"e\"\n//  }\n// }\n```\n\n### Implicit conversions\n\nSupported types can be implicitly converted to JSON values.\n\nIt is recommended to **NOT USE** implicit conversions **FROM** a JSON value.\nYou can find more details about this recommendation [here](https://www.github.com/nlohmann/json/issues/958). \n\n```cpp\n// strings\nstd::string s1 = \"Hello, world!\";\njson js = s1;\nauto s2 = js.get<std::string>();\n// NOT RECOMMENDED\nstd::string s3 = js;\nstd::string s4;\ns4 = js;\n\n// Booleans\nbool b1 = true;\njson jb = b1;\nauto b2 = jb.get<bool>();\n// NOT RECOMMENDED\nbool b3 = jb;\nbool b4;\nb4 = jb;\n\n// numbers\nint i = 42;\njson jn = i;\nauto f = jn.get<double>();\n// NOT RECOMMENDED\ndouble f2 = jb;\ndouble f3;\nf3 = jb;\n\n// etc.\n```\n\nNote that `char` types are not automatically converted to JSON strings, but to integer numbers. A conversion to a string must be specified explicitly:\n\n```cpp\nchar ch = 'A';                       // ASCII value 65\njson j_default = ch;                 // stores integer number 65\njson j_string = std::string(1, ch);  // stores string \"A\"\n```\n\n### Arbitrary types conversions\n\nEvery type can be serialized in JSON, not just STL containers and scalar types. Usually, you would do something along those lines:\n\n```cpp\nnamespace ns {\n    // a simple struct to model a person\n    struct person {\n        std::string name;\n        std::string address;\n        int age;\n    };\n}\n\nns::person p = {\"Ned Flanders\", \"744 Evergreen Terrace\", 60};\n\n// convert to JSON: copy each value into the JSON object\njson j;\nj[\"name\"] = p.name;\nj[\"address\"] = p.address;\nj[\"age\"] = p.age;\n\n// ...\n\n// convert from JSON: copy each value from the JSON object\nns::person p {\n    j[\"name\"].get<std::string>(),\n    j[\"address\"].get<std::string>(),\n    j[\"age\"].get<int>()\n};\n```\n\nIt works, but that's quite a lot of boilerplate... Fortunately, there's a better way:\n\n```cpp\n// create a person\nns::person p {\"Ned Flanders\", \"744 Evergreen Terrace\", 60};\n\n// conversion: person -> json\njson j = p;\n\nstd::cout << j << std::endl;\n// {\"address\":\"744 Evergreen Terrace\",\"age\":60,\"name\":\"Ned Flanders\"}\n\n// conversion: json -> person\nauto p2 = j.get<ns::person>();\n\n// that's it\nassert(p == p2);\n```\n\n#### Basic usage\n\nTo make this work with one of your types, you only need to provide two functions:\n\n```cpp\nusing nlohmann::json;\n\nnamespace ns {\n    void to_json(json& j, const person& p) {\n        j = json{{\"name\", p.name}, {\"address\", p.address}, {\"age\", p.age}};\n    }\n\n    void from_json(const json& j, person& p) {\n        j.at(\"name\").get_to(p.name);\n        j.at(\"address\").get_to(p.address);\n        j.at(\"age\").get_to(p.age);\n    }\n} // namespace ns\n```\n\nThat's all! When calling the `json` constructor with your type, your custom `to_json` method will be automatically called.\nLikewise, when calling `get<your_type>()` or `get_to(your_type&)`, the `from_json` method will be called.\n\nSome important things:\n\n* Those methods **MUST** be in your type's namespace (which can be the global namespace), or the library will not be able to locate them (in this example, they are in namespace `ns`, where `person` is defined).\n* Those methods **MUST** be available (e.g., properly headers must be included) everywhere you use these conversions. Look at [issue 1108](https://github.com/nlohmann/json/issues/1108) for errors that may occur otherwise.\n* When using `get<your_type>()`, `your_type` **MUST** be [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible). (There is a way to bypass this requirement described later.)\n* In function `from_json`, use function [`at()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a93403e803947b86f4da2d1fb3345cf2c.html#a93403e803947b86f4da2d1fb3345cf2c) to access the object values rather than `operator[]`. In case a key does not exist, `at` throws an exception that you can handle, whereas `operator[]` exhibits undefined behavior.\n* You do not need to add serializers or deserializers for STL types like `std::vector`: the library already implements these.\n\n\n#### How do I convert third-party types?\n\nThis requires a bit more advanced technique. But first, let's see how this conversion mechanism works:\n\nThe library uses **JSON Serializers** to convert types to json.\nThe default serializer for `nlohmann::json` is `nlohmann::adl_serializer` (ADL means [Argument-Dependent Lookup](https://en.cppreference.com/w/cpp/language/adl)).\n\nIt is implemented like this (simplified):\n\n```cpp\ntemplate <typename T>\nstruct adl_serializer {\n    static void to_json(json& j, const T& value) {\n        // calls the \"to_json\" method in T's namespace\n    }\n\n    static void from_json(const json& j, T& value) {\n        // same thing, but with the \"from_json\" method\n    }\n};\n```\n\nThis serializer works fine when you have control over the type's namespace. However, what about `boost::optional` or `std::filesystem::path` (C++17)? Hijacking the `boost` namespace is pretty bad, and it's illegal to add something other than template specializations to `std`...\n\nTo solve this, you need to add a specialization of `adl_serializer` to the `nlohmann` namespace, here's an example:\n\n```cpp\n// partial specialization (full specialization works too)\nnamespace nlohmann {\n    template <typename T>\n    struct adl_serializer<boost::optional<T>> {\n        static void to_json(json& j, const boost::optional<T>& opt) {\n            if (opt == boost::none) {\n                j = nullptr;\n            } else {\n              j = *opt; // this will call adl_serializer<T>::to_json which will\n                        // find the free function to_json in T's namespace!\n            }\n        }\n\n        static void from_json(const json& j, boost::optional<T>& opt) {\n            if (j.is_null()) {\n                opt = boost::none;\n            } else {\n                opt = j.get<T>(); // same as above, but with\n                                  // adl_serializer<T>::from_json\n            }\n        }\n    };\n}\n```\n\n#### How can I use `get()` for non-default constructible/non-copyable types?\n\nThere is a way, if your type is [MoveConstructible](https://en.cppreference.com/w/cpp/named_req/MoveConstructible). You will need to specialize the `adl_serializer` as well, but with a special `from_json` overload:\n\n```cpp\nstruct move_only_type {\n    move_only_type() = delete;\n    move_only_type(int ii): i(ii) {}\n    move_only_type(const move_only_type&) = delete;\n    move_only_type(move_only_type&&) = default;\n\n    int i;\n};\n\nnamespace nlohmann {\n    template <>\n    struct adl_serializer<move_only_type> {\n        // note: the return type is no longer 'void', and the method only takes\n        // one argument\n        static move_only_type from_json(const json& j) {\n            return {j.get<int>()};\n        }\n\n        // Here's the catch! You must provide a to_json method! Otherwise you\n        // will not be able to convert move_only_type to json, since you fully\n        // specialized adl_serializer on that type\n        static void to_json(json& j, move_only_type t) {\n            j = t.i;\n        }\n    };\n}\n```\n\n#### Can I write my own serializer? (Advanced use)\n\nYes. You might want to take a look at [`unit-udt.cpp`](https://github.com/nlohmann/json/blob/develop/test/src/unit-udt.cpp) in the test suite, to see a few examples.\n\nIf you write your own serializer, you'll need to do a few things:\n\n- use a different `basic_json` alias than `nlohmann::json` (the last template parameter of `basic_json` is the `JSONSerializer`)\n- use your `basic_json` alias (or a template parameter) in all your `to_json`/`from_json` methods\n- use `nlohmann::to_json` and `nlohmann::from_json` when you need ADL\n\nHere is an example, without simplifications, that only accepts types with a size <= 32, and uses ADL.\n\n```cpp\n// You should use void as a second template argument\n// if you don't need compile-time checks on T\ntemplate<typename T, typename SFINAE = typename std::enable_if<sizeof(T) <= 32>::type>\nstruct less_than_32_serializer {\n    template <typename BasicJsonType>\n    static void to_json(BasicJsonType& j, T value) {\n        // we want to use ADL, and call the correct to_json overload\n        using nlohmann::to_json; // this method is called by adl_serializer,\n                                 // this is where the magic happens\n        to_json(j, value);\n    }\n\n    template <typename BasicJsonType>\n    static void from_json(const BasicJsonType& j, T& value) {\n        // same thing here\n        using nlohmann::from_json;\n        from_json(j, value);\n    }\n};\n```\n\nBe **very** careful when reimplementing your serializer, you can stack overflow if you don't pay attention:\n\n```cpp\ntemplate <typename T, void>\nstruct bad_serializer\n{\n    template <typename BasicJsonType>\n    static void to_json(BasicJsonType& j, const T& value) {\n      // this calls BasicJsonType::json_serializer<T>::to_json(j, value);\n      // if BasicJsonType::json_serializer == bad_serializer ... oops!\n      j = value;\n    }\n\n    template <typename BasicJsonType>\n    static void to_json(const BasicJsonType& j, T& value) {\n      // this calls BasicJsonType::json_serializer<T>::from_json(j, value);\n      // if BasicJsonType::json_serializer == bad_serializer ... oops!\n      value = j.template get<T>(); // oops!\n    }\n};\n```\n\n### Specializing enum conversion\n\nBy default, enum values are serialized to JSON as integers. In some cases this could result in undesired behavior. If an enum is modified or re-ordered after data has been serialized to JSON, the later de-serialized JSON data may be undefined or a different enum value than was originally intended.\n\nIt is possible to more precisely specify how a given enum is mapped to and from JSON as shown below:\n\n```cpp\n// example enum type declaration\nenum TaskState {\n    TS_STOPPED,\n    TS_RUNNING,\n    TS_COMPLETED,\n    TS_INVALID=-1,\n};\n\n// map TaskState values to JSON as strings\nNLOHMANN_JSON_SERIALIZE_ENUM( TaskState, {\n    {TS_INVALID, nullptr},\n    {TS_STOPPED, \"stopped\"},\n    {TS_RUNNING, \"running\"},\n    {TS_COMPLETED, \"completed\"},\n});\n```\n\nThe `NLOHMANN_JSON_SERIALIZE_ENUM()` macro declares a set of `to_json()` / `from_json()` functions for type `TaskState` while avoiding repetition and boilerplate serilization code.\n\n**Usage:**\n\n```cpp\n// enum to JSON as string\njson j = TS_STOPPED;\nassert(j == \"stopped\");\n\n// json string to enum\njson j3 = \"running\";\nassert(j3.get<TaskState>() == TS_RUNNING);\n\n// undefined json value to enum (where the first map entry above is the default)\njson jPi = 3.14;\nassert(jPi.get<TaskState>() == TS_INVALID );\n```\n\nJust as in [Arbitrary Type Conversions](#arbitrary-types-conversions) above,\n- `NLOHMANN_JSON_SERIALIZE_ENUM()` MUST be declared in your enum type's namespace (which can be the global namespace), or the library will not be able to locate it and it will default to integer serialization.\n- It MUST be available (e.g., proper headers must be included) everywhere you use the conversions.\n\nOther Important points:\n- When using `get<ENUM_TYPE>()`, undefined JSON values will default to the first pair specified in your map. Select this default pair carefully.\n- If an enum or JSON value is specified more than once in your map, the first matching occurrence from the top of the map will be returned when converting to or from JSON.\n\n### Binary formats (BSON, CBOR, MessagePack, and UBJSON)\n\nThough JSON is a ubiquitous data format, it is not a very compact format suitable for data exchange, for instance over a network. Hence, the library supports [BSON](http://bsonspec.org) (Binary JSON), [CBOR](http://cbor.io) (Concise Binary Object Representation), [MessagePack](http://msgpack.org), and [UBJSON](http://ubjson.org) (Universal Binary JSON Specification) to efficiently encode JSON values to byte vectors and to decode such vectors.\n\n```cpp\n// create a JSON value\njson j = R\"({\"compact\": true, \"schema\": 0})\"_json;\n\n// serialize to BSON\nstd::vector<std::uint8_t> v_bson = json::to_bson(j);\n\n// 0x1B, 0x00, 0x00, 0x00, 0x08, 0x63, 0x6F, 0x6D, 0x70, 0x61, 0x63, 0x74, 0x00, 0x01, 0x10, 0x73, 0x63, 0x68, 0x65, 0x6D, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\n\n// roundtrip\njson j_from_bson = json::from_bson(v_bson);\n\n// serialize to CBOR\nstd::vector<std::uint8_t> v_cbor = json::to_cbor(j);\n\n// 0xA2, 0x67, 0x63, 0x6F, 0x6D, 0x70, 0x61, 0x63, 0x74, 0xF5, 0x66, 0x73, 0x63, 0x68, 0x65, 0x6D, 0x61, 0x00\n\n// roundtrip\njson j_from_cbor = json::from_cbor(v_cbor);\n\n// serialize to MessagePack\nstd::vector<std::uint8_t> v_msgpack = json::to_msgpack(j);\n\n// 0x82, 0xA7, 0x63, 0x6F, 0x6D, 0x70, 0x61, 0x63, 0x74, 0xC3, 0xA6, 0x73, 0x63, 0x68, 0x65, 0x6D, 0x61, 0x00\n\n// roundtrip\njson j_from_msgpack = json::from_msgpack(v_msgpack);\n\n// serialize to UBJSON\nstd::vector<std::uint8_t> v_ubjson = json::to_ubjson(j);\n\n// 0x7B, 0x69, 0x07, 0x63, 0x6F, 0x6D, 0x70, 0x61, 0x63, 0x74, 0x54, 0x69, 0x06, 0x73, 0x63, 0x68, 0x65, 0x6D, 0x61, 0x69, 0x00, 0x7D\n\n// roundtrip\njson j_from_ubjson = json::from_ubjson(v_ubjson);\n```\n\n\n## Supported compilers\n\nThough it's 2018 already, the support for C++11 is still a bit sparse. Currently, the following compilers are known to work:\n\n- GCC 4.8 - 9.0 (and possibly later)\n- Clang 3.4 - 8.0 (and possibly later)\n- Intel C++ Compiler 17.0.2 (and possibly later)\n- Microsoft Visual C++ 2015 / Build Tools 14.0.25123.0 (and possibly later)\n- Microsoft Visual C++ 2017 / Build Tools 15.5.180.51428 (and possibly later)\n\nI would be happy to learn about other compilers/versions.\n\nPlease note:\n\n- GCC 4.8 has a bug [57824](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57824)): multiline raw strings cannot be the arguments to macros. Don't use multiline raw strings directly in macros with this compiler.\n- Android defaults to using very old compilers and C++ libraries. To fix this, add the following to your `Application.mk`. This will switch to the LLVM C++ library, the Clang compiler, and enable C++11 and other features disabled by default.\n\n    ```\n    APP_STL := c++_shared\n    NDK_TOOLCHAIN_VERSION := clang3.6\n    APP_CPPFLAGS += -frtti -fexceptions\n    ```\n\n    The code compiles successfully with [Android NDK](https://developer.android.com/ndk/index.html?hl=ml), Revision 9 - 11 (and possibly later) and [CrystaX's Android NDK](https://www.crystax.net/en/android/ndk) version 10.\n\n- For GCC running on MinGW or Android SDK, the error `'to_string' is not a member of 'std'` (or similarly, for `strtod`) may occur. Note this is not an issue with the code,  but rather with the compiler itself. On Android, see above to build with a newer environment.  For MinGW, please refer to [this site](http://tehsausage.com/mingw-to-string) and [this discussion](https://github.com/nlohmann/json/issues/136) for information on how to fix this bug. For Android NDK using `APP_STL := gnustl_static`, please refer to [this discussion](https://github.com/nlohmann/json/issues/219).\n\n- Unsupported versions of GCC and Clang are rejected by `#error` directives. This can be switched off by defining `JSON_SKIP_UNSUPPORTED_COMPILER_CHECK`. Note that you can expect no support in this case.\n\nThe following compilers are currently used in continuous integration at [Travis](https://travis-ci.org/nlohmann/json) and [AppVeyor](https://ci.appveyor.com/project/nlohmann/json):\n\n| Compiler        | Operating System             | Version String |\n|-----------------|------------------------------|----------------|\n| GCC 4.8.5       | Ubuntu 14.04.5 LTS           | g++-4.8 (Ubuntu 4.8.5-2ubuntu1~14.04.2) 4.8.5 |\n| GCC 4.9.4       | Ubuntu 14.04.1 LTS           | g++-4.9 (Ubuntu 4.9.4-2ubuntu1~14.04.1) 4.9.4 |\n| GCC 5.5.0       | Ubuntu 14.04.1 LTS           | g++-5 (Ubuntu 5.5.0-12ubuntu1~14.04) 5.5.0 20171010 |\n| GCC 6.4.0       | Ubuntu 14.04.1 LTS           | g++-6 (Ubuntu 6.4.0-17ubuntu1~14.04) 6.4.0 20180424 |\n| GCC 7.3.0       | Ubuntu 14.04.1 LTS           | g++-7 (Ubuntu 7.3.0-21ubuntu1~14.04) 7.3.0 |\n| GCC 7.3.0       | Windows Server 2012 R2 (x64) | g++ (x86_64-posix-seh-rev0, Built by MinGW-W64 project) 7.3.0 |\n| GCC 8.1.0       | Ubuntu 14.04.1 LTS           | g++-8 (Ubuntu 8.1.0-5ubuntu1~14.04) 8.1.0 |\n| Clang 3.5.0     | Ubuntu 14.04.1 LTS           | clang version 3.5.0-4ubuntu2~trusty2 (tags/RELEASE_350/final) (based on LLVM 3.5.0) |\n| Clang 3.6.2     | Ubuntu 14.04.1 LTS           | clang version 3.6.2-svn240577-1~exp1 (branches/release_36) (based on LLVM 3.6.2) |\n| Clang 3.7.1     | Ubuntu 14.04.1 LTS           | clang version 3.7.1-svn253571-1~exp1 (branches/release_37) (based on LLVM 3.7.1) |\n| Clang 3.8.0     | Ubuntu 14.04.1 LTS           | clang version 3.8.0-2ubuntu3~trusty5 (tags/RELEASE_380/final) |\n| Clang 3.9.1     | Ubuntu 14.04.1 LTS           | clang version 3.9.1-4ubuntu3~14.04.3 (tags/RELEASE_391/rc2) |\n| Clang 4.0.1     | Ubuntu 14.04.1 LTS           | clang version 4.0.1-svn305264-1~exp1 (branches/release_40) |\n| Clang 5.0.2     | Ubuntu 14.04.1 LTS           | clang version 5.0.2-svn328729-1~exp1~20180509123505.100 (branches/release_50) |\n| Clang 6.0.1     | Ubuntu 14.04.1 LTS           | clang version 6.0.1-svn334776-1~exp1~20180726133705.85 (branches/release_60) |\n| Clang Xcode 6.4 | OSX 10.10.5 | Apple LLVM version 6.1.0 (clang-602.0.53) (based on LLVM 3.6.0svn) |\n| Clang Xcode 7.3 | OSX 10.11.6 | Apple LLVM version 7.3.0 (clang-703.0.31) |\n| Clang Xcode 8.0 | OSX 10.11.6 | Apple LLVM version 8.0.0 (clang-800.0.38) |\n| Clang Xcode 8.1 | OSX 10.12.6 | Apple LLVM version 8.0.0 (clang-800.0.42.1) |\n| Clang Xcode 8.2 | OSX 10.12.6 | Apple LLVM version 8.0.0 (clang-800.0.42.1) |\n| Clang Xcode 8.3 | OSX 10.11.6 | Apple LLVM version 8.1.0 (clang-802.0.38) |\n| Clang Xcode 9.0 | OSX 10.12.6 | Apple LLVM version 9.0.0 (clang-900.0.37) |\n| Clang Xcode 9.1 | OSX 10.12.6 | Apple LLVM version 9.0.0 (clang-900.0.38) |\n| Clang Xcode 9.2 | OSX 10.13.3 | Apple LLVM version 9.1.0 (clang-902.0.39.1) |\n| Clang Xcode 9.3 | OSX 10.13.3 | Apple LLVM version 9.1.0 (clang-902.0.39.2) |\n| Clang Xcode 10.0 | OSX 10.13.3 | Apple LLVM version 10.0.0 (clang-1000.11.45.2) |\n| Visual Studio 14 2015 | Windows Server 2012 R2 (x64) | Microsoft (R) Build Engine version 14.0.25420.1, MSVC 19.0.24215.1 |\n| Visual Studio 2017 | Windows Server 2016 | Microsoft (R) Build Engine version 15.7.180.61344, MSVC 19.14.26433.0 |\n\n## License\n\n<img align=\"right\" src=\"http://opensource.org/trademarks/opensource/OSI-Approved-License-100x137.png\">\n\nThe class is licensed under the [MIT License](http://opensource.org/licenses/MIT):\n\nCopyright &copy; 2013-2018 [Niels Lohmann](http://nlohmann.me)\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n* * *\n\nThe class contains the UTF-8 Decoder from Bjoern Hoehrmann which is licensed under the [MIT License](http://opensource.org/licenses/MIT) (see above). Copyright &copy; 2008-2009 [Björn Hoehrmann](http://bjoern.hoehrmann.de/) <bjoern@hoehrmann.de>\n\nThe class contains a slightly modified version of the Grisu2 algorithm from Florian Loitsch which is licensed under the [MIT License](http://opensource.org/licenses/MIT) (see above). Copyright &copy; 2009 [Florian Loitsch](http://florian.loitsch.com/)\n\n## Contact\n\nIf you have questions regarding the library, I would like to invite you to [open an issue at GitHub](https://github.com/nlohmann/json/issues/new). Please describe your request, problem, or question as detailed as possible, and also mention the version of the library you are using as well as the version of your compiler and operating system. Opening an issue at GitHub allows other users and contributors to this library to collaborate. For instance, I have little experience with MSVC, and most issues in this regard have been solved by a growing community. If you have a look at the [closed issues](https://github.com/nlohmann/json/issues?q=is%3Aissue+is%3Aclosed), you will see that we react quite timely in most cases.\n\nOnly if your request would contain confidential information, please [send me an email](mailto:mail@nlohmann.me). For encrypted messages, please use [this key](https://keybase.io/nlohmann/pgp_keys.asc).\n\n## Security\n\n[Commits by Niels Lohmann](https://github.com/nlohmann/json/commits) and [releases](https://github.com/nlohmann/json/releases) are signed with this [PGP Key](https://keybase.io/nlohmann/pgp_keys.asc?fingerprint=797167ae41c0a6d9232e48457f3cea63ae251b69).\n\n## Thanks\n\nI deeply appreciate the help of the following people.\n\n<img src=\"https://raw.githubusercontent.com/nlohmann/json/develop/doc/avatars.png\" align=\"right\">\n\n- [Teemperor](https://github.com/Teemperor) implemented CMake support and lcov integration, realized escape and Unicode handling in the string parser, and fixed the JSON serialization.\n- [elliotgoodrich](https://github.com/elliotgoodrich) fixed an issue with double deletion in the iterator classes.\n- [kirkshoop](https://github.com/kirkshoop) made the iterators of the class composable to other libraries.\n- [wancw](https://github.com/wanwc) fixed a bug that hindered the class to compile with Clang.\n- Tomas Åblad found a bug in the iterator implementation.\n- [Joshua C. Randall](https://github.com/jrandall) fixed a bug in the floating-point serialization.\n- [Aaron Burghardt](https://github.com/aburgh) implemented code to parse streams incrementally. Furthermore, he greatly improved the parser class by allowing the definition of a filter function to discard undesired elements while parsing.\n- [Daniel Kopeček](https://github.com/dkopecek) fixed a bug in the compilation with GCC 5.0.\n- [Florian Weber](https://github.com/Florianjw) fixed a bug in and improved the performance of the comparison operators.\n- [Eric Cornelius](https://github.com/EricMCornelius) pointed out a bug in the handling with NaN and infinity values. He also improved the performance of the string escaping.\n- [易思龙](https://github.com/likebeta) implemented a conversion from anonymous enums.\n- [kepkin](https://github.com/kepkin) patiently pushed forward the support for Microsoft Visual studio.\n- [gregmarr](https://github.com/gregmarr) simplified the implementation of reverse iterators and helped with numerous hints and improvements. In particular, he pushed forward the implementation of user-defined types.\n- [Caio Luppi](https://github.com/caiovlp) fixed a bug in the Unicode handling.\n- [dariomt](https://github.com/dariomt) fixed some typos in the examples.\n- [Daniel Frey](https://github.com/d-frey) cleaned up some pointers and implemented exception-safe memory allocation.\n- [Colin Hirsch](https://github.com/ColinH) took care of a small namespace issue.\n- [Huu Nguyen](https://github.com/whoshuu) correct a variable name in the documentation.\n- [Silverweed](https://github.com/silverweed) overloaded `parse()` to accept an rvalue reference.\n- [dariomt](https://github.com/dariomt) fixed a subtlety in MSVC type support and implemented the `get_ref()` function to get a reference to stored values.\n- [ZahlGraf](https://github.com/ZahlGraf) added a workaround that allows compilation using Android NDK.\n- [whackashoe](https://github.com/whackashoe) replaced a function that was marked as unsafe by Visual Studio.\n- [406345](https://github.com/406345) fixed two small warnings.\n- [Glen Fernandes](https://github.com/glenfe) noted a potential portability problem in the `has_mapped_type` function.\n- [Corbin Hughes](https://github.com/nibroc) fixed some typos in the contribution guidelines.\n- [twelsby](https://github.com/twelsby) fixed the array subscript operator, an issue that failed the MSVC build, and floating-point parsing/dumping. He further added support for unsigned integer numbers and implemented better roundtrip support for parsed numbers.\n- [Volker Diels-Grabsch](https://github.com/vog) fixed a link in the README file.\n- [msm-](https://github.com/msm-) added support for American Fuzzy Lop.\n- [Annihil](https://github.com/Annihil) fixed an example in the README file.\n- [Themercee](https://github.com/Themercee) noted a wrong URL in the README file.\n- [Lv Zheng](https://github.com/lv-zheng) fixed a namespace issue with `int64_t` and `uint64_t`.\n- [abc100m](https://github.com/abc100m) analyzed the issues with GCC 4.8 and proposed a [partial solution](https://github.com/nlohmann/json/pull/212).\n- [zewt](https://github.com/zewt) added useful notes to the README file about Android.\n- [Róbert Márki](https://github.com/robertmrk) added a fix to use move iterators and improved the integration via CMake.\n- [Chris Kitching](https://github.com/ChrisKitching) cleaned up the CMake files.\n- [Tom Needham](https://github.com/06needhamt) fixed a subtle bug with MSVC 2015 which was also proposed by [Michael K.](https://github.com/Epidal).\n- [Mário Feroldi](https://github.com/thelostt) fixed a small typo.\n- [duncanwerner](https://github.com/duncanwerner) found a really embarrassing performance regression in the 2.0.0 release.\n- [Damien](https://github.com/dtoma) fixed one of the last conversion warnings.\n- [Thomas Braun](https://github.com/t-b) fixed a warning in a test case.\n- [Théo DELRIEU](https://github.com/theodelrieu) patiently and constructively oversaw the long way toward [iterator-range parsing](https://github.com/nlohmann/json/issues/290). He also implemented the magic behind the serialization/deserialization of user-defined types and split the single header file into smaller chunks.\n- [Stefan](https://github.com/5tefan) fixed a minor issue in the documentation.\n- [Vasil Dimov](https://github.com/vasild) fixed the documentation regarding conversions from `std::multiset`.\n- [ChristophJud](https://github.com/ChristophJud) overworked the CMake files to ease project inclusion.\n- [Vladimir Petrigo](https://github.com/vpetrigo) made a SFINAE hack more readable and added Visual Studio 17 to the build matrix.\n- [Denis Andrejew](https://github.com/seeekr) fixed a grammar issue in the README file.\n- [Pierre-Antoine Lacaze](https://github.com/palacaze) found a subtle bug in the `dump()` function.\n- [TurpentineDistillery](https://github.com/TurpentineDistillery) pointed to [`std::locale::classic()`](https://en.cppreference.com/w/cpp/locale/locale/classic) to avoid too much locale joggling, found some nice performance improvements in the parser, improved the benchmarking code, and realized locale-independent number parsing and printing.\n- [cgzones](https://github.com/cgzones) had an idea how to fix the Coverity scan.\n- [Jared Grubb](https://github.com/jaredgrubb) silenced a nasty documentation warning.\n- [Yixin Zhang](https://github.com/qwename) fixed an integer overflow check.\n- [Bosswestfalen](https://github.com/Bosswestfalen) merged two iterator classes into a smaller one.\n- [Daniel599](https://github.com/Daniel599) helped to get Travis execute the tests with Clang's sanitizers.\n- [Jonathan Lee](https://github.com/vjon) fixed an example in the README file.\n- [gnzlbg](https://github.com/gnzlbg) supported the implementation of user-defined types.\n- [Alexej Harm](https://github.com/qis) helped to get the user-defined types working with Visual Studio.\n- [Jared Grubb](https://github.com/jaredgrubb) supported the implementation of user-defined types.\n- [EnricoBilla](https://github.com/EnricoBilla) noted a typo in an example.\n- [Martin Hořeňovský](https://github.com/horenmar) found a way for a 2x speedup for the compilation time of the test suite.\n- [ukhegg](https://github.com/ukhegg) found proposed an improvement for the examples section.\n- [rswanson-ihi](https://github.com/rswanson-ihi) noted a typo in the README.\n- [Mihai Stan](https://github.com/stanmihai4) fixed a bug in the comparison with `nullptr`s.\n- [Tushar Maheshwari](https://github.com/tusharpm) added [cotire](https://github.com/sakra/cotire) support to speed up the compilation.\n- [TedLyngmo](https://github.com/TedLyngmo) noted a typo in the README, removed unnecessary bit arithmetic, and fixed some `-Weffc++` warnings.\n- [Krzysztof Woś](https://github.com/krzysztofwos) made exceptions more visible.\n- [ftillier](https://github.com/ftillier) fixed a compiler warning.\n- [tinloaf](https://github.com/tinloaf) made sure all pushed warnings are properly popped.\n- [Fytch](https://github.com/Fytch) found a bug in the documentation.\n- [Jay Sistar](https://github.com/Type1J) implemented a Meson build description.\n- [Henry Lee](https://github.com/HenryRLee) fixed a warning in ICC and improved the iterator implementation.\n- [Vincent Thiery](https://github.com/vthiery) maintains a package for the Conan package manager.\n- [Steffen](https://github.com/koemeet) fixed a potential issue with MSVC and `std::min`.\n- [Mike Tzou](https://github.com/Chocobo1) fixed some typos.\n- [amrcode](https://github.com/amrcode) noted a misleading documentation about comparison of floats.\n- [Oleg Endo](https://github.com/olegendo) reduced the memory consumption by replacing `<iostream>` with `<iosfwd>`.\n- [dan-42](https://github.com/dan-42) cleaned up the CMake files to simplify including/reusing of the library.\n- [Nikita Ofitserov](https://github.com/himikof) allowed for moving values from initializer lists.\n- [Greg Hurrell](https://github.com/wincent) fixed a typo.\n- [Dmitry Kukovinets](https://github.com/DmitryKuk) fixed a typo.\n- [kbthomp1](https://github.com/kbthomp1) fixed an issue related to the Intel OSX compiler.\n- [Markus Werle](https://github.com/daixtrose) fixed a typo.\n- [WebProdPP](https://github.com/WebProdPP) fixed a subtle error in a precondition check.\n- [Alex](https://github.com/leha-bot) noted an error in a code sample.\n- [Tom de Geus](https://github.com/tdegeus) reported some warnings with ICC and helped fixing them.\n- [Perry Kundert](https://github.com/pjkundert) simplified reading from input streams.\n- [Sonu Lohani](https://github.com/sonulohani) fixed a small compilation error.\n- [Jamie Seward](https://github.com/jseward) fixed all MSVC warnings.\n- [Nate Vargas](https://github.com/eld00d) added a Doxygen tag file.\n- [pvleuven](https://github.com/pvleuven) helped fixing a warning in ICC.\n- [Pavel](https://github.com/crea7or) helped fixing some warnings in MSVC.\n- [Jamie Seward](https://github.com/jseward) avoided unnecessary string copies in `find()` and `count()`.\n- [Mitja](https://github.com/Itja) fixed some typos.\n- [Jorrit Wronski](https://github.com/jowr) updated the Hunter package links.\n- [Matthias Möller](https://github.com/TinyTinni) added a `.natvis` for the MSVC debug view.\n- [bogemic](https://github.com/bogemic) fixed some C++17 deprecation warnings.\n- [Eren Okka](https://github.com/erengy) fixed some MSVC warnings.\n- [abolz](https://github.com/abolz) integrated the Grisu2 algorithm for proper floating-point formatting, allowing more roundtrip checks to succeed.\n- [Vadim Evard](https://github.com/Pipeliner) fixed a Markdown issue in the README.\n- [zerodefect](https://github.com/zerodefect) fixed a compiler warning.\n- [Kert](https://github.com/kaidokert) allowed to template the string type in the serialization and added the possibility to override the exceptional behavior.\n- [mark-99](https://github.com/mark-99) helped fixing an ICC error.\n- [Patrik Huber](https://github.com/patrikhuber) fixed links in the README file.\n- [johnfb](https://github.com/johnfb) found a bug in the implementation of CBOR's indefinite length strings.\n- [Paul Fultz II](https://github.com/pfultz2) added a note on the cget package manager.\n- [Wilson Lin](https://github.com/wla80) made the integration section of the README more concise.\n- [RalfBielig](https://github.com/ralfbielig) detected and fixed a memory leak in the parser callback.\n- [agrianius](https://github.com/agrianius) allowed to dump JSON to an alternative string type.\n- [Kevin Tonon](https://github.com/ktonon) overworked the C++11 compiler checks in CMake.\n- [Axel Huebl](https://github.com/ax3l) simplified a CMake check and added support for the [Spack package manager](https://spack.io).\n- [Carlos O'Ryan](https://github.com/coryan) fixed a typo.\n- [James Upjohn](https://github.com/jammehcow) fixed a version number in the compilers section.\n- [Chuck Atkins](https://github.com/chuckatkins) adjusted the CMake files to the CMake packaging guidelines and provided documentation for the CMake integration.\n- [Jan Schöppach](https://github.com/dns13) fixed a typo.\n- [martin-mfg](https://github.com/martin-mfg) fixed a typo.\n- [Matthias Möller](https://github.com/TinyTinni) removed the dependency from `std::stringstream`.\n- [agrianius](https://github.com/agrianius) added code to use alternative string implementations.\n- [Daniel599](https://github.com/Daniel599) allowed to use more algorithms with the `items()` function.\n- [Julius Rakow](https://github.com/jrakow) fixed the Meson include directory and fixed the links to [cppreference.com](cppreference.com).\n- [Sonu Lohani](https://github.com/sonulohani) fixed the compilation with MSVC 2015 in debug mode.\n- [grembo](https://github.com/grembo) fixed the test suite and re-enabled several test cases.\n- [Hyeon Kim](https://github.com/simnalamburt) introduced the macro `JSON_INTERNAL_CATCH` to control the exception handling inside the library.\n- [thyu](https://github.com/thyu) fixed a compiler warning.\n- [David Guthrie](https://github.com/LEgregius) fixed a subtle compilation error with Clang 3.4.2.\n- [Dennis Fischer](https://github.com/dennisfischer) allowed to call `find_package` without installing the library.\n- [Hyeon Kim](https://github.com/simnalamburt) fixed an issue with a double macro definition.\n- [Ben Berman](https://github.com/rivertam) made some error messages more understandable.\n- [zakalibit](https://github.com/zakalibit) fixed a compilation problem with the Intel C++ compiler.\n- [mandreyel](https://github.com/mandreyel) fixed a compilation problem.\n- [Kostiantyn Ponomarenko](https://github.com/koponomarenko) added version and license information to the Meson build file.\n- [Henry Schreiner](https://github.com/henryiii) added support for GCC 4.8.\n- [knilch](https://github.com/knilch0r) made sure the test suite does not stall when run in the wrong directory.\n- [Antonio Borondo](https://github.com/antonioborondo) fixed an MSVC 2017 warning.\n- [Dan Gendreau](https://github.com/dgendreau) implemented the `NLOHMANN_JSON_SERIALIZE_ENUM` macro to quickly define a enum/JSON mapping.\n- [efp](https://github.com/efp) added line and column information to parse errors.\n- [julian-becker](https://github.com/julian-becker) added BSON support.\n- [Pratik Chowdhury](https://github.com/pratikpc) added support for structured bindings.\n- [David Avedissian](https://github.com/davedissian) added support for Clang 5.0.1 (PS4 version).\n- [Jonathan Dumaresq](https://github.com/dumarjo) implemented an input adapter to read from `FILE*`.\n- [kjpus](https://github.com/kjpus) fixed a link in the documentation.\n- [Manvendra Singh](https://github.com/manu-chroma) fixed a typo in the documentation.\n- [ziggurat29](https://github.com/ziggurat29) fixed an MSVC warning.\n- [Sylvain Corlay](https://github.com/SylvainCorlay) added code to avoid an issue with MSVC.\n- [mefyl](https://github.com/mefyl) fixed a bug when JSON was parsed from an input stream.\n- [Millian Poquet](https://github.com/mpoquet) allowed to install the library via Meson.\n\nThanks a lot for helping out! Please [let me know](mailto:mail@nlohmann.me) if I forgot someone.\n\n\n## Used third-party tools\n\nThe library itself consists of a single header file licensed under the MIT license. However, it is built, tested, documented, and whatnot using a lot of third-party tools and services. Thanks a lot!\n\n- [**amalgamate.py - Amalgamate C source and header files**](https://github.com/edlund/amalgamate) to create a single header file\n- [**American fuzzy lop**](http://lcamtuf.coredump.cx/afl/) for fuzz testing\n- [**AppVeyor**](https://www.appveyor.com) for [continuous integration](https://ci.appveyor.com/project/nlohmann/json) on Windows\n- [**Artistic Style**](http://astyle.sourceforge.net) for automatic source code identation\n- [**Catch**](https://github.com/philsquared/Catch) for the unit tests\n- [**Clang**](http://clang.llvm.org) for compilation with code sanitizers\n- [**CMake**](https://cmake.org) for build automation\n- [**Codacity**](https://www.codacy.com) for further [code analysis](https://www.codacy.com/app/nlohmann/json)\n- [**Coveralls**](https://coveralls.io) to measure [code coverage](https://coveralls.io/github/nlohmann/json)\n- [**Coverity Scan**](https://scan.coverity.com) for [static analysis](https://scan.coverity.com/projects/nlohmann-json)\n- [**cppcheck**](http://cppcheck.sourceforge.net) for static analysis\n- [**Doxygen**](http://www.stack.nl/~dimitri/doxygen/) to generate [documentation](https://nlohmann.github.io/json/)\n- [**git-update-ghpages**](https://github.com/rstacruz/git-update-ghpages) to upload the documentation to gh-pages\n- [**GitHub Changelog Generator**](https://github.com/skywinder/github-changelog-generator) to generate the [ChangeLog](https://github.com/nlohmann/json/blob/develop/ChangeLog.md)\n- [**Google Benchmark**](https://github.com/google/benchmark) to implement the benchmarks\n- [**libFuzzer**](http://llvm.org/docs/LibFuzzer.html) to implement fuzz testing for OSS-Fuzz\n- [**OSS-Fuzz**](https://github.com/google/oss-fuzz) for continuous fuzz testing of the library ([project repository](https://github.com/google/oss-fuzz/tree/master/projects/json))\n- [**Probot**](https://probot.github.io) for automating maintainer tasks such as closing stale issues, requesting missing information, or detecting toxic comments.\n- [**send_to_wandbox**](https://github.com/nlohmann/json/blob/develop/doc/scripts/send_to_wandbox.py) to send code examples to [Wandbox](http://melpon.org/wandbox)\n- [**Travis**](https://travis-ci.org) for [continuous integration](https://travis-ci.org/nlohmann/json) on Linux and macOS\n- [**Valgrind**](http://valgrind.org) to check for correct memory management\n- [**Wandbox**](http://melpon.org/wandbox) for [online examples](https://wandbox.org/permlink/TarF5pPn9NtHQjhf)\n\n\n## Projects using JSON for Modern C++\n\nThe library is currently used in Apple macOS Sierra and iOS 10. I am not sure what they are using the library for, but I am happy that it runs on so many devices.\n\n\n## Notes\n\n- The code contains numerous debug **assertions** which can be switched off by defining the preprocessor macro `NDEBUG`, see the [documentation of `assert`](https://en.cppreference.com/w/cpp/error/assert). In particular, note [`operator[]`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a2e26bd0b0168abb61f67ad5bcd5b9fa1.html#a2e26bd0b0168abb61f67ad5bcd5b9fa1) implements **unchecked access** for const objects: If the given key is not present, the behavior is undefined (think of a dereferenced null pointer) and yields an [assertion failure](https://github.com/nlohmann/json/issues/289) if assertions are switched on. If you are not sure whether an element in an object exists, use checked access with the [`at()` function](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a674de1ee73e6bf4843fc5dc1351fb726.html#a674de1ee73e6bf4843fc5dc1351fb726).\n- As the exact type of a number is not defined in the [JSON specification](http://rfc7159.net/rfc7159), this library tries to choose the best fitting C++ number type automatically. As a result, the type `double` may be used to store numbers which may yield [**floating-point exceptions**](https://github.com/nlohmann/json/issues/181) in certain rare situations if floating-point exceptions have been unmasked in the calling code. These exceptions are not caused by the library and need to be fixed in the calling code, such as by re-masking the exceptions prior to calling library functions.\n- The library supports **Unicode input** as follows:\n  - Only **UTF-8** encoded input is supported which is the default encoding for JSON according to [RFC 7159](http://rfc7159.net/rfc7159#rfc.section.8.1).\n  - Other encodings such as Latin-1, UTF-16, or UTF-32 are not supported and will yield parse or serialization errors.\n  - [Unicode noncharacters](http://www.unicode.org/faq/private_use.html#nonchar1) will not be replaced by the library.\n  - Invalid surrogates (e.g., incomplete pairs such as `\\uDEAD`) will yield parse errors.\n  - The strings stored in the library are UTF-8 encoded. When using the default string type (`std::string`), note that its length/size functions return the number of stored bytes rather than the number of characters or glyphs.\n- The code can be compiled without C++ **runtime type identification** features; that is, you can use the `-fno-rtti` compiler flag.\n- **Exceptions** are used widely within the library. They can, however, be switched off with either using the compiler flag `-fno-exceptions` or by defining the symbol `JSON_NOEXCEPTION`. In this case, exceptions are replaced by an `abort()` call.\n- By default, the library does not preserve the **insertion order of object elements**. This is standards-compliant, as the [JSON standard](https://tools.ietf.org/html/rfc7159.html) defines objects as \"an unordered collection of zero or more name/value pairs\". If you do want to preserve the insertion order, you can specialize the object type with containers like [`tsl::ordered_map`](https://github.com/Tessil/ordered-map) ([integration](https://github.com/nlohmann/json/issues/546#issuecomment-304447518)) or [`nlohmann::fifo_map`](https://github.com/nlohmann/fifo_map) ([integration](https://github.com/nlohmann/json/issues/485#issuecomment-333652309)).\n\n\n## Execute unit tests\n\nTo compile and run the tests, you need to execute\n\n```sh\n$ mkdir build\n$ cd build\n$ cmake ..\n$ cmake --build .\n$ ctest --output-on-failure\n```\n\nFor more information, have a look at the file [.travis.yml](https://github.com/nlohmann/json/blob/master/.travis.yml).\n"
  },
  {
    "path": "nlohmann_json/appveyor.yml",
    "content": "version: '{build}'\n\nenvironment:\n  matrix:\n    - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015\n      COMPILER: mingw\n      platform: x86\n      FLAGS: \"\"\n      GENERATOR: Ninja\n\n    - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015\n      platform: x86\n      FLAGS: \"\"\n      GENERATOR: Visual Studio 14 2015\n\n    - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017\n      platform: x86\n      FLAGS: \"\"\n      GENERATOR: Visual Studio 15 2017\n\n    - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017\n      platform: x86\n      FLAGS: \"/permissive- /std:c++latest /utf-8\"\n      GENERATOR: Visual Studio 15 2017\n\n    - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015\n      platform: x64\n      FLAGS: \"\"\n      GENERATOR: Visual Studio 14 2015\n\n    - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017\n      platform: x64\n      FLAGS: \"\"\n      GENERATOR: Visual Studio 15 2017\n\n    - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017\n      platform: x64\n      FLAGS: \"/permissive- /std:c++latest /utf-8\"\n      GENERATOR: Visual Studio 15 2017\n\ninit:\n  - cmake --version\n  - msbuild /version\n\ninstall:\n  - if \"%COMPILER%\"==\"mingw\" appveyor DownloadFile https://github.com/ninja-build/ninja/releases/download/v1.6.0/ninja-win.zip -FileName ninja.zip\n  - if \"%COMPILER%\"==\"mingw\" 7z x ninja.zip -oC:\\projects\\deps\\ninja > nul\n  - if \"%COMPILER%\"==\"mingw\" set PATH=C:\\projects\\deps\\ninja;%PATH%\n  - if \"%COMPILER%\"==\"mingw\" set PATH=C:\\mingw-w64\\x86_64-7.3.0-posix-seh-rt_v5-rev0\\mingw64\\bin;%PATH%\n  - if \"%COMPILER%\"==\"mingw\" g++ --version\n\nbefore_build:\n  - cmake . -G \"%GENERATOR%\" -DCMAKE_CXX_FLAGS=\"%FLAGS%\" -DCMAKE_IGNORE_PATH=\"C:/Program Files/Git/usr/bin\"\n\nbuild_script:\n  - cmake --build . --config Release\n\ntest_script:\n  - ctest -C Release -V -j\n"
  },
  {
    "path": "nlohmann_json/cmake/config.cmake.in",
    "content": "include(FindPackageHandleStandardArgs)\nset(${CMAKE_FIND_PACKAGE_NAME}_CONFIG ${CMAKE_CURRENT_LIST_FILE})\nfind_package_handle_standard_args(@PROJECT_NAME@ CONFIG_MODE)\n\nif(NOT TARGET @PROJECT_NAME@::@NLOHMANN_JSON_TARGET_NAME@)\n    include(\"${CMAKE_CURRENT_LIST_DIR}/@NLOHMANN_JSON_TARGETS_EXPORT_NAME@.cmake\")\n    if((NOT TARGET @NLOHMANN_JSON_TARGET_NAME@) AND\n       (NOT @PROJECT_NAME@_FIND_VERSION OR\n        @PROJECT_NAME@_FIND_VERSION VERSION_LESS 3.2.0))\n        add_library(@NLOHMANN_JSON_TARGET_NAME@ INTERFACE IMPORTED)\n        set_target_properties(@NLOHMANN_JSON_TARGET_NAME@ PROPERTIES\n            INTERFACE_LINK_LIBRARIES @PROJECT_NAME@::@NLOHMANN_JSON_TARGET_NAME@\n        )\n    endif()\nendif()\n"
  },
  {
    "path": "nlohmann_json/include/nlohmann/adl_serializer.hpp",
    "content": "#pragma once\n\n#include <utility>\n\n#include <nlohmann/detail/conversions/from_json.hpp>\n#include <nlohmann/detail/conversions/to_json.hpp>\n\nnamespace nlohmann\n{\n\ntemplate<typename, typename>\nstruct adl_serializer\n{\n    /*!\n    @brief convert a JSON value to any value type\n\n    This function is usually called by the `get()` function of the\n    @ref basic_json class (either explicit or via conversion operators).\n\n    @param[in] j        JSON value to read from\n    @param[in,out] val  value to write to\n    */\n    template<typename BasicJsonType, typename ValueType>\n    static auto from_json(BasicJsonType&& j, ValueType& val) noexcept(\n        noexcept(::nlohmann::from_json(std::forward<BasicJsonType>(j), val)))\n    -> decltype(::nlohmann::from_json(std::forward<BasicJsonType>(j), val), void())\n    {\n        ::nlohmann::from_json(std::forward<BasicJsonType>(j), val);\n    }\n\n    /*!\n    @brief convert any value type to a JSON value\n\n    This function is usually called by the constructors of the @ref basic_json\n    class.\n\n    @param[in,out] j  JSON value to write to\n    @param[in] val    value to read from\n    */\n    template <typename BasicJsonType, typename ValueType>\n    static auto to_json(BasicJsonType& j, ValueType&& val) noexcept(\n        noexcept(::nlohmann::to_json(j, std::forward<ValueType>(val))))\n    -> decltype(::nlohmann::to_json(j, std::forward<ValueType>(val)), void())\n    {\n        ::nlohmann::to_json(j, std::forward<ValueType>(val));\n    }\n};\n\n}  // namespace nlohmann\n"
  },
  {
    "path": "nlohmann_json/include/nlohmann/detail/conversions/from_json.hpp",
    "content": "#pragma once\n\n#include <algorithm> // transform\n#include <array> // array\n#include <ciso646> // and, not\n#include <forward_list> // forward_list\n#include <iterator> // inserter, front_inserter, end\n#include <map> // map\n#include <string> // string\n#include <tuple> // tuple, make_tuple\n#include <type_traits> // is_arithmetic, is_same, is_enum, underlying_type, is_convertible\n#include <unordered_map> // unordered_map\n#include <utility> // pair, declval\n#include <valarray> // valarray\n\n#include <nlohmann/detail/exceptions.hpp>\n#include <nlohmann/detail/macro_scope.hpp>\n#include <nlohmann/detail/meta/cpp_future.hpp>\n#include <nlohmann/detail/meta/type_traits.hpp>\n#include <nlohmann/detail/value_t.hpp>\n\nnamespace nlohmann\n{\nnamespace detail\n{\ntemplate<typename BasicJsonType>\nvoid from_json(const BasicJsonType& j, typename std::nullptr_t& n)\n{\n    if (JSON_UNLIKELY(not j.is_null()))\n    {\n        JSON_THROW(type_error::create(302, \"type must be null, but is \" + std::string(j.type_name())));\n    }\n    n = nullptr;\n}\n\n// overloads for basic_json template parameters\ntemplate<typename BasicJsonType, typename ArithmeticType,\n         enable_if_t<std::is_arithmetic<ArithmeticType>::value and\n                     not std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value,\n                     int> = 0>\nvoid get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val)\n{\n    switch (static_cast<value_t>(j))\n    {\n        case value_t::number_unsigned:\n        {\n            val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_unsigned_t*>());\n            break;\n        }\n        case value_t::number_integer:\n        {\n            val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_integer_t*>());\n            break;\n        }\n        case value_t::number_float:\n        {\n            val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_float_t*>());\n            break;\n        }\n\n        default:\n            JSON_THROW(type_error::create(302, \"type must be number, but is \" + std::string(j.type_name())));\n    }\n}\n\ntemplate<typename BasicJsonType>\nvoid from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b)\n{\n    if (JSON_UNLIKELY(not j.is_boolean()))\n    {\n        JSON_THROW(type_error::create(302, \"type must be boolean, but is \" + std::string(j.type_name())));\n    }\n    b = *j.template get_ptr<const typename BasicJsonType::boolean_t*>();\n}\n\ntemplate<typename BasicJsonType>\nvoid from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s)\n{\n    if (JSON_UNLIKELY(not j.is_string()))\n    {\n        JSON_THROW(type_error::create(302, \"type must be string, but is \" + std::string(j.type_name())));\n    }\n    s = *j.template get_ptr<const typename BasicJsonType::string_t*>();\n}\n\ntemplate <\n    typename BasicJsonType, typename ConstructibleStringType,\n    enable_if_t <\n        is_constructible_string_type<BasicJsonType, ConstructibleStringType>::value and\n        not std::is_same<typename BasicJsonType::string_t,\n                         ConstructibleStringType>::value,\n        int > = 0 >\nvoid from_json(const BasicJsonType& j, ConstructibleStringType& s)\n{\n    if (JSON_UNLIKELY(not j.is_string()))\n    {\n        JSON_THROW(type_error::create(302, \"type must be string, but is \" + std::string(j.type_name())));\n    }\n\n    s = *j.template get_ptr<const typename BasicJsonType::string_t*>();\n}\n\ntemplate<typename BasicJsonType>\nvoid from_json(const BasicJsonType& j, typename BasicJsonType::number_float_t& val)\n{\n    get_arithmetic_value(j, val);\n}\n\ntemplate<typename BasicJsonType>\nvoid from_json(const BasicJsonType& j, typename BasicJsonType::number_unsigned_t& val)\n{\n    get_arithmetic_value(j, val);\n}\n\ntemplate<typename BasicJsonType>\nvoid from_json(const BasicJsonType& j, typename BasicJsonType::number_integer_t& val)\n{\n    get_arithmetic_value(j, val);\n}\n\ntemplate<typename BasicJsonType, typename EnumType,\n         enable_if_t<std::is_enum<EnumType>::value, int> = 0>\nvoid from_json(const BasicJsonType& j, EnumType& e)\n{\n    typename std::underlying_type<EnumType>::type val;\n    get_arithmetic_value(j, val);\n    e = static_cast<EnumType>(val);\n}\n\n// forward_list doesn't have an insert method\ntemplate<typename BasicJsonType, typename T, typename Allocator,\n         enable_if_t<std::is_convertible<BasicJsonType, T>::value, int> = 0>\nvoid from_json(const BasicJsonType& j, std::forward_list<T, Allocator>& l)\n{\n    if (JSON_UNLIKELY(not j.is_array()))\n    {\n        JSON_THROW(type_error::create(302, \"type must be array, but is \" + std::string(j.type_name())));\n    }\n    std::transform(j.rbegin(), j.rend(),\n                   std::front_inserter(l), [](const BasicJsonType & i)\n    {\n        return i.template get<T>();\n    });\n}\n\n// valarray doesn't have an insert method\ntemplate<typename BasicJsonType, typename T,\n         enable_if_t<std::is_convertible<BasicJsonType, T>::value, int> = 0>\nvoid from_json(const BasicJsonType& j, std::valarray<T>& l)\n{\n    if (JSON_UNLIKELY(not j.is_array()))\n    {\n        JSON_THROW(type_error::create(302, \"type must be array, but is \" + std::string(j.type_name())));\n    }\n    l.resize(j.size());\n    std::copy(j.m_value.array->begin(), j.m_value.array->end(), std::begin(l));\n}\n\ntemplate<typename BasicJsonType>\nvoid from_json_array_impl(const BasicJsonType& j, typename BasicJsonType::array_t& arr, priority_tag<3> /*unused*/)\n{\n    arr = *j.template get_ptr<const typename BasicJsonType::array_t*>();\n}\n\ntemplate <typename BasicJsonType, typename T, std::size_t N>\nauto from_json_array_impl(const BasicJsonType& j, std::array<T, N>& arr,\n                          priority_tag<2> /*unused*/)\n-> decltype(j.template get<T>(), void())\n{\n    for (std::size_t i = 0; i < N; ++i)\n    {\n        arr[i] = j.at(i).template get<T>();\n    }\n}\n\ntemplate<typename BasicJsonType, typename ConstructibleArrayType>\nauto from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, priority_tag<1> /*unused*/)\n-> decltype(\n    arr.reserve(std::declval<typename ConstructibleArrayType::size_type>()),\n    j.template get<typename ConstructibleArrayType::value_type>(),\n    void())\n{\n    using std::end;\n\n    arr.reserve(j.size());\n    std::transform(j.begin(), j.end(),\n                   std::inserter(arr, end(arr)), [](const BasicJsonType & i)\n    {\n        // get<BasicJsonType>() returns *this, this won't call a from_json\n        // method when value_type is BasicJsonType\n        return i.template get<typename ConstructibleArrayType::value_type>();\n    });\n}\n\ntemplate <typename BasicJsonType, typename ConstructibleArrayType>\nvoid from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr,\n                          priority_tag<0> /*unused*/)\n{\n    using std::end;\n\n    std::transform(\n        j.begin(), j.end(), std::inserter(arr, end(arr)),\n        [](const BasicJsonType & i)\n    {\n        // get<BasicJsonType>() returns *this, this won't call a from_json\n        // method when value_type is BasicJsonType\n        return i.template get<typename ConstructibleArrayType::value_type>();\n    });\n}\n\ntemplate <typename BasicJsonType, typename ConstructibleArrayType,\n          enable_if_t <\n              is_constructible_array_type<BasicJsonType, ConstructibleArrayType>::value and\n              not is_constructible_object_type<BasicJsonType, ConstructibleArrayType>::value and\n              not is_constructible_string_type<BasicJsonType, ConstructibleArrayType>::value and\n              not is_basic_json<ConstructibleArrayType>::value,\n              int > = 0 >\n\nauto from_json(const BasicJsonType& j, ConstructibleArrayType& arr)\n-> decltype(from_json_array_impl(j, arr, priority_tag<3> {}),\nj.template get<typename ConstructibleArrayType::value_type>(),\nvoid())\n{\n    if (JSON_UNLIKELY(not j.is_array()))\n    {\n        JSON_THROW(type_error::create(302, \"type must be array, but is \" +\n                                      std::string(j.type_name())));\n    }\n\n    from_json_array_impl(j, arr, priority_tag<3> {});\n}\n\ntemplate<typename BasicJsonType, typename ConstructibleObjectType,\n         enable_if_t<is_constructible_object_type<BasicJsonType, ConstructibleObjectType>::value, int> = 0>\nvoid from_json(const BasicJsonType& j, ConstructibleObjectType& obj)\n{\n    if (JSON_UNLIKELY(not j.is_object()))\n    {\n        JSON_THROW(type_error::create(302, \"type must be object, but is \" + std::string(j.type_name())));\n    }\n\n    auto inner_object = j.template get_ptr<const typename BasicJsonType::object_t*>();\n    using value_type = typename ConstructibleObjectType::value_type;\n    std::transform(\n        inner_object->begin(), inner_object->end(),\n        std::inserter(obj, obj.begin()),\n        [](typename BasicJsonType::object_t::value_type const & p)\n    {\n        return value_type(p.first, p.second.template get<typename ConstructibleObjectType::mapped_type>());\n    });\n}\n\n// overload for arithmetic types, not chosen for basic_json template arguments\n// (BooleanType, etc..); note: Is it really necessary to provide explicit\n// overloads for boolean_t etc. in case of a custom BooleanType which is not\n// an arithmetic type?\ntemplate<typename BasicJsonType, typename ArithmeticType,\n         enable_if_t <\n             std::is_arithmetic<ArithmeticType>::value and\n             not std::is_same<ArithmeticType, typename BasicJsonType::number_unsigned_t>::value and\n             not std::is_same<ArithmeticType, typename BasicJsonType::number_integer_t>::value and\n             not std::is_same<ArithmeticType, typename BasicJsonType::number_float_t>::value and\n             not std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value,\n             int> = 0>\nvoid from_json(const BasicJsonType& j, ArithmeticType& val)\n{\n    switch (static_cast<value_t>(j))\n    {\n        case value_t::number_unsigned:\n        {\n            val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_unsigned_t*>());\n            break;\n        }\n        case value_t::number_integer:\n        {\n            val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_integer_t*>());\n            break;\n        }\n        case value_t::number_float:\n        {\n            val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_float_t*>());\n            break;\n        }\n        case value_t::boolean:\n        {\n            val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::boolean_t*>());\n            break;\n        }\n\n        default:\n            JSON_THROW(type_error::create(302, \"type must be number, but is \" + std::string(j.type_name())));\n    }\n}\n\ntemplate<typename BasicJsonType, typename A1, typename A2>\nvoid from_json(const BasicJsonType& j, std::pair<A1, A2>& p)\n{\n    p = {j.at(0).template get<A1>(), j.at(1).template get<A2>()};\n}\n\ntemplate<typename BasicJsonType, typename Tuple, std::size_t... Idx>\nvoid from_json_tuple_impl(const BasicJsonType& j, Tuple& t, index_sequence<Idx...> /*unused*/)\n{\n    t = std::make_tuple(j.at(Idx).template get<typename std::tuple_element<Idx, Tuple>::type>()...);\n}\n\ntemplate<typename BasicJsonType, typename... Args>\nvoid from_json(const BasicJsonType& j, std::tuple<Args...>& t)\n{\n    from_json_tuple_impl(j, t, index_sequence_for<Args...> {});\n}\n\ntemplate <typename BasicJsonType, typename Key, typename Value, typename Compare, typename Allocator,\n          typename = enable_if_t<not std::is_constructible<\n                                     typename BasicJsonType::string_t, Key>::value>>\nvoid from_json(const BasicJsonType& j, std::map<Key, Value, Compare, Allocator>& m)\n{\n    if (JSON_UNLIKELY(not j.is_array()))\n    {\n        JSON_THROW(type_error::create(302, \"type must be array, but is \" + std::string(j.type_name())));\n    }\n    for (const auto& p : j)\n    {\n        if (JSON_UNLIKELY(not p.is_array()))\n        {\n            JSON_THROW(type_error::create(302, \"type must be array, but is \" + std::string(p.type_name())));\n        }\n        m.emplace(p.at(0).template get<Key>(), p.at(1).template get<Value>());\n    }\n}\n\ntemplate <typename BasicJsonType, typename Key, typename Value, typename Hash, typename KeyEqual, typename Allocator,\n          typename = enable_if_t<not std::is_constructible<\n                                     typename BasicJsonType::string_t, Key>::value>>\nvoid from_json(const BasicJsonType& j, std::unordered_map<Key, Value, Hash, KeyEqual, Allocator>& m)\n{\n    if (JSON_UNLIKELY(not j.is_array()))\n    {\n        JSON_THROW(type_error::create(302, \"type must be array, but is \" + std::string(j.type_name())));\n    }\n    for (const auto& p : j)\n    {\n        if (JSON_UNLIKELY(not p.is_array()))\n        {\n            JSON_THROW(type_error::create(302, \"type must be array, but is \" + std::string(p.type_name())));\n        }\n        m.emplace(p.at(0).template get<Key>(), p.at(1).template get<Value>());\n    }\n}\n\nstruct from_json_fn\n{\n    template<typename BasicJsonType, typename T>\n    auto operator()(const BasicJsonType& j, T& val) const\n    noexcept(noexcept(from_json(j, val)))\n    -> decltype(from_json(j, val), void())\n    {\n        return from_json(j, val);\n    }\n};\n}  // namespace detail\n\n/// namespace to hold default `from_json` function\n/// to see why this is required:\n/// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html\nnamespace\n{\nconstexpr const auto& from_json = detail::static_const<detail::from_json_fn>::value;\n} // namespace\n}  // namespace nlohmann\n"
  },
  {
    "path": "nlohmann_json/include/nlohmann/detail/conversions/to_chars.hpp",
    "content": "#pragma once\n\n#include <cassert> // assert\n#include <ciso646> // or, and, not\n#include <cmath>   // signbit, isfinite\n#include <cstdint> // intN_t, uintN_t\n#include <cstring> // memcpy, memmove\n\nnamespace nlohmann\n{\nnamespace detail\n{\n\n/*!\n@brief implements the Grisu2 algorithm for binary to decimal floating-point\nconversion.\n\nThis implementation is a slightly modified version of the reference\nimplementation which may be obtained from\nhttp://florian.loitsch.com/publications (bench.tar.gz).\n\nThe code is distributed under the MIT license, Copyright (c) 2009 Florian Loitsch.\n\nFor a detailed description of the algorithm see:\n\n[1] Loitsch, \"Printing Floating-Point Numbers Quickly and Accurately with\n    Integers\", Proceedings of the ACM SIGPLAN 2010 Conference on Programming\n    Language Design and Implementation, PLDI 2010\n[2] Burger, Dybvig, \"Printing Floating-Point Numbers Quickly and Accurately\",\n    Proceedings of the ACM SIGPLAN 1996 Conference on Programming Language\n    Design and Implementation, PLDI 1996\n*/\nnamespace dtoa_impl\n{\n\ntemplate <typename Target, typename Source>\nTarget reinterpret_bits(const Source source)\n{\n    static_assert(sizeof(Target) == sizeof(Source), \"size mismatch\");\n\n    Target target;\n    std::memcpy(&target, &source, sizeof(Source));\n    return target;\n}\n\nstruct diyfp // f * 2^e\n{\n    static constexpr int kPrecision = 64; // = q\n\n    uint64_t f = 0;\n    int e = 0;\n\n    constexpr diyfp(uint64_t f_, int e_) noexcept : f(f_), e(e_) {}\n\n    /*!\n    @brief returns x - y\n    @pre x.e == y.e and x.f >= y.f\n    */\n    static diyfp sub(const diyfp& x, const diyfp& y) noexcept\n    {\n        assert(x.e == y.e);\n        assert(x.f >= y.f);\n\n        return {x.f - y.f, x.e};\n    }\n\n    /*!\n    @brief returns x * y\n    @note The result is rounded. (Only the upper q bits are returned.)\n    */\n    static diyfp mul(const diyfp& x, const diyfp& y) noexcept\n    {\n        static_assert(kPrecision == 64, \"internal error\");\n\n        // Computes:\n        //  f = round((x.f * y.f) / 2^q)\n        //  e = x.e + y.e + q\n\n        // Emulate the 64-bit * 64-bit multiplication:\n        //\n        // p = u * v\n        //   = (u_lo + 2^32 u_hi) (v_lo + 2^32 v_hi)\n        //   = (u_lo v_lo         ) + 2^32 ((u_lo v_hi         ) + (u_hi v_lo         )) + 2^64 (u_hi v_hi         )\n        //   = (p0                ) + 2^32 ((p1                ) + (p2                )) + 2^64 (p3                )\n        //   = (p0_lo + 2^32 p0_hi) + 2^32 ((p1_lo + 2^32 p1_hi) + (p2_lo + 2^32 p2_hi)) + 2^64 (p3                )\n        //   = (p0_lo             ) + 2^32 (p0_hi + p1_lo + p2_lo                      ) + 2^64 (p1_hi + p2_hi + p3)\n        //   = (p0_lo             ) + 2^32 (Q                                          ) + 2^64 (H                 )\n        //   = (p0_lo             ) + 2^32 (Q_lo + 2^32 Q_hi                           ) + 2^64 (H                 )\n        //\n        // (Since Q might be larger than 2^32 - 1)\n        //\n        //   = (p0_lo + 2^32 Q_lo) + 2^64 (Q_hi + H)\n        //\n        // (Q_hi + H does not overflow a 64-bit int)\n        //\n        //   = p_lo + 2^64 p_hi\n\n        const uint64_t u_lo = x.f & 0xFFFFFFFF;\n        const uint64_t u_hi = x.f >> 32;\n        const uint64_t v_lo = y.f & 0xFFFFFFFF;\n        const uint64_t v_hi = y.f >> 32;\n\n        const uint64_t p0 = u_lo * v_lo;\n        const uint64_t p1 = u_lo * v_hi;\n        const uint64_t p2 = u_hi * v_lo;\n        const uint64_t p3 = u_hi * v_hi;\n\n        const uint64_t p0_hi = p0 >> 32;\n        const uint64_t p1_lo = p1 & 0xFFFFFFFF;\n        const uint64_t p1_hi = p1 >> 32;\n        const uint64_t p2_lo = p2 & 0xFFFFFFFF;\n        const uint64_t p2_hi = p2 >> 32;\n\n        uint64_t Q = p0_hi + p1_lo + p2_lo;\n\n        // The full product might now be computed as\n        //\n        // p_hi = p3 + p2_hi + p1_hi + (Q >> 32)\n        // p_lo = p0_lo + (Q << 32)\n        //\n        // But in this particular case here, the full p_lo is not required.\n        // Effectively we only need to add the highest bit in p_lo to p_hi (and\n        // Q_hi + 1 does not overflow).\n\n        Q += uint64_t{1} << (64 - 32 - 1); // round, ties up\n\n        const uint64_t h = p3 + p2_hi + p1_hi + (Q >> 32);\n\n        return {h, x.e + y.e + 64};\n    }\n\n    /*!\n    @brief normalize x such that the significand is >= 2^(q-1)\n    @pre x.f != 0\n    */\n    static diyfp normalize(diyfp x) noexcept\n    {\n        assert(x.f != 0);\n\n        while ((x.f >> 63) == 0)\n        {\n            x.f <<= 1;\n            x.e--;\n        }\n\n        return x;\n    }\n\n    /*!\n    @brief normalize x such that the result has the exponent E\n    @pre e >= x.e and the upper e - x.e bits of x.f must be zero.\n    */\n    static diyfp normalize_to(const diyfp& x, const int target_exponent) noexcept\n    {\n        const int delta = x.e - target_exponent;\n\n        assert(delta >= 0);\n        assert(((x.f << delta) >> delta) == x.f);\n\n        return {x.f << delta, target_exponent};\n    }\n};\n\nstruct boundaries\n{\n    diyfp w;\n    diyfp minus;\n    diyfp plus;\n};\n\n/*!\nCompute the (normalized) diyfp representing the input number 'value' and its\nboundaries.\n\n@pre value must be finite and positive\n*/\ntemplate <typename FloatType>\nboundaries compute_boundaries(FloatType value)\n{\n    assert(std::isfinite(value));\n    assert(value > 0);\n\n    // Convert the IEEE representation into a diyfp.\n    //\n    // If v is denormal:\n    //      value = 0.F * 2^(1 - bias) = (          F) * 2^(1 - bias - (p-1))\n    // If v is normalized:\n    //      value = 1.F * 2^(E - bias) = (2^(p-1) + F) * 2^(E - bias - (p-1))\n\n    static_assert(std::numeric_limits<FloatType>::is_iec559,\n                  \"internal error: dtoa_short requires an IEEE-754 floating-point implementation\");\n\n    constexpr int      kPrecision = std::numeric_limits<FloatType>::digits; // = p (includes the hidden bit)\n    constexpr int      kBias      = std::numeric_limits<FloatType>::max_exponent - 1 + (kPrecision - 1);\n    constexpr int      kMinExp    = 1 - kBias;\n    constexpr uint64_t kHiddenBit = uint64_t{1} << (kPrecision - 1); // = 2^(p-1)\n\n    using bits_type = typename std::conditional< kPrecision == 24, uint32_t, uint64_t >::type;\n\n    const uint64_t bits = reinterpret_bits<bits_type>(value);\n    const uint64_t E = bits >> (kPrecision - 1);\n    const uint64_t F = bits & (kHiddenBit - 1);\n\n    const bool is_denormal = (E == 0);\n    const diyfp v = is_denormal\n                    ? diyfp(F, kMinExp)\n                    : diyfp(F + kHiddenBit, static_cast<int>(E) - kBias);\n\n    // Compute the boundaries m- and m+ of the floating-point value\n    // v = f * 2^e.\n    //\n    // Determine v- and v+, the floating-point predecessor and successor if v,\n    // respectively.\n    //\n    //      v- = v - 2^e        if f != 2^(p-1) or e == e_min                (A)\n    //         = v - 2^(e-1)    if f == 2^(p-1) and e > e_min                (B)\n    //\n    //      v+ = v + 2^e\n    //\n    // Let m- = (v- + v) / 2 and m+ = (v + v+) / 2. All real numbers _strictly_\n    // between m- and m+ round to v, regardless of how the input rounding\n    // algorithm breaks ties.\n    //\n    //      ---+-------------+-------------+-------------+-------------+---  (A)\n    //         v-            m-            v             m+            v+\n    //\n    //      -----------------+------+------+-------------+-------------+---  (B)\n    //                       v-     m-     v             m+            v+\n\n    const bool lower_boundary_is_closer = (F == 0 and E > 1);\n    const diyfp m_plus = diyfp(2 * v.f + 1, v.e - 1);\n    const diyfp m_minus = lower_boundary_is_closer\n                          ? diyfp(4 * v.f - 1, v.e - 2)  // (B)\n                          : diyfp(2 * v.f - 1, v.e - 1); // (A)\n\n    // Determine the normalized w+ = m+.\n    const diyfp w_plus = diyfp::normalize(m_plus);\n\n    // Determine w- = m- such that e_(w-) = e_(w+).\n    const diyfp w_minus = diyfp::normalize_to(m_minus, w_plus.e);\n\n    return {diyfp::normalize(v), w_minus, w_plus};\n}\n\n// Given normalized diyfp w, Grisu needs to find a (normalized) cached\n// power-of-ten c, such that the exponent of the product c * w = f * 2^e lies\n// within a certain range [alpha, gamma] (Definition 3.2 from [1])\n//\n//      alpha <= e = e_c + e_w + q <= gamma\n//\n// or\n//\n//      f_c * f_w * 2^alpha <= f_c 2^(e_c) * f_w 2^(e_w) * 2^q\n//                          <= f_c * f_w * 2^gamma\n//\n// Since c and w are normalized, i.e. 2^(q-1) <= f < 2^q, this implies\n//\n//      2^(q-1) * 2^(q-1) * 2^alpha <= c * w * 2^q < 2^q * 2^q * 2^gamma\n//\n// or\n//\n//      2^(q - 2 + alpha) <= c * w < 2^(q + gamma)\n//\n// The choice of (alpha,gamma) determines the size of the table and the form of\n// the digit generation procedure. Using (alpha,gamma)=(-60,-32) works out well\n// in practice:\n//\n// The idea is to cut the number c * w = f * 2^e into two parts, which can be\n// processed independently: An integral part p1, and a fractional part p2:\n//\n//      f * 2^e = ( (f div 2^-e) * 2^-e + (f mod 2^-e) ) * 2^e\n//              = (f div 2^-e) + (f mod 2^-e) * 2^e\n//              = p1 + p2 * 2^e\n//\n// The conversion of p1 into decimal form requires a series of divisions and\n// modulos by (a power of) 10. These operations are faster for 32-bit than for\n// 64-bit integers, so p1 should ideally fit into a 32-bit integer. This can be\n// achieved by choosing\n//\n//      -e >= 32   or   e <= -32 := gamma\n//\n// In order to convert the fractional part\n//\n//      p2 * 2^e = p2 / 2^-e = d[-1] / 10^1 + d[-2] / 10^2 + ...\n//\n// into decimal form, the fraction is repeatedly multiplied by 10 and the digits\n// d[-i] are extracted in order:\n//\n//      (10 * p2) div 2^-e = d[-1]\n//      (10 * p2) mod 2^-e = d[-2] / 10^1 + ...\n//\n// The multiplication by 10 must not overflow. It is sufficient to choose\n//\n//      10 * p2 < 16 * p2 = 2^4 * p2 <= 2^64.\n//\n// Since p2 = f mod 2^-e < 2^-e,\n//\n//      -e <= 60   or   e >= -60 := alpha\n\nconstexpr int kAlpha = -60;\nconstexpr int kGamma = -32;\n\nstruct cached_power // c = f * 2^e ~= 10^k\n{\n    uint64_t f;\n    int e;\n    int k;\n};\n\n/*!\nFor a normalized diyfp w = f * 2^e, this function returns a (normalized) cached\npower-of-ten c = f_c * 2^e_c, such that the exponent of the product w * c\nsatisfies (Definition 3.2 from [1])\n\n     alpha <= e_c + e + q <= gamma.\n*/\ninline cached_power get_cached_power_for_binary_exponent(int e)\n{\n    // Now\n    //\n    //      alpha <= e_c + e + q <= gamma                                    (1)\n    //      ==> f_c * 2^alpha <= c * 2^e * 2^q\n    //\n    // and since the c's are normalized, 2^(q-1) <= f_c,\n    //\n    //      ==> 2^(q - 1 + alpha) <= c * 2^(e + q)\n    //      ==> 2^(alpha - e - 1) <= c\n    //\n    // If c were an exakt power of ten, i.e. c = 10^k, one may determine k as\n    //\n    //      k = ceil( log_10( 2^(alpha - e - 1) ) )\n    //        = ceil( (alpha - e - 1) * log_10(2) )\n    //\n    // From the paper:\n    // \"In theory the result of the procedure could be wrong since c is rounded,\n    //  and the computation itself is approximated [...]. In practice, however,\n    //  this simple function is sufficient.\"\n    //\n    // For IEEE double precision floating-point numbers converted into\n    // normalized diyfp's w = f * 2^e, with q = 64,\n    //\n    //      e >= -1022      (min IEEE exponent)\n    //           -52        (p - 1)\n    //           -52        (p - 1, possibly normalize denormal IEEE numbers)\n    //           -11        (normalize the diyfp)\n    //         = -1137\n    //\n    // and\n    //\n    //      e <= +1023      (max IEEE exponent)\n    //           -52        (p - 1)\n    //           -11        (normalize the diyfp)\n    //         = 960\n    //\n    // This binary exponent range [-1137,960] results in a decimal exponent\n    // range [-307,324]. One does not need to store a cached power for each\n    // k in this range. For each such k it suffices to find a cached power\n    // such that the exponent of the product lies in [alpha,gamma].\n    // This implies that the difference of the decimal exponents of adjacent\n    // table entries must be less than or equal to\n    //\n    //      floor( (gamma - alpha) * log_10(2) ) = 8.\n    //\n    // (A smaller distance gamma-alpha would require a larger table.)\n\n    // NB:\n    // Actually this function returns c, such that -60 <= e_c + e + 64 <= -34.\n\n    constexpr int kCachedPowersSize = 79;\n    constexpr int kCachedPowersMinDecExp = -300;\n    constexpr int kCachedPowersDecStep = 8;\n\n    static constexpr cached_power kCachedPowers[] =\n    {\n        { 0xAB70FE17C79AC6CA, -1060, -300 },\n        { 0xFF77B1FCBEBCDC4F, -1034, -292 },\n        { 0xBE5691EF416BD60C, -1007, -284 },\n        { 0x8DD01FAD907FFC3C,  -980, -276 },\n        { 0xD3515C2831559A83,  -954, -268 },\n        { 0x9D71AC8FADA6C9B5,  -927, -260 },\n        { 0xEA9C227723EE8BCB,  -901, -252 },\n        { 0xAECC49914078536D,  -874, -244 },\n        { 0x823C12795DB6CE57,  -847, -236 },\n        { 0xC21094364DFB5637,  -821, -228 },\n        { 0x9096EA6F3848984F,  -794, -220 },\n        { 0xD77485CB25823AC7,  -768, -212 },\n        { 0xA086CFCD97BF97F4,  -741, -204 },\n        { 0xEF340A98172AACE5,  -715, -196 },\n        { 0xB23867FB2A35B28E,  -688, -188 },\n        { 0x84C8D4DFD2C63F3B,  -661, -180 },\n        { 0xC5DD44271AD3CDBA,  -635, -172 },\n        { 0x936B9FCEBB25C996,  -608, -164 },\n        { 0xDBAC6C247D62A584,  -582, -156 },\n        { 0xA3AB66580D5FDAF6,  -555, -148 },\n        { 0xF3E2F893DEC3F126,  -529, -140 },\n        { 0xB5B5ADA8AAFF80B8,  -502, -132 },\n        { 0x87625F056C7C4A8B,  -475, -124 },\n        { 0xC9BCFF6034C13053,  -449, -116 },\n        { 0x964E858C91BA2655,  -422, -108 },\n        { 0xDFF9772470297EBD,  -396, -100 },\n        { 0xA6DFBD9FB8E5B88F,  -369,  -92 },\n        { 0xF8A95FCF88747D94,  -343,  -84 },\n        { 0xB94470938FA89BCF,  -316,  -76 },\n        { 0x8A08F0F8BF0F156B,  -289,  -68 },\n        { 0xCDB02555653131B6,  -263,  -60 },\n        { 0x993FE2C6D07B7FAC,  -236,  -52 },\n        { 0xE45C10C42A2B3B06,  -210,  -44 },\n        { 0xAA242499697392D3,  -183,  -36 },\n        { 0xFD87B5F28300CA0E,  -157,  -28 },\n        { 0xBCE5086492111AEB,  -130,  -20 },\n        { 0x8CBCCC096F5088CC,  -103,  -12 },\n        { 0xD1B71758E219652C,   -77,   -4 },\n        { 0x9C40000000000000,   -50,    4 },\n        { 0xE8D4A51000000000,   -24,   12 },\n        { 0xAD78EBC5AC620000,     3,   20 },\n        { 0x813F3978F8940984,    30,   28 },\n        { 0xC097CE7BC90715B3,    56,   36 },\n        { 0x8F7E32CE7BEA5C70,    83,   44 },\n        { 0xD5D238A4ABE98068,   109,   52 },\n        { 0x9F4F2726179A2245,   136,   60 },\n        { 0xED63A231D4C4FB27,   162,   68 },\n        { 0xB0DE65388CC8ADA8,   189,   76 },\n        { 0x83C7088E1AAB65DB,   216,   84 },\n        { 0xC45D1DF942711D9A,   242,   92 },\n        { 0x924D692CA61BE758,   269,  100 },\n        { 0xDA01EE641A708DEA,   295,  108 },\n        { 0xA26DA3999AEF774A,   322,  116 },\n        { 0xF209787BB47D6B85,   348,  124 },\n        { 0xB454E4A179DD1877,   375,  132 },\n        { 0x865B86925B9BC5C2,   402,  140 },\n        { 0xC83553C5C8965D3D,   428,  148 },\n        { 0x952AB45CFA97A0B3,   455,  156 },\n        { 0xDE469FBD99A05FE3,   481,  164 },\n        { 0xA59BC234DB398C25,   508,  172 },\n        { 0xF6C69A72A3989F5C,   534,  180 },\n        { 0xB7DCBF5354E9BECE,   561,  188 },\n        { 0x88FCF317F22241E2,   588,  196 },\n        { 0xCC20CE9BD35C78A5,   614,  204 },\n        { 0x98165AF37B2153DF,   641,  212 },\n        { 0xE2A0B5DC971F303A,   667,  220 },\n        { 0xA8D9D1535CE3B396,   694,  228 },\n        { 0xFB9B7CD9A4A7443C,   720,  236 },\n        { 0xBB764C4CA7A44410,   747,  244 },\n        { 0x8BAB8EEFB6409C1A,   774,  252 },\n        { 0xD01FEF10A657842C,   800,  260 },\n        { 0x9B10A4E5E9913129,   827,  268 },\n        { 0xE7109BFBA19C0C9D,   853,  276 },\n        { 0xAC2820D9623BF429,   880,  284 },\n        { 0x80444B5E7AA7CF85,   907,  292 },\n        { 0xBF21E44003ACDD2D,   933,  300 },\n        { 0x8E679C2F5E44FF8F,   960,  308 },\n        { 0xD433179D9C8CB841,   986,  316 },\n        { 0x9E19DB92B4E31BA9,  1013,  324 },\n    };\n\n    // This computation gives exactly the same results for k as\n    //      k = ceil((kAlpha - e - 1) * 0.30102999566398114)\n    // for |e| <= 1500, but doesn't require floating-point operations.\n    // NB: log_10(2) ~= 78913 / 2^18\n    assert(e >= -1500);\n    assert(e <=  1500);\n    const int f = kAlpha - e - 1;\n    const int k = (f * 78913) / (1 << 18) + static_cast<int>(f > 0);\n\n    const int index = (-kCachedPowersMinDecExp + k + (kCachedPowersDecStep - 1)) / kCachedPowersDecStep;\n    assert(index >= 0);\n    assert(index < kCachedPowersSize);\n    static_cast<void>(kCachedPowersSize); // Fix warning.\n\n    const cached_power cached = kCachedPowers[index];\n    assert(kAlpha <= cached.e + e + 64);\n    assert(kGamma >= cached.e + e + 64);\n\n    return cached;\n}\n\n/*!\nFor n != 0, returns k, such that pow10 := 10^(k-1) <= n < 10^k.\nFor n == 0, returns 1 and sets pow10 := 1.\n*/\ninline int find_largest_pow10(const uint32_t n, uint32_t& pow10)\n{\n    // LCOV_EXCL_START\n    if (n >= 1000000000)\n    {\n        pow10 = 1000000000;\n        return 10;\n    }\n    // LCOV_EXCL_STOP\n    else if (n >= 100000000)\n    {\n        pow10 = 100000000;\n        return  9;\n    }\n    else if (n >= 10000000)\n    {\n        pow10 = 10000000;\n        return  8;\n    }\n    else if (n >= 1000000)\n    {\n        pow10 = 1000000;\n        return  7;\n    }\n    else if (n >= 100000)\n    {\n        pow10 = 100000;\n        return  6;\n    }\n    else if (n >= 10000)\n    {\n        pow10 = 10000;\n        return  5;\n    }\n    else if (n >= 1000)\n    {\n        pow10 = 1000;\n        return  4;\n    }\n    else if (n >= 100)\n    {\n        pow10 = 100;\n        return  3;\n    }\n    else if (n >= 10)\n    {\n        pow10 = 10;\n        return  2;\n    }\n    else\n    {\n        pow10 = 1;\n        return 1;\n    }\n}\n\ninline void grisu2_round(char* buf, int len, uint64_t dist, uint64_t delta,\n                         uint64_t rest, uint64_t ten_k)\n{\n    assert(len >= 1);\n    assert(dist <= delta);\n    assert(rest <= delta);\n    assert(ten_k > 0);\n\n    //               <--------------------------- delta ---->\n    //                                  <---- dist --------->\n    // --------------[------------------+-------------------]--------------\n    //               M-                 w                   M+\n    //\n    //                                  ten_k\n    //                                <------>\n    //                                       <---- rest ---->\n    // --------------[------------------+----+--------------]--------------\n    //                                  w    V\n    //                                       = buf * 10^k\n    //\n    // ten_k represents a unit-in-the-last-place in the decimal representation\n    // stored in buf.\n    // Decrement buf by ten_k while this takes buf closer to w.\n\n    // The tests are written in this order to avoid overflow in unsigned\n    // integer arithmetic.\n\n    while (rest < dist\n            and delta - rest >= ten_k\n            and (rest + ten_k < dist or dist - rest > rest + ten_k - dist))\n    {\n        assert(buf[len - 1] != '0');\n        buf[len - 1]--;\n        rest += ten_k;\n    }\n}\n\n/*!\nGenerates V = buffer * 10^decimal_exponent, such that M- <= V <= M+.\nM- and M+ must be normalized and share the same exponent -60 <= e <= -32.\n*/\ninline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent,\n                             diyfp M_minus, diyfp w, diyfp M_plus)\n{\n    static_assert(kAlpha >= -60, \"internal error\");\n    static_assert(kGamma <= -32, \"internal error\");\n\n    // Generates the digits (and the exponent) of a decimal floating-point\n    // number V = buffer * 10^decimal_exponent in the range [M-, M+]. The diyfp's\n    // w, M- and M+ share the same exponent e, which satisfies alpha <= e <= gamma.\n    //\n    //               <--------------------------- delta ---->\n    //                                  <---- dist --------->\n    // --------------[------------------+-------------------]--------------\n    //               M-                 w                   M+\n    //\n    // Grisu2 generates the digits of M+ from left to right and stops as soon as\n    // V is in [M-,M+].\n\n    assert(M_plus.e >= kAlpha);\n    assert(M_plus.e <= kGamma);\n\n    uint64_t delta = diyfp::sub(M_plus, M_minus).f; // (significand of (M+ - M-), implicit exponent is e)\n    uint64_t dist  = diyfp::sub(M_plus, w      ).f; // (significand of (M+ - w ), implicit exponent is e)\n\n    // Split M+ = f * 2^e into two parts p1 and p2 (note: e < 0):\n    //\n    //      M+ = f * 2^e\n    //         = ((f div 2^-e) * 2^-e + (f mod 2^-e)) * 2^e\n    //         = ((p1        ) * 2^-e + (p2        )) * 2^e\n    //         = p1 + p2 * 2^e\n\n    const diyfp one(uint64_t{1} << -M_plus.e, M_plus.e);\n\n    auto p1 = static_cast<uint32_t>(M_plus.f >> -one.e); // p1 = f div 2^-e (Since -e >= 32, p1 fits into a 32-bit int.)\n    uint64_t p2 = M_plus.f & (one.f - 1);                    // p2 = f mod 2^-e\n\n    // 1)\n    //\n    // Generate the digits of the integral part p1 = d[n-1]...d[1]d[0]\n\n    assert(p1 > 0);\n\n    uint32_t pow10;\n    const int k = find_largest_pow10(p1, pow10);\n\n    //      10^(k-1) <= p1 < 10^k, pow10 = 10^(k-1)\n    //\n    //      p1 = (p1 div 10^(k-1)) * 10^(k-1) + (p1 mod 10^(k-1))\n    //         = (d[k-1]         ) * 10^(k-1) + (p1 mod 10^(k-1))\n    //\n    //      M+ = p1                                             + p2 * 2^e\n    //         = d[k-1] * 10^(k-1) + (p1 mod 10^(k-1))          + p2 * 2^e\n    //         = d[k-1] * 10^(k-1) + ((p1 mod 10^(k-1)) * 2^-e + p2) * 2^e\n    //         = d[k-1] * 10^(k-1) + (                         rest) * 2^e\n    //\n    // Now generate the digits d[n] of p1 from left to right (n = k-1,...,0)\n    //\n    //      p1 = d[k-1]...d[n] * 10^n + d[n-1]...d[0]\n    //\n    // but stop as soon as\n    //\n    //      rest * 2^e = (d[n-1]...d[0] * 2^-e + p2) * 2^e <= delta * 2^e\n\n    int n = k;\n    while (n > 0)\n    {\n        // Invariants:\n        //      M+ = buffer * 10^n + (p1 + p2 * 2^e)    (buffer = 0 for n = k)\n        //      pow10 = 10^(n-1) <= p1 < 10^n\n        //\n        const uint32_t d = p1 / pow10;  // d = p1 div 10^(n-1)\n        const uint32_t r = p1 % pow10;  // r = p1 mod 10^(n-1)\n        //\n        //      M+ = buffer * 10^n + (d * 10^(n-1) + r) + p2 * 2^e\n        //         = (buffer * 10 + d) * 10^(n-1) + (r + p2 * 2^e)\n        //\n        assert(d <= 9);\n        buffer[length++] = static_cast<char>('0' + d); // buffer := buffer * 10 + d\n        //\n        //      M+ = buffer * 10^(n-1) + (r + p2 * 2^e)\n        //\n        p1 = r;\n        n--;\n        //\n        //      M+ = buffer * 10^n + (p1 + p2 * 2^e)\n        //      pow10 = 10^n\n        //\n\n        // Now check if enough digits have been generated.\n        // Compute\n        //\n        //      p1 + p2 * 2^e = (p1 * 2^-e + p2) * 2^e = rest * 2^e\n        //\n        // Note:\n        // Since rest and delta share the same exponent e, it suffices to\n        // compare the significands.\n        const uint64_t rest = (uint64_t{p1} << -one.e) + p2;\n        if (rest <= delta)\n        {\n            // V = buffer * 10^n, with M- <= V <= M+.\n\n            decimal_exponent += n;\n\n            // We may now just stop. But instead look if the buffer could be\n            // decremented to bring V closer to w.\n            //\n            // pow10 = 10^n is now 1 ulp in the decimal representation V.\n            // The rounding procedure works with diyfp's with an implicit\n            // exponent of e.\n            //\n            //      10^n = (10^n * 2^-e) * 2^e = ulp * 2^e\n            //\n            const uint64_t ten_n = uint64_t{pow10} << -one.e;\n            grisu2_round(buffer, length, dist, delta, rest, ten_n);\n\n            return;\n        }\n\n        pow10 /= 10;\n        //\n        //      pow10 = 10^(n-1) <= p1 < 10^n\n        // Invariants restored.\n    }\n\n    // 2)\n    //\n    // The digits of the integral part have been generated:\n    //\n    //      M+ = d[k-1]...d[1]d[0] + p2 * 2^e\n    //         = buffer            + p2 * 2^e\n    //\n    // Now generate the digits of the fractional part p2 * 2^e.\n    //\n    // Note:\n    // No decimal point is generated: the exponent is adjusted instead.\n    //\n    // p2 actually represents the fraction\n    //\n    //      p2 * 2^e\n    //          = p2 / 2^-e\n    //          = d[-1] / 10^1 + d[-2] / 10^2 + ...\n    //\n    // Now generate the digits d[-m] of p1 from left to right (m = 1,2,...)\n    //\n    //      p2 * 2^e = d[-1]d[-2]...d[-m] * 10^-m\n    //                      + 10^-m * (d[-m-1] / 10^1 + d[-m-2] / 10^2 + ...)\n    //\n    // using\n    //\n    //      10^m * p2 = ((10^m * p2) div 2^-e) * 2^-e + ((10^m * p2) mod 2^-e)\n    //                = (                   d) * 2^-e + (                   r)\n    //\n    // or\n    //      10^m * p2 * 2^e = d + r * 2^e\n    //\n    // i.e.\n    //\n    //      M+ = buffer + p2 * 2^e\n    //         = buffer + 10^-m * (d + r * 2^e)\n    //         = (buffer * 10^m + d) * 10^-m + 10^-m * r * 2^e\n    //\n    // and stop as soon as 10^-m * r * 2^e <= delta * 2^e\n\n    assert(p2 > delta);\n\n    int m = 0;\n    for (;;)\n    {\n        // Invariant:\n        //      M+ = buffer * 10^-m + 10^-m * (d[-m-1] / 10 + d[-m-2] / 10^2 + ...) * 2^e\n        //         = buffer * 10^-m + 10^-m * (p2                                 ) * 2^e\n        //         = buffer * 10^-m + 10^-m * (1/10 * (10 * p2)                   ) * 2^e\n        //         = buffer * 10^-m + 10^-m * (1/10 * ((10*p2 div 2^-e) * 2^-e + (10*p2 mod 2^-e)) * 2^e\n        //\n        assert(p2 <= UINT64_MAX / 10);\n        p2 *= 10;\n        const uint64_t d = p2 >> -one.e;     // d = (10 * p2) div 2^-e\n        const uint64_t r = p2 & (one.f - 1); // r = (10 * p2) mod 2^-e\n        //\n        //      M+ = buffer * 10^-m + 10^-m * (1/10 * (d * 2^-e + r) * 2^e\n        //         = buffer * 10^-m + 10^-m * (1/10 * (d + r * 2^e))\n        //         = (buffer * 10 + d) * 10^(-m-1) + 10^(-m-1) * r * 2^e\n        //\n        assert(d <= 9);\n        buffer[length++] = static_cast<char>('0' + d); // buffer := buffer * 10 + d\n        //\n        //      M+ = buffer * 10^(-m-1) + 10^(-m-1) * r * 2^e\n        //\n        p2 = r;\n        m++;\n        //\n        //      M+ = buffer * 10^-m + 10^-m * p2 * 2^e\n        // Invariant restored.\n\n        // Check if enough digits have been generated.\n        //\n        //      10^-m * p2 * 2^e <= delta * 2^e\n        //              p2 * 2^e <= 10^m * delta * 2^e\n        //                    p2 <= 10^m * delta\n        delta *= 10;\n        dist  *= 10;\n        if (p2 <= delta)\n        {\n            break;\n        }\n    }\n\n    // V = buffer * 10^-m, with M- <= V <= M+.\n\n    decimal_exponent -= m;\n\n    // 1 ulp in the decimal representation is now 10^-m.\n    // Since delta and dist are now scaled by 10^m, we need to do the\n    // same with ulp in order to keep the units in sync.\n    //\n    //      10^m * 10^-m = 1 = 2^-e * 2^e = ten_m * 2^e\n    //\n    const uint64_t ten_m = one.f;\n    grisu2_round(buffer, length, dist, delta, p2, ten_m);\n\n    // By construction this algorithm generates the shortest possible decimal\n    // number (Loitsch, Theorem 6.2) which rounds back to w.\n    // For an input number of precision p, at least\n    //\n    //      N = 1 + ceil(p * log_10(2))\n    //\n    // decimal digits are sufficient to identify all binary floating-point\n    // numbers (Matula, \"In-and-Out conversions\").\n    // This implies that the algorithm does not produce more than N decimal\n    // digits.\n    //\n    //      N = 17 for p = 53 (IEEE double precision)\n    //      N = 9  for p = 24 (IEEE single precision)\n}\n\n/*!\nv = buf * 10^decimal_exponent\nlen is the length of the buffer (number of decimal digits)\nThe buffer must be large enough, i.e. >= max_digits10.\n*/\ninline void grisu2(char* buf, int& len, int& decimal_exponent,\n                   diyfp m_minus, diyfp v, diyfp m_plus)\n{\n    assert(m_plus.e == m_minus.e);\n    assert(m_plus.e == v.e);\n\n    //  --------(-----------------------+-----------------------)--------    (A)\n    //          m-                      v                       m+\n    //\n    //  --------------------(-----------+-----------------------)--------    (B)\n    //                      m-          v                       m+\n    //\n    // First scale v (and m- and m+) such that the exponent is in the range\n    // [alpha, gamma].\n\n    const cached_power cached = get_cached_power_for_binary_exponent(m_plus.e);\n\n    const diyfp c_minus_k(cached.f, cached.e); // = c ~= 10^-k\n\n    // The exponent of the products is = v.e + c_minus_k.e + q and is in the range [alpha,gamma]\n    const diyfp w       = diyfp::mul(v,       c_minus_k);\n    const diyfp w_minus = diyfp::mul(m_minus, c_minus_k);\n    const diyfp w_plus  = diyfp::mul(m_plus,  c_minus_k);\n\n    //  ----(---+---)---------------(---+---)---------------(---+---)----\n    //          w-                      w                       w+\n    //          = c*m-                  = c*v                   = c*m+\n    //\n    // diyfp::mul rounds its result and c_minus_k is approximated too. w, w- and\n    // w+ are now off by a small amount.\n    // In fact:\n    //\n    //      w - v * 10^k < 1 ulp\n    //\n    // To account for this inaccuracy, add resp. subtract 1 ulp.\n    //\n    //  --------+---[---------------(---+---)---------------]---+--------\n    //          w-  M-                  w                   M+  w+\n    //\n    // Now any number in [M-, M+] (bounds included) will round to w when input,\n    // regardless of how the input rounding algorithm breaks ties.\n    //\n    // And digit_gen generates the shortest possible such number in [M-, M+].\n    // Note that this does not mean that Grisu2 always generates the shortest\n    // possible number in the interval (m-, m+).\n    const diyfp M_minus(w_minus.f + 1, w_minus.e);\n    const diyfp M_plus (w_plus.f  - 1, w_plus.e );\n\n    decimal_exponent = -cached.k; // = -(-k) = k\n\n    grisu2_digit_gen(buf, len, decimal_exponent, M_minus, w, M_plus);\n}\n\n/*!\nv = buf * 10^decimal_exponent\nlen is the length of the buffer (number of decimal digits)\nThe buffer must be large enough, i.e. >= max_digits10.\n*/\ntemplate <typename FloatType>\nvoid grisu2(char* buf, int& len, int& decimal_exponent, FloatType value)\n{\n    static_assert(diyfp::kPrecision >= std::numeric_limits<FloatType>::digits + 3,\n                  \"internal error: not enough precision\");\n\n    assert(std::isfinite(value));\n    assert(value > 0);\n\n    // If the neighbors (and boundaries) of 'value' are always computed for double-precision\n    // numbers, all float's can be recovered using strtod (and strtof). However, the resulting\n    // decimal representations are not exactly \"short\".\n    //\n    // The documentation for 'std::to_chars' (https://en.cppreference.com/w/cpp/utility/to_chars)\n    // says \"value is converted to a string as if by std::sprintf in the default (\"C\") locale\"\n    // and since sprintf promotes float's to double's, I think this is exactly what 'std::to_chars'\n    // does.\n    // On the other hand, the documentation for 'std::to_chars' requires that \"parsing the\n    // representation using the corresponding std::from_chars function recovers value exactly\". That\n    // indicates that single precision floating-point numbers should be recovered using\n    // 'std::strtof'.\n    //\n    // NB: If the neighbors are computed for single-precision numbers, there is a single float\n    //     (7.0385307e-26f) which can't be recovered using strtod. The resulting double precision\n    //     value is off by 1 ulp.\n#if 0\n    const boundaries w = compute_boundaries(static_cast<double>(value));\n#else\n    const boundaries w = compute_boundaries(value);\n#endif\n\n    grisu2(buf, len, decimal_exponent, w.minus, w.w, w.plus);\n}\n\n/*!\n@brief appends a decimal representation of e to buf\n@return a pointer to the element following the exponent.\n@pre -1000 < e < 1000\n*/\ninline char* append_exponent(char* buf, int e)\n{\n    assert(e > -1000);\n    assert(e <  1000);\n\n    if (e < 0)\n    {\n        e = -e;\n        *buf++ = '-';\n    }\n    else\n    {\n        *buf++ = '+';\n    }\n\n    auto k = static_cast<uint32_t>(e);\n    if (k < 10)\n    {\n        // Always print at least two digits in the exponent.\n        // This is for compatibility with printf(\"%g\").\n        *buf++ = '0';\n        *buf++ = static_cast<char>('0' + k);\n    }\n    else if (k < 100)\n    {\n        *buf++ = static_cast<char>('0' + k / 10);\n        k %= 10;\n        *buf++ = static_cast<char>('0' + k);\n    }\n    else\n    {\n        *buf++ = static_cast<char>('0' + k / 100);\n        k %= 100;\n        *buf++ = static_cast<char>('0' + k / 10);\n        k %= 10;\n        *buf++ = static_cast<char>('0' + k);\n    }\n\n    return buf;\n}\n\n/*!\n@brief prettify v = buf * 10^decimal_exponent\n\nIf v is in the range [10^min_exp, 10^max_exp) it will be printed in fixed-point\nnotation. Otherwise it will be printed in exponential notation.\n\n@pre min_exp < 0\n@pre max_exp > 0\n*/\ninline char* format_buffer(char* buf, int len, int decimal_exponent,\n                           int min_exp, int max_exp)\n{\n    assert(min_exp < 0);\n    assert(max_exp > 0);\n\n    const int k = len;\n    const int n = len + decimal_exponent;\n\n    // v = buf * 10^(n-k)\n    // k is the length of the buffer (number of decimal digits)\n    // n is the position of the decimal point relative to the start of the buffer.\n\n    if (k <= n and n <= max_exp)\n    {\n        // digits[000]\n        // len <= max_exp + 2\n\n        std::memset(buf + k, '0', static_cast<size_t>(n - k));\n        // Make it look like a floating-point number (#362, #378)\n        buf[n + 0] = '.';\n        buf[n + 1] = '0';\n        return buf + (n + 2);\n    }\n\n    if (0 < n and n <= max_exp)\n    {\n        // dig.its\n        // len <= max_digits10 + 1\n\n        assert(k > n);\n\n        std::memmove(buf + (n + 1), buf + n, static_cast<size_t>(k - n));\n        buf[n] = '.';\n        return buf + (k + 1);\n    }\n\n    if (min_exp < n and n <= 0)\n    {\n        // 0.[000]digits\n        // len <= 2 + (-min_exp - 1) + max_digits10\n\n        std::memmove(buf + (2 + -n), buf, static_cast<size_t>(k));\n        buf[0] = '0';\n        buf[1] = '.';\n        std::memset(buf + 2, '0', static_cast<size_t>(-n));\n        return buf + (2 + (-n) + k);\n    }\n\n    if (k == 1)\n    {\n        // dE+123\n        // len <= 1 + 5\n\n        buf += 1;\n    }\n    else\n    {\n        // d.igitsE+123\n        // len <= max_digits10 + 1 + 5\n\n        std::memmove(buf + 2, buf + 1, static_cast<size_t>(k - 1));\n        buf[1] = '.';\n        buf += 1 + k;\n    }\n\n    *buf++ = 'e';\n    return append_exponent(buf, n - 1);\n}\n\n} // namespace dtoa_impl\n\n/*!\n@brief generates a decimal representation of the floating-point number value in [first, last).\n\nThe format of the resulting decimal representation is similar to printf's %g\nformat. Returns an iterator pointing past-the-end of the decimal representation.\n\n@note The input number must be finite, i.e. NaN's and Inf's are not supported.\n@note The buffer must be large enough.\n@note The result is NOT null-terminated.\n*/\ntemplate <typename FloatType>\nchar* to_chars(char* first, const char* last, FloatType value)\n{\n    static_cast<void>(last); // maybe unused - fix warning\n    assert(std::isfinite(value));\n\n    // Use signbit(value) instead of (value < 0) since signbit works for -0.\n    if (std::signbit(value))\n    {\n        value = -value;\n        *first++ = '-';\n    }\n\n    if (value == 0) // +-0\n    {\n        *first++ = '0';\n        // Make it look like a floating-point number (#362, #378)\n        *first++ = '.';\n        *first++ = '0';\n        return first;\n    }\n\n    assert(last - first >= std::numeric_limits<FloatType>::max_digits10);\n\n    // Compute v = buffer * 10^decimal_exponent.\n    // The decimal digits are stored in the buffer, which needs to be interpreted\n    // as an unsigned decimal integer.\n    // len is the length of the buffer, i.e. the number of decimal digits.\n    int len = 0;\n    int decimal_exponent = 0;\n    dtoa_impl::grisu2(first, len, decimal_exponent, value);\n\n    assert(len <= std::numeric_limits<FloatType>::max_digits10);\n\n    // Format the buffer like printf(\"%.*g\", prec, value)\n    constexpr int kMinExp = -4;\n    // Use digits10 here to increase compatibility with version 2.\n    constexpr int kMaxExp = std::numeric_limits<FloatType>::digits10;\n\n    assert(last - first >= kMaxExp + 2);\n    assert(last - first >= 2 + (-kMinExp - 1) + std::numeric_limits<FloatType>::max_digits10);\n    assert(last - first >= std::numeric_limits<FloatType>::max_digits10 + 6);\n\n    return dtoa_impl::format_buffer(first, len, decimal_exponent, kMinExp, kMaxExp);\n}\n\n} // namespace detail\n} // namespace nlohmann\n"
  },
  {
    "path": "nlohmann_json/include/nlohmann/detail/conversions/to_json.hpp",
    "content": "#pragma once\n\n#include <ciso646> // or, and, not\n#include <iterator> // begin, end\n#include <tuple> // tuple, get\n#include <type_traits> // is_same, is_constructible, is_floating_point, is_enum, underlying_type\n#include <utility> // move, forward, declval, pair\n#include <valarray> // valarray\n#include <vector> // vector\n\n#include <nlohmann/detail/meta/cpp_future.hpp>\n#include <nlohmann/detail/meta/type_traits.hpp>\n#include <nlohmann/detail/value_t.hpp>\n#include <nlohmann/detail/iterators/iteration_proxy.hpp>\n\nnamespace nlohmann\n{\nnamespace detail\n{\n//////////////////\n// constructors //\n//////////////////\n\ntemplate<value_t> struct external_constructor;\n\ntemplate<>\nstruct external_constructor<value_t::boolean>\n{\n    template<typename BasicJsonType>\n    static void construct(BasicJsonType& j, typename BasicJsonType::boolean_t b) noexcept\n    {\n        j.m_type = value_t::boolean;\n        j.m_value = b;\n        j.assert_invariant();\n    }\n};\n\ntemplate<>\nstruct external_constructor<value_t::string>\n{\n    template<typename BasicJsonType>\n    static void construct(BasicJsonType& j, const typename BasicJsonType::string_t& s)\n    {\n        j.m_type = value_t::string;\n        j.m_value = s;\n        j.assert_invariant();\n    }\n\n    template<typename BasicJsonType>\n    static void construct(BasicJsonType& j, typename BasicJsonType::string_t&& s)\n    {\n        j.m_type = value_t::string;\n        j.m_value = std::move(s);\n        j.assert_invariant();\n    }\n\n    template<typename BasicJsonType, typename CompatibleStringType,\n             enable_if_t<not std::is_same<CompatibleStringType, typename BasicJsonType::string_t>::value,\n                         int> = 0>\n    static void construct(BasicJsonType& j, const CompatibleStringType& str)\n    {\n        j.m_type = value_t::string;\n        j.m_value.string = j.template create<typename BasicJsonType::string_t>(str);\n        j.assert_invariant();\n    }\n};\n\ntemplate<>\nstruct external_constructor<value_t::number_float>\n{\n    template<typename BasicJsonType>\n    static void construct(BasicJsonType& j, typename BasicJsonType::number_float_t val) noexcept\n    {\n        j.m_type = value_t::number_float;\n        j.m_value = val;\n        j.assert_invariant();\n    }\n};\n\ntemplate<>\nstruct external_constructor<value_t::number_unsigned>\n{\n    template<typename BasicJsonType>\n    static void construct(BasicJsonType& j, typename BasicJsonType::number_unsigned_t val) noexcept\n    {\n        j.m_type = value_t::number_unsigned;\n        j.m_value = val;\n        j.assert_invariant();\n    }\n};\n\ntemplate<>\nstruct external_constructor<value_t::number_integer>\n{\n    template<typename BasicJsonType>\n    static void construct(BasicJsonType& j, typename BasicJsonType::number_integer_t val) noexcept\n    {\n        j.m_type = value_t::number_integer;\n        j.m_value = val;\n        j.assert_invariant();\n    }\n};\n\ntemplate<>\nstruct external_constructor<value_t::array>\n{\n    template<typename BasicJsonType>\n    static void construct(BasicJsonType& j, const typename BasicJsonType::array_t& arr)\n    {\n        j.m_type = value_t::array;\n        j.m_value = arr;\n        j.assert_invariant();\n    }\n\n    template<typename BasicJsonType>\n    static void construct(BasicJsonType& j, typename BasicJsonType::array_t&& arr)\n    {\n        j.m_type = value_t::array;\n        j.m_value = std::move(arr);\n        j.assert_invariant();\n    }\n\n    template<typename BasicJsonType, typename CompatibleArrayType,\n             enable_if_t<not std::is_same<CompatibleArrayType, typename BasicJsonType::array_t>::value,\n                         int> = 0>\n    static void construct(BasicJsonType& j, const CompatibleArrayType& arr)\n    {\n        using std::begin;\n        using std::end;\n        j.m_type = value_t::array;\n        j.m_value.array = j.template create<typename BasicJsonType::array_t>(begin(arr), end(arr));\n        j.assert_invariant();\n    }\n\n    template<typename BasicJsonType>\n    static void construct(BasicJsonType& j, const std::vector<bool>& arr)\n    {\n        j.m_type = value_t::array;\n        j.m_value = value_t::array;\n        j.m_value.array->reserve(arr.size());\n        for (const bool x : arr)\n        {\n            j.m_value.array->push_back(x);\n        }\n        j.assert_invariant();\n    }\n\n    template<typename BasicJsonType, typename T,\n             enable_if_t<std::is_convertible<T, BasicJsonType>::value, int> = 0>\n    static void construct(BasicJsonType& j, const std::valarray<T>& arr)\n    {\n        j.m_type = value_t::array;\n        j.m_value = value_t::array;\n        j.m_value.array->resize(arr.size());\n        std::copy(std::begin(arr), std::end(arr), j.m_value.array->begin());\n        j.assert_invariant();\n    }\n};\n\ntemplate<>\nstruct external_constructor<value_t::object>\n{\n    template<typename BasicJsonType>\n    static void construct(BasicJsonType& j, const typename BasicJsonType::object_t& obj)\n    {\n        j.m_type = value_t::object;\n        j.m_value = obj;\n        j.assert_invariant();\n    }\n\n    template<typename BasicJsonType>\n    static void construct(BasicJsonType& j, typename BasicJsonType::object_t&& obj)\n    {\n        j.m_type = value_t::object;\n        j.m_value = std::move(obj);\n        j.assert_invariant();\n    }\n\n    template<typename BasicJsonType, typename CompatibleObjectType,\n             enable_if_t<not std::is_same<CompatibleObjectType, typename BasicJsonType::object_t>::value, int> = 0>\n    static void construct(BasicJsonType& j, const CompatibleObjectType& obj)\n    {\n        using std::begin;\n        using std::end;\n\n        j.m_type = value_t::object;\n        j.m_value.object = j.template create<typename BasicJsonType::object_t>(begin(obj), end(obj));\n        j.assert_invariant();\n    }\n};\n\n/////////////\n// to_json //\n/////////////\n\ntemplate<typename BasicJsonType, typename T,\n         enable_if_t<std::is_same<T, typename BasicJsonType::boolean_t>::value, int> = 0>\nvoid to_json(BasicJsonType& j, T b) noexcept\n{\n    external_constructor<value_t::boolean>::construct(j, b);\n}\n\ntemplate<typename BasicJsonType, typename CompatibleString,\n         enable_if_t<std::is_constructible<typename BasicJsonType::string_t, CompatibleString>::value, int> = 0>\nvoid to_json(BasicJsonType& j, const CompatibleString& s)\n{\n    external_constructor<value_t::string>::construct(j, s);\n}\n\ntemplate<typename BasicJsonType>\nvoid to_json(BasicJsonType& j, typename BasicJsonType::string_t&& s)\n{\n    external_constructor<value_t::string>::construct(j, std::move(s));\n}\n\ntemplate<typename BasicJsonType, typename FloatType,\n         enable_if_t<std::is_floating_point<FloatType>::value, int> = 0>\nvoid to_json(BasicJsonType& j, FloatType val) noexcept\n{\n    external_constructor<value_t::number_float>::construct(j, static_cast<typename BasicJsonType::number_float_t>(val));\n}\n\ntemplate<typename BasicJsonType, typename CompatibleNumberUnsignedType,\n         enable_if_t<is_compatible_integer_type<typename BasicJsonType::number_unsigned_t, CompatibleNumberUnsignedType>::value, int> = 0>\nvoid to_json(BasicJsonType& j, CompatibleNumberUnsignedType val) noexcept\n{\n    external_constructor<value_t::number_unsigned>::construct(j, static_cast<typename BasicJsonType::number_unsigned_t>(val));\n}\n\ntemplate<typename BasicJsonType, typename CompatibleNumberIntegerType,\n         enable_if_t<is_compatible_integer_type<typename BasicJsonType::number_integer_t, CompatibleNumberIntegerType>::value, int> = 0>\nvoid to_json(BasicJsonType& j, CompatibleNumberIntegerType val) noexcept\n{\n    external_constructor<value_t::number_integer>::construct(j, static_cast<typename BasicJsonType::number_integer_t>(val));\n}\n\ntemplate<typename BasicJsonType, typename EnumType,\n         enable_if_t<std::is_enum<EnumType>::value, int> = 0>\nvoid to_json(BasicJsonType& j, EnumType e) noexcept\n{\n    using underlying_type = typename std::underlying_type<EnumType>::type;\n    external_constructor<value_t::number_integer>::construct(j, static_cast<underlying_type>(e));\n}\n\ntemplate<typename BasicJsonType>\nvoid to_json(BasicJsonType& j, const std::vector<bool>& e)\n{\n    external_constructor<value_t::array>::construct(j, e);\n}\n\ntemplate <typename BasicJsonType, typename CompatibleArrayType,\n          enable_if_t<is_compatible_array_type<BasicJsonType,\n                      CompatibleArrayType>::value and\n                      not is_compatible_object_type<\n                          BasicJsonType, CompatibleArrayType>::value and\n                      not is_compatible_string_type<BasicJsonType, CompatibleArrayType>::value and\n                      not is_basic_json<CompatibleArrayType>::value,\n                      int> = 0>\nvoid to_json(BasicJsonType& j, const CompatibleArrayType& arr)\n{\n    external_constructor<value_t::array>::construct(j, arr);\n}\n\ntemplate<typename BasicJsonType, typename T,\n         enable_if_t<std::is_convertible<T, BasicJsonType>::value, int> = 0>\nvoid to_json(BasicJsonType& j, const std::valarray<T>& arr)\n{\n    external_constructor<value_t::array>::construct(j, std::move(arr));\n}\n\ntemplate<typename BasicJsonType>\nvoid to_json(BasicJsonType& j, typename BasicJsonType::array_t&& arr)\n{\n    external_constructor<value_t::array>::construct(j, std::move(arr));\n}\n\ntemplate<typename BasicJsonType, typename CompatibleObjectType,\n         enable_if_t<is_compatible_object_type<BasicJsonType, CompatibleObjectType>::value and not is_basic_json<CompatibleObjectType>::value, int> = 0>\nvoid to_json(BasicJsonType& j, const CompatibleObjectType& obj)\n{\n    external_constructor<value_t::object>::construct(j, obj);\n}\n\ntemplate<typename BasicJsonType>\nvoid to_json(BasicJsonType& j, typename BasicJsonType::object_t&& obj)\n{\n    external_constructor<value_t::object>::construct(j, std::move(obj));\n}\n\ntemplate <\n    typename BasicJsonType, typename T, std::size_t N,\n    enable_if_t<not std::is_constructible<typename BasicJsonType::string_t,\n                const T(&)[N]>::value,\n                int> = 0 >\nvoid to_json(BasicJsonType& j, const T(&arr)[N])\n{\n    external_constructor<value_t::array>::construct(j, arr);\n}\n\ntemplate<typename BasicJsonType, typename... Args>\nvoid to_json(BasicJsonType& j, const std::pair<Args...>& p)\n{\n    j = { p.first, p.second };\n}\n\n// for https://github.com/nlohmann/json/pull/1134\ntemplate < typename BasicJsonType, typename T,\n           enable_if_t<std::is_same<T, iteration_proxy_value<typename BasicJsonType::iterator>>::value, int> = 0>\nvoid to_json(BasicJsonType& j, const T& b)\n{\n    j = { {b.key(), b.value()} };\n}\n\ntemplate<typename BasicJsonType, typename Tuple, std::size_t... Idx>\nvoid to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence<Idx...> /*unused*/)\n{\n    j = { std::get<Idx>(t)... };\n}\n\ntemplate<typename BasicJsonType, typename... Args>\nvoid to_json(BasicJsonType& j, const std::tuple<Args...>& t)\n{\n    to_json_tuple_impl(j, t, index_sequence_for<Args...> {});\n}\n\nstruct to_json_fn\n{\n    template<typename BasicJsonType, typename T>\n    auto operator()(BasicJsonType& j, T&& val) const noexcept(noexcept(to_json(j, std::forward<T>(val))))\n    -> decltype(to_json(j, std::forward<T>(val)), void())\n    {\n        return to_json(j, std::forward<T>(val));\n    }\n};\n}  // namespace detail\n\n/// namespace to hold default `to_json` function\nnamespace\n{\nconstexpr const auto& to_json = detail::static_const<detail::to_json_fn>::value;\n} // namespace\n}  // namespace nlohmann\n"
  },
  {
    "path": "nlohmann_json/include/nlohmann/detail/exceptions.hpp",
    "content": "#pragma once\n\n#include <exception> // exception\n#include <stdexcept> // runtime_error\n#include <string> // to_string\n\n#include <nlohmann/detail/input/position_t.hpp>\n\nnamespace nlohmann\n{\nnamespace detail\n{\n////////////////\n// exceptions //\n////////////////\n\n/*!\n@brief general exception of the @ref basic_json class\n\nThis class is an extension of `std::exception` objects with a member @a id for\nexception ids. It is used as the base class for all exceptions thrown by the\n@ref basic_json class. This class can hence be used as \"wildcard\" to catch\nexceptions.\n\nSubclasses:\n- @ref parse_error for exceptions indicating a parse error\n- @ref invalid_iterator for exceptions indicating errors with iterators\n- @ref type_error for exceptions indicating executing a member function with\n                  a wrong type\n- @ref out_of_range for exceptions indicating access out of the defined range\n- @ref other_error for exceptions indicating other library errors\n\n@internal\n@note To have nothrow-copy-constructible exceptions, we internally use\n      `std::runtime_error` which can cope with arbitrary-length error messages.\n      Intermediate strings are built with static functions and then passed to\n      the actual constructor.\n@endinternal\n\n@liveexample{The following code shows how arbitrary library exceptions can be\ncaught.,exception}\n\n@since version 3.0.0\n*/\nclass exception : public std::exception\n{\n  public:\n    /// returns the explanatory string\n    const char* what() const noexcept override\n    {\n        return m.what();\n    }\n\n    /// the id of the exception\n    const int id;\n\n  protected:\n    exception(int id_, const char* what_arg) : id(id_), m(what_arg) {}\n\n    static std::string name(const std::string& ename, int id_)\n    {\n        return \"[json.exception.\" + ename + \".\" + std::to_string(id_) + \"] \";\n    }\n\n  private:\n    /// an exception object as storage for error messages\n    std::runtime_error m;\n};\n\n/*!\n@brief exception indicating a parse error\n\nThis exception is thrown by the library when a parse error occurs. Parse errors\ncan occur during the deserialization of JSON text, CBOR, MessagePack, as well\nas when using JSON Patch.\n\nMember @a byte holds the byte index of the last read character in the input\nfile.\n\nExceptions have ids 1xx.\n\nname / id                      | example message | description\n------------------------------ | --------------- | -------------------------\njson.exception.parse_error.101 | parse error at 2: unexpected end of input; expected string literal | This error indicates a syntax error while deserializing a JSON text. The error message describes that an unexpected token (character) was encountered, and the member @a byte indicates the error position.\njson.exception.parse_error.102 | parse error at 14: missing or wrong low surrogate | JSON uses the `\\uxxxx` format to describe Unicode characters. Code points above above 0xFFFF are split into two `\\uxxxx` entries (\"surrogate pairs\"). This error indicates that the surrogate pair is incomplete or contains an invalid code point.\njson.exception.parse_error.103 | parse error: code points above 0x10FFFF are invalid | Unicode supports code points up to 0x10FFFF. Code points above 0x10FFFF are invalid.\njson.exception.parse_error.104 | parse error: JSON patch must be an array of objects | [RFC 6902](https://tools.ietf.org/html/rfc6902) requires a JSON Patch document to be a JSON document that represents an array of objects.\njson.exception.parse_error.105 | parse error: operation must have string member 'op' | An operation of a JSON Patch document must contain exactly one \"op\" member, whose value indicates the operation to perform. Its value must be one of \"add\", \"remove\", \"replace\", \"move\", \"copy\", or \"test\"; other values are errors.\njson.exception.parse_error.106 | parse error: array index '01' must not begin with '0' | An array index in a JSON Pointer ([RFC 6901](https://tools.ietf.org/html/rfc6901)) may be `0` or any number without a leading `0`.\njson.exception.parse_error.107 | parse error: JSON pointer must be empty or begin with '/' - was: 'foo' | A JSON Pointer must be a Unicode string containing a sequence of zero or more reference tokens, each prefixed by a `/` character.\njson.exception.parse_error.108 | parse error: escape character '~' must be followed with '0' or '1' | In a JSON Pointer, only `~0` and `~1` are valid escape sequences.\njson.exception.parse_error.109 | parse error: array index 'one' is not a number | A JSON Pointer array index must be a number.\njson.exception.parse_error.110 | parse error at 1: cannot read 2 bytes from vector | When parsing CBOR or MessagePack, the byte vector ends before the complete value has been read.\njson.exception.parse_error.112 | parse error at 1: error reading CBOR; last byte: 0xF8 | Not all types of CBOR or MessagePack are supported. This exception occurs if an unsupported byte was read.\njson.exception.parse_error.113 | parse error at 2: expected a CBOR string; last byte: 0x98 | While parsing a map key, a value that is not a string has been read.\njson.exception.parse_error.114 | parse error: Unsupported BSON record type 0x0F | The parsing of the corresponding BSON record type is not implemented (yet).\n\n@note For an input with n bytes, 1 is the index of the first character and n+1\n      is the index of the terminating null byte or the end of file. This also\n      holds true when reading a byte vector (CBOR or MessagePack).\n\n@liveexample{The following code shows how a `parse_error` exception can be\ncaught.,parse_error}\n\n@sa @ref exception for the base class of the library exceptions\n@sa @ref invalid_iterator for exceptions indicating errors with iterators\n@sa @ref type_error for exceptions indicating executing a member function with\n                    a wrong type\n@sa @ref out_of_range for exceptions indicating access out of the defined range\n@sa @ref other_error for exceptions indicating other library errors\n\n@since version 3.0.0\n*/\nclass parse_error : public exception\n{\n  public:\n    /*!\n    @brief create a parse error exception\n    @param[in] id_       the id of the exception\n    @param[in] position  the position where the error occurred (or with\n                         chars_read_total=0 if the position cannot be\n                         determined)\n    @param[in] what_arg  the explanatory string\n    @return parse_error object\n    */\n    static parse_error create(int id_, const position_t& pos, const std::string& what_arg)\n    {\n        std::string w = exception::name(\"parse_error\", id_) + \"parse error\" +\n                        position_string(pos) + \": \" + what_arg;\n        return parse_error(id_, pos.chars_read_total, w.c_str());\n    }\n\n    static parse_error create(int id_, std::size_t byte_, const std::string& what_arg)\n    {\n        std::string w = exception::name(\"parse_error\", id_) + \"parse error\" +\n                        (byte_ != 0 ? (\" at byte \" + std::to_string(byte_)) : \"\") +\n                        \": \" + what_arg;\n        return parse_error(id_, byte_, w.c_str());\n    }\n\n    /*!\n    @brief byte index of the parse error\n\n    The byte index of the last read character in the input file.\n\n    @note For an input with n bytes, 1 is the index of the first character and\n          n+1 is the index of the terminating null byte or the end of file.\n          This also holds true when reading a byte vector (CBOR or MessagePack).\n    */\n    const std::size_t byte;\n\n  private:\n    parse_error(int id_, std::size_t byte_, const char* what_arg)\n        : exception(id_, what_arg), byte(byte_) {}\n\n    static std::string position_string(const position_t& pos)\n    {\n        return \" at line \" + std::to_string(pos.lines_read + 1) +\n               \", column \" + std::to_string(pos.chars_read_current_line);\n    }\n};\n\n/*!\n@brief exception indicating errors with iterators\n\nThis exception is thrown if iterators passed to a library function do not match\nthe expected semantics.\n\nExceptions have ids 2xx.\n\nname / id                           | example message | description\n----------------------------------- | --------------- | -------------------------\njson.exception.invalid_iterator.201 | iterators are not compatible | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid.\njson.exception.invalid_iterator.202 | iterator does not fit current value | In an erase or insert function, the passed iterator @a pos does not belong to the JSON value for which the function was called. It hence does not define a valid position for the deletion/insertion.\njson.exception.invalid_iterator.203 | iterators do not fit current value | Either iterator passed to function @ref erase(IteratorType first, IteratorType last) does not belong to the JSON value from which values shall be erased. It hence does not define a valid range to delete values from.\njson.exception.invalid_iterator.204 | iterators out of range | When an iterator range for a primitive type (number, boolean, or string) is passed to a constructor or an erase function, this range has to be exactly (@ref begin(), @ref end()), because this is the only way the single stored value is expressed. All other ranges are invalid.\njson.exception.invalid_iterator.205 | iterator out of range | When an iterator for a primitive type (number, boolean, or string) is passed to an erase function, the iterator has to be the @ref begin() iterator, because it is the only way to address the stored value. All other iterators are invalid.\njson.exception.invalid_iterator.206 | cannot construct with iterators from null | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) belong to a JSON null value and hence to not define a valid range.\njson.exception.invalid_iterator.207 | cannot use key() for non-object iterators | The key() member function can only be used on iterators belonging to a JSON object, because other types do not have a concept of a key.\njson.exception.invalid_iterator.208 | cannot use operator[] for object iterators | The operator[] to specify a concrete offset cannot be used on iterators belonging to a JSON object, because JSON objects are unordered.\njson.exception.invalid_iterator.209 | cannot use offsets with object iterators | The offset operators (+, -, +=, -=) cannot be used on iterators belonging to a JSON object, because JSON objects are unordered.\njson.exception.invalid_iterator.210 | iterators do not fit | The iterator range passed to the insert function are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid.\njson.exception.invalid_iterator.211 | passed iterators may not belong to container | The iterator range passed to the insert function must not be a subrange of the container to insert to.\njson.exception.invalid_iterator.212 | cannot compare iterators of different containers | When two iterators are compared, they must belong to the same container.\njson.exception.invalid_iterator.213 | cannot compare order of object iterators | The order of object iterators cannot be compared, because JSON objects are unordered.\njson.exception.invalid_iterator.214 | cannot get value | Cannot get value for iterator: Either the iterator belongs to a null value or it is an iterator to a primitive type (number, boolean, or string), but the iterator is different to @ref begin().\n\n@liveexample{The following code shows how an `invalid_iterator` exception can be\ncaught.,invalid_iterator}\n\n@sa @ref exception for the base class of the library exceptions\n@sa @ref parse_error for exceptions indicating a parse error\n@sa @ref type_error for exceptions indicating executing a member function with\n                    a wrong type\n@sa @ref out_of_range for exceptions indicating access out of the defined range\n@sa @ref other_error for exceptions indicating other library errors\n\n@since version 3.0.0\n*/\nclass invalid_iterator : public exception\n{\n  public:\n    static invalid_iterator create(int id_, const std::string& what_arg)\n    {\n        std::string w = exception::name(\"invalid_iterator\", id_) + what_arg;\n        return invalid_iterator(id_, w.c_str());\n    }\n\n  private:\n    invalid_iterator(int id_, const char* what_arg)\n        : exception(id_, what_arg) {}\n};\n\n/*!\n@brief exception indicating executing a member function with a wrong type\n\nThis exception is thrown in case of a type error; that is, a library function is\nexecuted on a JSON value whose type does not match the expected semantics.\n\nExceptions have ids 3xx.\n\nname / id                     | example message | description\n----------------------------- | --------------- | -------------------------\njson.exception.type_error.301 | cannot create object from initializer list | To create an object from an initializer list, the initializer list must consist only of a list of pairs whose first element is a string. When this constraint is violated, an array is created instead.\njson.exception.type_error.302 | type must be object, but is array | During implicit or explicit value conversion, the JSON type must be compatible to the target type. For instance, a JSON string can only be converted into string types, but not into numbers or boolean types.\njson.exception.type_error.303 | incompatible ReferenceType for get_ref, actual type is object | To retrieve a reference to a value stored in a @ref basic_json object with @ref get_ref, the type of the reference must match the value type. For instance, for a JSON array, the @a ReferenceType must be @ref array_t&.\njson.exception.type_error.304 | cannot use at() with string | The @ref at() member functions can only be executed for certain JSON types.\njson.exception.type_error.305 | cannot use operator[] with string | The @ref operator[] member functions can only be executed for certain JSON types.\njson.exception.type_error.306 | cannot use value() with string | The @ref value() member functions can only be executed for certain JSON types.\njson.exception.type_error.307 | cannot use erase() with string | The @ref erase() member functions can only be executed for certain JSON types.\njson.exception.type_error.308 | cannot use push_back() with string | The @ref push_back() and @ref operator+= member functions can only be executed for certain JSON types.\njson.exception.type_error.309 | cannot use insert() with | The @ref insert() member functions can only be executed for certain JSON types.\njson.exception.type_error.310 | cannot use swap() with number | The @ref swap() member functions can only be executed for certain JSON types.\njson.exception.type_error.311 | cannot use emplace_back() with string | The @ref emplace_back() member function can only be executed for certain JSON types.\njson.exception.type_error.312 | cannot use update() with string | The @ref update() member functions can only be executed for certain JSON types.\njson.exception.type_error.313 | invalid value to unflatten | The @ref unflatten function converts an object whose keys are JSON Pointers back into an arbitrary nested JSON value. The JSON Pointers must not overlap, because then the resulting value would not be well defined.\njson.exception.type_error.314 | only objects can be unflattened | The @ref unflatten function only works for an object whose keys are JSON Pointers.\njson.exception.type_error.315 | values in object must be primitive | The @ref unflatten function only works for an object whose keys are JSON Pointers and whose values are primitive.\njson.exception.type_error.316 | invalid UTF-8 byte at index 10: 0x7E | The @ref dump function only works with UTF-8 encoded strings; that is, if you assign a `std::string` to a JSON value, make sure it is UTF-8 encoded. |\njson.exception.type_error.317 | JSON value cannot be serialized to requested format | The dynamic type of the object cannot be represented in the requested serialization format (e.g. a raw `true` or `null` JSON object cannot be serialized to BSON) |\n\n@liveexample{The following code shows how a `type_error` exception can be\ncaught.,type_error}\n\n@sa @ref exception for the base class of the library exceptions\n@sa @ref parse_error for exceptions indicating a parse error\n@sa @ref invalid_iterator for exceptions indicating errors with iterators\n@sa @ref out_of_range for exceptions indicating access out of the defined range\n@sa @ref other_error for exceptions indicating other library errors\n\n@since version 3.0.0\n*/\nclass type_error : public exception\n{\n  public:\n    static type_error create(int id_, const std::string& what_arg)\n    {\n        std::string w = exception::name(\"type_error\", id_) + what_arg;\n        return type_error(id_, w.c_str());\n    }\n\n  private:\n    type_error(int id_, const char* what_arg) : exception(id_, what_arg) {}\n};\n\n/*!\n@brief exception indicating access out of the defined range\n\nThis exception is thrown in case a library function is called on an input\nparameter that exceeds the expected range, for instance in case of array\nindices or nonexisting object keys.\n\nExceptions have ids 4xx.\n\nname / id                       | example message | description\n------------------------------- | --------------- | -------------------------\njson.exception.out_of_range.401 | array index 3 is out of range | The provided array index @a i is larger than @a size-1.\njson.exception.out_of_range.402 | array index '-' (3) is out of range | The special array index `-` in a JSON Pointer never describes a valid element of the array, but the index past the end. That is, it can only be used to add elements at this position, but not to read it.\njson.exception.out_of_range.403 | key 'foo' not found | The provided key was not found in the JSON object.\njson.exception.out_of_range.404 | unresolved reference token 'foo' | A reference token in a JSON Pointer could not be resolved.\njson.exception.out_of_range.405 | JSON pointer has no parent | The JSON Patch operations 'remove' and 'add' can not be applied to the root element of the JSON value.\njson.exception.out_of_range.406 | number overflow parsing '10E1000' | A parsed number could not be stored as without changing it to NaN or INF.\njson.exception.out_of_range.407 | number overflow serializing '9223372036854775808' | UBJSON and BSON only support integer numbers up to 9223372036854775807. |\njson.exception.out_of_range.408 | excessive array size: 8658170730974374167 | The size (following `#`) of an UBJSON array or object exceeds the maximal capacity. |\njson.exception.out_of_range.409 | BSON key cannot contain code point U+0000 (at byte 2) | Key identifiers to be serialized to BSON cannot contain code point U+0000, since the key is stored as zero-terminated c-string |\n\n@liveexample{The following code shows how an `out_of_range` exception can be\ncaught.,out_of_range}\n\n@sa @ref exception for the base class of the library exceptions\n@sa @ref parse_error for exceptions indicating a parse error\n@sa @ref invalid_iterator for exceptions indicating errors with iterators\n@sa @ref type_error for exceptions indicating executing a member function with\n                    a wrong type\n@sa @ref other_error for exceptions indicating other library errors\n\n@since version 3.0.0\n*/\nclass out_of_range : public exception\n{\n  public:\n    static out_of_range create(int id_, const std::string& what_arg)\n    {\n        std::string w = exception::name(\"out_of_range\", id_) + what_arg;\n        return out_of_range(id_, w.c_str());\n    }\n\n  private:\n    out_of_range(int id_, const char* what_arg) : exception(id_, what_arg) {}\n};\n\n/*!\n@brief exception indicating other library errors\n\nThis exception is thrown in case of errors that cannot be classified with the\nother exception types.\n\nExceptions have ids 5xx.\n\nname / id                      | example message | description\n------------------------------ | --------------- | -------------------------\njson.exception.other_error.501 | unsuccessful: {\"op\":\"test\",\"path\":\"/baz\", \"value\":\"bar\"} | A JSON Patch operation 'test' failed. The unsuccessful operation is also printed.\n\n@sa @ref exception for the base class of the library exceptions\n@sa @ref parse_error for exceptions indicating a parse error\n@sa @ref invalid_iterator for exceptions indicating errors with iterators\n@sa @ref type_error for exceptions indicating executing a member function with\n                    a wrong type\n@sa @ref out_of_range for exceptions indicating access out of the defined range\n\n@liveexample{The following code shows how an `other_error` exception can be\ncaught.,other_error}\n\n@since version 3.0.0\n*/\nclass other_error : public exception\n{\n  public:\n    static other_error create(int id_, const std::string& what_arg)\n    {\n        std::string w = exception::name(\"other_error\", id_) + what_arg;\n        return other_error(id_, w.c_str());\n    }\n\n  private:\n    other_error(int id_, const char* what_arg) : exception(id_, what_arg) {}\n};\n}  // namespace detail\n}  // namespace nlohmann\n"
  },
  {
    "path": "nlohmann_json/include/nlohmann/detail/input/binary_reader.hpp",
    "content": "#pragma once\n\n#include <algorithm> // generate_n\n#include <array> // array\n#include <cassert> // assert\n#include <cmath> // ldexp\n#include <cstddef> // size_t\n#include <cstdint> // uint8_t, uint16_t, uint32_t, uint64_t\n#include <cstdio> // snprintf\n#include <cstring> // memcpy\n#include <iterator> // back_inserter\n#include <limits> // numeric_limits\n#include <string> // char_traits, string\n#include <utility> // make_pair, move\n\n#include <nlohmann/detail/input/input_adapters.hpp>\n#include <nlohmann/detail/input/json_sax.hpp>\n#include <nlohmann/detail/exceptions.hpp>\n#include <nlohmann/detail/macro_scope.hpp>\n#include <nlohmann/detail/meta/is_sax.hpp>\n#include <nlohmann/detail/value_t.hpp>\n\nnamespace nlohmann\n{\nnamespace detail\n{\n///////////////////\n// binary reader //\n///////////////////\n\n/*!\n@brief deserialization of CBOR, MessagePack, and UBJSON values\n*/\ntemplate<typename BasicJsonType, typename SAX = json_sax_dom_parser<BasicJsonType>>\nclass binary_reader\n{\n    using number_integer_t = typename BasicJsonType::number_integer_t;\n    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n    using number_float_t = typename BasicJsonType::number_float_t;\n    using string_t = typename BasicJsonType::string_t;\n    using json_sax_t = SAX;\n\n  public:\n    /*!\n    @brief create a binary reader\n\n    @param[in] adapter  input adapter to read from\n    */\n    explicit binary_reader(input_adapter_t adapter) : ia(std::move(adapter))\n    {\n        (void)detail::is_sax_static_asserts<SAX, BasicJsonType> {};\n        assert(ia);\n    }\n\n    /*!\n    @param[in] format  the binary format to parse\n    @param[in] sax_    a SAX event processor\n    @param[in] strict  whether to expect the input to be consumed completed\n\n    @return\n    */\n    bool sax_parse(const input_format_t format,\n                   json_sax_t* sax_,\n                   const bool strict = true)\n    {\n        sax = sax_;\n        bool result = false;\n\n        switch (format)\n        {\n            case input_format_t::bson:\n                result = parse_bson_internal();\n                break;\n\n            case input_format_t::cbor:\n                result = parse_cbor_internal();\n                break;\n\n            case input_format_t::msgpack:\n                result = parse_msgpack_internal();\n                break;\n\n            case input_format_t::ubjson:\n                result = parse_ubjson_internal();\n                break;\n\n            // LCOV_EXCL_START\n            default:\n                assert(false);\n                // LCOV_EXCL_STOP\n        }\n\n        // strict mode: next byte must be EOF\n        if (result and strict)\n        {\n            if (format == input_format_t::ubjson)\n            {\n                get_ignore_noop();\n            }\n            else\n            {\n                get();\n            }\n\n            if (JSON_UNLIKELY(current != std::char_traits<char>::eof()))\n            {\n                return sax->parse_error(chars_read, get_token_string(),\n                                        parse_error::create(110, chars_read, exception_message(format, \"expected end of input; last byte: 0x\" + get_token_string(), \"value\")));\n            }\n        }\n\n        return result;\n    }\n\n    /*!\n    @brief determine system byte order\n\n    @return true if and only if system's byte order is little endian\n\n    @note from http://stackoverflow.com/a/1001328/266378\n    */\n    static constexpr bool little_endianess(int num = 1) noexcept\n    {\n        return (*reinterpret_cast<char*>(&num) == 1);\n    }\n\n  private:\n    //////////\n    // BSON //\n    //////////\n\n    /*!\n    @brief Reads in a BSON-object and passes it to the SAX-parser.\n    @return whether a valid BSON-value was passed to the SAX parser\n    */\n    bool parse_bson_internal()\n    {\n        std::int32_t document_size;\n        get_number<std::int32_t, true>(input_format_t::bson, document_size);\n\n        if (JSON_UNLIKELY(not sax->start_object(std::size_t(-1))))\n        {\n            return false;\n        }\n\n        if (JSON_UNLIKELY(not parse_bson_element_list(/*is_array*/false)))\n        {\n            return false;\n        }\n\n        return sax->end_object();\n    }\n\n    /*!\n    @brief Parses a C-style string from the BSON input.\n    @param[in, out] result  A reference to the string variable where the read\n                            string is to be stored.\n    @return `true` if the \\x00-byte indicating the end of the string was\n             encountered before the EOF; false` indicates an unexpected EOF.\n    */\n    bool get_bson_cstr(string_t& result)\n    {\n        auto out = std::back_inserter(result);\n        while (true)\n        {\n            get();\n            if (JSON_UNLIKELY(not unexpect_eof(input_format_t::bson, \"cstring\")))\n            {\n                return false;\n            }\n            if (current == 0x00)\n            {\n                return true;\n            }\n            *out++ = static_cast<char>(current);\n        }\n\n        return true;\n    }\n\n    /*!\n    @brief Parses a zero-terminated string of length @a len from the BSON\n           input.\n    @param[in] len  The length (including the zero-byte at the end) of the\n                    string to be read.\n    @param[in, out] result  A reference to the string variable where the read\n                            string is to be stored.\n    @tparam NumberType The type of the length @a len\n    @pre len >= 1\n    @return `true` if the string was successfully parsed\n    */\n    template<typename NumberType>\n    bool get_bson_string(const NumberType len, string_t& result)\n    {\n        if (JSON_UNLIKELY(len < 1))\n        {\n            auto last_token = get_token_string();\n            return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::bson, \"string length must be at least 1, is \" + std::to_string(len), \"string\")));\n        }\n\n        return get_string(input_format_t::bson, len - static_cast<NumberType>(1), result) and get() != std::char_traits<char>::eof();\n    }\n\n    /*!\n    @brief Read a BSON document element of the given @a element_type.\n    @param[in] element_type The BSON element type, c.f. http://bsonspec.org/spec.html\n    @param[in] element_type_parse_position The position in the input stream,\n               where the `element_type` was read.\n    @warning Not all BSON element types are supported yet. An unsupported\n             @a element_type will give rise to a parse_error.114:\n             Unsupported BSON record type 0x...\n    @return whether a valid BSON-object/array was passed to the SAX parser\n    */\n    bool parse_bson_element_internal(const int element_type,\n                                     const std::size_t element_type_parse_position)\n    {\n        switch (element_type)\n        {\n            case 0x01: // double\n            {\n                double number;\n                return get_number<double, true>(input_format_t::bson, number) and sax->number_float(static_cast<number_float_t>(number), \"\");\n            }\n\n            case 0x02: // string\n            {\n                std::int32_t len;\n                string_t value;\n                return get_number<std::int32_t, true>(input_format_t::bson, len) and get_bson_string(len, value) and sax->string(value);\n            }\n\n            case 0x03: // object\n            {\n                return parse_bson_internal();\n            }\n\n            case 0x04: // array\n            {\n                return parse_bson_array();\n            }\n\n            case 0x08: // boolean\n            {\n                return sax->boolean(get() != 0);\n            }\n\n            case 0x0A: // null\n            {\n                return sax->null();\n            }\n\n            case 0x10: // int32\n            {\n                std::int32_t value;\n                return get_number<std::int32_t, true>(input_format_t::bson, value) and sax->number_integer(value);\n            }\n\n            case 0x12: // int64\n            {\n                std::int64_t value;\n                return get_number<std::int64_t, true>(input_format_t::bson, value) and sax->number_integer(value);\n            }\n\n            default: // anything else not supported (yet)\n            {\n                char cr[3];\n                (std::snprintf)(cr, sizeof(cr), \"%.2hhX\", static_cast<unsigned char>(element_type));\n                return sax->parse_error(element_type_parse_position, std::string(cr), parse_error::create(114, element_type_parse_position, \"Unsupported BSON record type 0x\" + std::string(cr)));\n            }\n        }\n    }\n\n    /*!\n    @brief Read a BSON element list (as specified in the BSON-spec)\n\n    The same binary layout is used for objects and arrays, hence it must be\n    indicated with the argument @a is_array which one is expected\n    (true --> array, false --> object).\n\n    @param[in] is_array Determines if the element list being read is to be\n                        treated as an object (@a is_array == false), or as an\n                        array (@a is_array == true).\n    @return whether a valid BSON-object/array was passed to the SAX parser\n    */\n    bool parse_bson_element_list(const bool is_array)\n    {\n        string_t key;\n        while (int element_type = get())\n        {\n            if (JSON_UNLIKELY(not unexpect_eof(input_format_t::bson, \"element list\")))\n            {\n                return false;\n            }\n\n            const std::size_t element_type_parse_position = chars_read;\n            if (JSON_UNLIKELY(not get_bson_cstr(key)))\n            {\n                return false;\n            }\n\n            if (not is_array)\n            {\n                if (not sax->key(key))\n                {\n                    return false;\n                }\n            }\n\n            if (JSON_UNLIKELY(not parse_bson_element_internal(element_type, element_type_parse_position)))\n            {\n                return false;\n            }\n\n            // get_bson_cstr only appends\n            key.clear();\n        }\n\n        return true;\n    }\n\n    /*!\n    @brief Reads an array from the BSON input and passes it to the SAX-parser.\n    @return whether a valid BSON-array was passed to the SAX parser\n    */\n    bool parse_bson_array()\n    {\n        std::int32_t document_size;\n        get_number<std::int32_t, true>(input_format_t::bson, document_size);\n\n        if (JSON_UNLIKELY(not sax->start_array(std::size_t(-1))))\n        {\n            return false;\n        }\n\n        if (JSON_UNLIKELY(not parse_bson_element_list(/*is_array*/true)))\n        {\n            return false;\n        }\n\n        return sax->end_array();\n    }\n\n    //////////\n    // CBOR //\n    //////////\n\n    /*!\n    @param[in] get_char  whether a new character should be retrieved from the\n                         input (true, default) or whether the last read\n                         character should be considered instead\n\n    @return whether a valid CBOR value was passed to the SAX parser\n    */\n    bool parse_cbor_internal(const bool get_char = true)\n    {\n        switch (get_char ? get() : current)\n        {\n            // EOF\n            case std::char_traits<char>::eof():\n                return unexpect_eof(input_format_t::cbor, \"value\");\n\n            // Integer 0x00..0x17 (0..23)\n            case 0x00:\n            case 0x01:\n            case 0x02:\n            case 0x03:\n            case 0x04:\n            case 0x05:\n            case 0x06:\n            case 0x07:\n            case 0x08:\n            case 0x09:\n            case 0x0A:\n            case 0x0B:\n            case 0x0C:\n            case 0x0D:\n            case 0x0E:\n            case 0x0F:\n            case 0x10:\n            case 0x11:\n            case 0x12:\n            case 0x13:\n            case 0x14:\n            case 0x15:\n            case 0x16:\n            case 0x17:\n                return sax->number_unsigned(static_cast<number_unsigned_t>(current));\n\n            case 0x18: // Unsigned integer (one-byte uint8_t follows)\n            {\n                uint8_t number;\n                return get_number(input_format_t::cbor, number) and sax->number_unsigned(number);\n            }\n\n            case 0x19: // Unsigned integer (two-byte uint16_t follows)\n            {\n                uint16_t number;\n                return get_number(input_format_t::cbor, number) and sax->number_unsigned(number);\n            }\n\n            case 0x1A: // Unsigned integer (four-byte uint32_t follows)\n            {\n                uint32_t number;\n                return get_number(input_format_t::cbor, number) and sax->number_unsigned(number);\n            }\n\n            case 0x1B: // Unsigned integer (eight-byte uint64_t follows)\n            {\n                uint64_t number;\n                return get_number(input_format_t::cbor, number) and sax->number_unsigned(number);\n            }\n\n            // Negative integer -1-0x00..-1-0x17 (-1..-24)\n            case 0x20:\n            case 0x21:\n            case 0x22:\n            case 0x23:\n            case 0x24:\n            case 0x25:\n            case 0x26:\n            case 0x27:\n            case 0x28:\n            case 0x29:\n            case 0x2A:\n            case 0x2B:\n            case 0x2C:\n            case 0x2D:\n            case 0x2E:\n            case 0x2F:\n            case 0x30:\n            case 0x31:\n            case 0x32:\n            case 0x33:\n            case 0x34:\n            case 0x35:\n            case 0x36:\n            case 0x37:\n                return sax->number_integer(static_cast<int8_t>(0x20 - 1 - current));\n\n            case 0x38: // Negative integer (one-byte uint8_t follows)\n            {\n                uint8_t number;\n                return get_number(input_format_t::cbor, number) and sax->number_integer(static_cast<number_integer_t>(-1) - number);\n            }\n\n            case 0x39: // Negative integer -1-n (two-byte uint16_t follows)\n            {\n                uint16_t number;\n                return get_number(input_format_t::cbor, number) and sax->number_integer(static_cast<number_integer_t>(-1) - number);\n            }\n\n            case 0x3A: // Negative integer -1-n (four-byte uint32_t follows)\n            {\n                uint32_t number;\n                return get_number(input_format_t::cbor, number) and sax->number_integer(static_cast<number_integer_t>(-1) - number);\n            }\n\n            case 0x3B: // Negative integer -1-n (eight-byte uint64_t follows)\n            {\n                uint64_t number;\n                return get_number(input_format_t::cbor, number) and sax->number_integer(static_cast<number_integer_t>(-1)\n                        - static_cast<number_integer_t>(number));\n            }\n\n            // UTF-8 string (0x00..0x17 bytes follow)\n            case 0x60:\n            case 0x61:\n            case 0x62:\n            case 0x63:\n            case 0x64:\n            case 0x65:\n            case 0x66:\n            case 0x67:\n            case 0x68:\n            case 0x69:\n            case 0x6A:\n            case 0x6B:\n            case 0x6C:\n            case 0x6D:\n            case 0x6E:\n            case 0x6F:\n            case 0x70:\n            case 0x71:\n            case 0x72:\n            case 0x73:\n            case 0x74:\n            case 0x75:\n            case 0x76:\n            case 0x77:\n            case 0x78: // UTF-8 string (one-byte uint8_t for n follows)\n            case 0x79: // UTF-8 string (two-byte uint16_t for n follow)\n            case 0x7A: // UTF-8 string (four-byte uint32_t for n follow)\n            case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow)\n            case 0x7F: // UTF-8 string (indefinite length)\n            {\n                string_t s;\n                return get_cbor_string(s) and sax->string(s);\n            }\n\n            // array (0x00..0x17 data items follow)\n            case 0x80:\n            case 0x81:\n            case 0x82:\n            case 0x83:\n            case 0x84:\n            case 0x85:\n            case 0x86:\n            case 0x87:\n            case 0x88:\n            case 0x89:\n            case 0x8A:\n            case 0x8B:\n            case 0x8C:\n            case 0x8D:\n            case 0x8E:\n            case 0x8F:\n            case 0x90:\n            case 0x91:\n            case 0x92:\n            case 0x93:\n            case 0x94:\n            case 0x95:\n            case 0x96:\n            case 0x97:\n                return get_cbor_array(static_cast<std::size_t>(current & 0x1F));\n\n            case 0x98: // array (one-byte uint8_t for n follows)\n            {\n                uint8_t len;\n                return get_number(input_format_t::cbor, len) and get_cbor_array(static_cast<std::size_t>(len));\n            }\n\n            case 0x99: // array (two-byte uint16_t for n follow)\n            {\n                uint16_t len;\n                return get_number(input_format_t::cbor, len) and get_cbor_array(static_cast<std::size_t>(len));\n            }\n\n            case 0x9A: // array (four-byte uint32_t for n follow)\n            {\n                uint32_t len;\n                return get_number(input_format_t::cbor, len) and get_cbor_array(static_cast<std::size_t>(len));\n            }\n\n            case 0x9B: // array (eight-byte uint64_t for n follow)\n            {\n                uint64_t len;\n                return get_number(input_format_t::cbor, len) and get_cbor_array(static_cast<std::size_t>(len));\n            }\n\n            case 0x9F: // array (indefinite length)\n                return get_cbor_array(std::size_t(-1));\n\n            // map (0x00..0x17 pairs of data items follow)\n            case 0xA0:\n            case 0xA1:\n            case 0xA2:\n            case 0xA3:\n            case 0xA4:\n            case 0xA5:\n            case 0xA6:\n            case 0xA7:\n            case 0xA8:\n            case 0xA9:\n            case 0xAA:\n            case 0xAB:\n            case 0xAC:\n            case 0xAD:\n            case 0xAE:\n            case 0xAF:\n            case 0xB0:\n            case 0xB1:\n            case 0xB2:\n            case 0xB3:\n            case 0xB4:\n            case 0xB5:\n            case 0xB6:\n            case 0xB7:\n                return get_cbor_object(static_cast<std::size_t>(current & 0x1F));\n\n            case 0xB8: // map (one-byte uint8_t for n follows)\n            {\n                uint8_t len;\n                return get_number(input_format_t::cbor, len) and get_cbor_object(static_cast<std::size_t>(len));\n            }\n\n            case 0xB9: // map (two-byte uint16_t for n follow)\n            {\n                uint16_t len;\n                return get_number(input_format_t::cbor, len) and get_cbor_object(static_cast<std::size_t>(len));\n            }\n\n            case 0xBA: // map (four-byte uint32_t for n follow)\n            {\n                uint32_t len;\n                return get_number(input_format_t::cbor, len) and get_cbor_object(static_cast<std::size_t>(len));\n            }\n\n            case 0xBB: // map (eight-byte uint64_t for n follow)\n            {\n                uint64_t len;\n                return get_number(input_format_t::cbor, len) and get_cbor_object(static_cast<std::size_t>(len));\n            }\n\n            case 0xBF: // map (indefinite length)\n                return get_cbor_object(std::size_t(-1));\n\n            case 0xF4: // false\n                return sax->boolean(false);\n\n            case 0xF5: // true\n                return sax->boolean(true);\n\n            case 0xF6: // null\n                return sax->null();\n\n            case 0xF9: // Half-Precision Float (two-byte IEEE 754)\n            {\n                const int byte1_raw = get();\n                if (JSON_UNLIKELY(not unexpect_eof(input_format_t::cbor, \"number\")))\n                {\n                    return false;\n                }\n                const int byte2_raw = get();\n                if (JSON_UNLIKELY(not unexpect_eof(input_format_t::cbor, \"number\")))\n                {\n                    return false;\n                }\n\n                const auto byte1 = static_cast<unsigned char>(byte1_raw);\n                const auto byte2 = static_cast<unsigned char>(byte2_raw);\n\n                // code from RFC 7049, Appendix D, Figure 3:\n                // As half-precision floating-point numbers were only added\n                // to IEEE 754 in 2008, today's programming platforms often\n                // still only have limited support for them. It is very\n                // easy to include at least decoding support for them even\n                // without such support. An example of a small decoder for\n                // half-precision floating-point numbers in the C language\n                // is shown in Fig. 3.\n                const int half = (byte1 << 8) + byte2;\n                const double val = [&half]\n                {\n                    const int exp = (half >> 10) & 0x1F;\n                    const int mant = half & 0x3FF;\n                    assert(0 <= exp and exp <= 32);\n                    assert(0 <= mant and mant <= 1024);\n                    switch (exp)\n                    {\n                        case 0:\n                            return std::ldexp(mant, -24);\n                        case 31:\n                            return (mant == 0)\n                            ? std::numeric_limits<double>::infinity()\n                            : std::numeric_limits<double>::quiet_NaN();\n                        default:\n                            return std::ldexp(mant + 1024, exp - 25);\n                    }\n                }();\n                return sax->number_float((half & 0x8000) != 0\n                                         ? static_cast<number_float_t>(-val)\n                                         : static_cast<number_float_t>(val), \"\");\n            }\n\n            case 0xFA: // Single-Precision Float (four-byte IEEE 754)\n            {\n                float number;\n                return get_number(input_format_t::cbor, number) and sax->number_float(static_cast<number_float_t>(number), \"\");\n            }\n\n            case 0xFB: // Double-Precision Float (eight-byte IEEE 754)\n            {\n                double number;\n                return get_number(input_format_t::cbor, number) and sax->number_float(static_cast<number_float_t>(number), \"\");\n            }\n\n            default: // anything else (0xFF is handled inside the other types)\n            {\n                auto last_token = get_token_string();\n                return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::cbor, \"invalid byte: 0x\" + last_token, \"value\")));\n            }\n        }\n    }\n\n    /*!\n    @brief reads a CBOR string\n\n    This function first reads starting bytes to determine the expected\n    string length and then copies this number of bytes into a string.\n    Additionally, CBOR's strings with indefinite lengths are supported.\n\n    @param[out] result  created string\n\n    @return whether string creation completed\n    */\n    bool get_cbor_string(string_t& result)\n    {\n        if (JSON_UNLIKELY(not unexpect_eof(input_format_t::cbor, \"string\")))\n        {\n            return false;\n        }\n\n        switch (current)\n        {\n            // UTF-8 string (0x00..0x17 bytes follow)\n            case 0x60:\n            case 0x61:\n            case 0x62:\n            case 0x63:\n            case 0x64:\n            case 0x65:\n            case 0x66:\n            case 0x67:\n            case 0x68:\n            case 0x69:\n            case 0x6A:\n            case 0x6B:\n            case 0x6C:\n            case 0x6D:\n            case 0x6E:\n            case 0x6F:\n            case 0x70:\n            case 0x71:\n            case 0x72:\n            case 0x73:\n            case 0x74:\n            case 0x75:\n            case 0x76:\n            case 0x77:\n            {\n                return get_string(input_format_t::cbor, current & 0x1F, result);\n            }\n\n            case 0x78: // UTF-8 string (one-byte uint8_t for n follows)\n            {\n                uint8_t len;\n                return get_number(input_format_t::cbor, len) and get_string(input_format_t::cbor, len, result);\n            }\n\n            case 0x79: // UTF-8 string (two-byte uint16_t for n follow)\n            {\n                uint16_t len;\n                return get_number(input_format_t::cbor, len) and get_string(input_format_t::cbor, len, result);\n            }\n\n            case 0x7A: // UTF-8 string (four-byte uint32_t for n follow)\n            {\n                uint32_t len;\n                return get_number(input_format_t::cbor, len) and get_string(input_format_t::cbor, len, result);\n            }\n\n            case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow)\n            {\n                uint64_t len;\n                return get_number(input_format_t::cbor, len) and get_string(input_format_t::cbor, len, result);\n            }\n\n            case 0x7F: // UTF-8 string (indefinite length)\n            {\n                while (get() != 0xFF)\n                {\n                    string_t chunk;\n                    if (not get_cbor_string(chunk))\n                    {\n                        return false;\n                    }\n                    result.append(chunk);\n                }\n                return true;\n            }\n\n            default:\n            {\n                auto last_token = get_token_string();\n                return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::cbor, \"expected length specification (0x60-0x7B) or indefinite string type (0x7F); last byte: 0x\" + last_token, \"string\")));\n            }\n        }\n    }\n\n    /*!\n    @param[in] len  the length of the array or std::size_t(-1) for an\n                    array of indefinite size\n    @return whether array creation completed\n    */\n    bool get_cbor_array(const std::size_t len)\n    {\n        if (JSON_UNLIKELY(not sax->start_array(len)))\n        {\n            return false;\n        }\n\n        if (len != std::size_t(-1))\n        {\n            for (std::size_t i = 0; i < len; ++i)\n            {\n                if (JSON_UNLIKELY(not parse_cbor_internal()))\n                {\n                    return false;\n                }\n            }\n        }\n        else\n        {\n            while (get() != 0xFF)\n            {\n                if (JSON_UNLIKELY(not parse_cbor_internal(false)))\n                {\n                    return false;\n                }\n            }\n        }\n\n        return sax->end_array();\n    }\n\n    /*!\n    @param[in] len  the length of the object or std::size_t(-1) for an\n                    object of indefinite size\n    @return whether object creation completed\n    */\n    bool get_cbor_object(const std::size_t len)\n    {\n        if (not JSON_UNLIKELY(sax->start_object(len)))\n        {\n            return false;\n        }\n\n        string_t key;\n        if (len != std::size_t(-1))\n        {\n            for (std::size_t i = 0; i < len; ++i)\n            {\n                get();\n                if (JSON_UNLIKELY(not get_cbor_string(key) or not sax->key(key)))\n                {\n                    return false;\n                }\n\n                if (JSON_UNLIKELY(not parse_cbor_internal()))\n                {\n                    return false;\n                }\n                key.clear();\n            }\n        }\n        else\n        {\n            while (get() != 0xFF)\n            {\n                if (JSON_UNLIKELY(not get_cbor_string(key) or not sax->key(key)))\n                {\n                    return false;\n                }\n\n                if (JSON_UNLIKELY(not parse_cbor_internal()))\n                {\n                    return false;\n                }\n                key.clear();\n            }\n        }\n\n        return sax->end_object();\n    }\n\n    /////////////\n    // MsgPack //\n    /////////////\n\n    /*!\n    @return whether a valid MessagePack value was passed to the SAX parser\n    */\n    bool parse_msgpack_internal()\n    {\n        switch (get())\n        {\n            // EOF\n            case std::char_traits<char>::eof():\n                return unexpect_eof(input_format_t::msgpack, \"value\");\n\n            // positive fixint\n            case 0x00:\n            case 0x01:\n            case 0x02:\n            case 0x03:\n            case 0x04:\n            case 0x05:\n            case 0x06:\n            case 0x07:\n            case 0x08:\n            case 0x09:\n            case 0x0A:\n            case 0x0B:\n            case 0x0C:\n            case 0x0D:\n            case 0x0E:\n            case 0x0F:\n            case 0x10:\n            case 0x11:\n            case 0x12:\n            case 0x13:\n            case 0x14:\n            case 0x15:\n            case 0x16:\n            case 0x17:\n            case 0x18:\n            case 0x19:\n            case 0x1A:\n            case 0x1B:\n            case 0x1C:\n            case 0x1D:\n            case 0x1E:\n            case 0x1F:\n            case 0x20:\n            case 0x21:\n            case 0x22:\n            case 0x23:\n            case 0x24:\n            case 0x25:\n            case 0x26:\n            case 0x27:\n            case 0x28:\n            case 0x29:\n            case 0x2A:\n            case 0x2B:\n            case 0x2C:\n            case 0x2D:\n            case 0x2E:\n            case 0x2F:\n            case 0x30:\n            case 0x31:\n            case 0x32:\n            case 0x33:\n            case 0x34:\n            case 0x35:\n            case 0x36:\n            case 0x37:\n            case 0x38:\n            case 0x39:\n            case 0x3A:\n            case 0x3B:\n            case 0x3C:\n            case 0x3D:\n            case 0x3E:\n            case 0x3F:\n            case 0x40:\n            case 0x41:\n            case 0x42:\n            case 0x43:\n            case 0x44:\n            case 0x45:\n            case 0x46:\n            case 0x47:\n            case 0x48:\n            case 0x49:\n            case 0x4A:\n            case 0x4B:\n            case 0x4C:\n            case 0x4D:\n            case 0x4E:\n            case 0x4F:\n            case 0x50:\n            case 0x51:\n            case 0x52:\n            case 0x53:\n            case 0x54:\n            case 0x55:\n            case 0x56:\n            case 0x57:\n            case 0x58:\n            case 0x59:\n            case 0x5A:\n            case 0x5B:\n            case 0x5C:\n            case 0x5D:\n            case 0x5E:\n            case 0x5F:\n            case 0x60:\n            case 0x61:\n            case 0x62:\n            case 0x63:\n            case 0x64:\n            case 0x65:\n            case 0x66:\n            case 0x67:\n            case 0x68:\n            case 0x69:\n            case 0x6A:\n            case 0x6B:\n            case 0x6C:\n            case 0x6D:\n            case 0x6E:\n            case 0x6F:\n            case 0x70:\n            case 0x71:\n            case 0x72:\n            case 0x73:\n            case 0x74:\n            case 0x75:\n            case 0x76:\n            case 0x77:\n            case 0x78:\n            case 0x79:\n            case 0x7A:\n            case 0x7B:\n            case 0x7C:\n            case 0x7D:\n            case 0x7E:\n            case 0x7F:\n                return sax->number_unsigned(static_cast<number_unsigned_t>(current));\n\n            // fixmap\n            case 0x80:\n            case 0x81:\n            case 0x82:\n            case 0x83:\n            case 0x84:\n            case 0x85:\n            case 0x86:\n            case 0x87:\n            case 0x88:\n            case 0x89:\n            case 0x8A:\n            case 0x8B:\n            case 0x8C:\n            case 0x8D:\n            case 0x8E:\n            case 0x8F:\n                return get_msgpack_object(static_cast<std::size_t>(current & 0x0F));\n\n            // fixarray\n            case 0x90:\n            case 0x91:\n            case 0x92:\n            case 0x93:\n            case 0x94:\n            case 0x95:\n            case 0x96:\n            case 0x97:\n            case 0x98:\n            case 0x99:\n            case 0x9A:\n            case 0x9B:\n            case 0x9C:\n            case 0x9D:\n            case 0x9E:\n            case 0x9F:\n                return get_msgpack_array(static_cast<std::size_t>(current & 0x0F));\n\n            // fixstr\n            case 0xA0:\n            case 0xA1:\n            case 0xA2:\n            case 0xA3:\n            case 0xA4:\n            case 0xA5:\n            case 0xA6:\n            case 0xA7:\n            case 0xA8:\n            case 0xA9:\n            case 0xAA:\n            case 0xAB:\n            case 0xAC:\n            case 0xAD:\n            case 0xAE:\n            case 0xAF:\n            case 0xB0:\n            case 0xB1:\n            case 0xB2:\n            case 0xB3:\n            case 0xB4:\n            case 0xB5:\n            case 0xB6:\n            case 0xB7:\n            case 0xB8:\n            case 0xB9:\n            case 0xBA:\n            case 0xBB:\n            case 0xBC:\n            case 0xBD:\n            case 0xBE:\n            case 0xBF:\n            {\n                string_t s;\n                return get_msgpack_string(s) and sax->string(s);\n            }\n\n            case 0xC0: // nil\n                return sax->null();\n\n            case 0xC2: // false\n                return sax->boolean(false);\n\n            case 0xC3: // true\n                return sax->boolean(true);\n\n            case 0xCA: // float 32\n            {\n                float number;\n                return get_number(input_format_t::msgpack, number) and sax->number_float(static_cast<number_float_t>(number), \"\");\n            }\n\n            case 0xCB: // float 64\n            {\n                double number;\n                return get_number(input_format_t::msgpack, number) and sax->number_float(static_cast<number_float_t>(number), \"\");\n            }\n\n            case 0xCC: // uint 8\n            {\n                uint8_t number;\n                return get_number(input_format_t::msgpack, number) and sax->number_unsigned(number);\n            }\n\n            case 0xCD: // uint 16\n            {\n                uint16_t number;\n                return get_number(input_format_t::msgpack, number) and sax->number_unsigned(number);\n            }\n\n            case 0xCE: // uint 32\n            {\n                uint32_t number;\n                return get_number(input_format_t::msgpack, number) and sax->number_unsigned(number);\n            }\n\n            case 0xCF: // uint 64\n            {\n                uint64_t number;\n                return get_number(input_format_t::msgpack, number) and sax->number_unsigned(number);\n            }\n\n            case 0xD0: // int 8\n            {\n                int8_t number;\n                return get_number(input_format_t::msgpack, number) and sax->number_integer(number);\n            }\n\n            case 0xD1: // int 16\n            {\n                int16_t number;\n                return get_number(input_format_t::msgpack, number) and sax->number_integer(number);\n            }\n\n            case 0xD2: // int 32\n            {\n                int32_t number;\n                return get_number(input_format_t::msgpack, number) and sax->number_integer(number);\n            }\n\n            case 0xD3: // int 64\n            {\n                int64_t number;\n                return get_number(input_format_t::msgpack, number) and sax->number_integer(number);\n            }\n\n            case 0xD9: // str 8\n            case 0xDA: // str 16\n            case 0xDB: // str 32\n            {\n                string_t s;\n                return get_msgpack_string(s) and sax->string(s);\n            }\n\n            case 0xDC: // array 16\n            {\n                uint16_t len;\n                return get_number(input_format_t::msgpack, len) and get_msgpack_array(static_cast<std::size_t>(len));\n            }\n\n            case 0xDD: // array 32\n            {\n                uint32_t len;\n                return get_number(input_format_t::msgpack, len) and get_msgpack_array(static_cast<std::size_t>(len));\n            }\n\n            case 0xDE: // map 16\n            {\n                uint16_t len;\n                return get_number(input_format_t::msgpack, len) and get_msgpack_object(static_cast<std::size_t>(len));\n            }\n\n            case 0xDF: // map 32\n            {\n                uint32_t len;\n                return get_number(input_format_t::msgpack, len) and get_msgpack_object(static_cast<std::size_t>(len));\n            }\n\n            // negative fixint\n            case 0xE0:\n            case 0xE1:\n            case 0xE2:\n            case 0xE3:\n            case 0xE4:\n            case 0xE5:\n            case 0xE6:\n            case 0xE7:\n            case 0xE8:\n            case 0xE9:\n            case 0xEA:\n            case 0xEB:\n            case 0xEC:\n            case 0xED:\n            case 0xEE:\n            case 0xEF:\n            case 0xF0:\n            case 0xF1:\n            case 0xF2:\n            case 0xF3:\n            case 0xF4:\n            case 0xF5:\n            case 0xF6:\n            case 0xF7:\n            case 0xF8:\n            case 0xF9:\n            case 0xFA:\n            case 0xFB:\n            case 0xFC:\n            case 0xFD:\n            case 0xFE:\n            case 0xFF:\n                return sax->number_integer(static_cast<int8_t>(current));\n\n            default: // anything else\n            {\n                auto last_token = get_token_string();\n                return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::msgpack, \"invalid byte: 0x\" + last_token, \"value\")));\n            }\n        }\n    }\n\n    /*!\n    @brief reads a MessagePack string\n\n    This function first reads starting bytes to determine the expected\n    string length and then copies this number of bytes into a string.\n\n    @param[out] result  created string\n\n    @return whether string creation completed\n    */\n    bool get_msgpack_string(string_t& result)\n    {\n        if (JSON_UNLIKELY(not unexpect_eof(input_format_t::msgpack, \"string\")))\n        {\n            return false;\n        }\n\n        switch (current)\n        {\n            // fixstr\n            case 0xA0:\n            case 0xA1:\n            case 0xA2:\n            case 0xA3:\n            case 0xA4:\n            case 0xA5:\n            case 0xA6:\n            case 0xA7:\n            case 0xA8:\n            case 0xA9:\n            case 0xAA:\n            case 0xAB:\n            case 0xAC:\n            case 0xAD:\n            case 0xAE:\n            case 0xAF:\n            case 0xB0:\n            case 0xB1:\n            case 0xB2:\n            case 0xB3:\n            case 0xB4:\n            case 0xB5:\n            case 0xB6:\n            case 0xB7:\n            case 0xB8:\n            case 0xB9:\n            case 0xBA:\n            case 0xBB:\n            case 0xBC:\n            case 0xBD:\n            case 0xBE:\n            case 0xBF:\n            {\n                return get_string(input_format_t::msgpack, current & 0x1F, result);\n            }\n\n            case 0xD9: // str 8\n            {\n                uint8_t len;\n                return get_number(input_format_t::msgpack, len) and get_string(input_format_t::msgpack, len, result);\n            }\n\n            case 0xDA: // str 16\n            {\n                uint16_t len;\n                return get_number(input_format_t::msgpack, len) and get_string(input_format_t::msgpack, len, result);\n            }\n\n            case 0xDB: // str 32\n            {\n                uint32_t len;\n                return get_number(input_format_t::msgpack, len) and get_string(input_format_t::msgpack, len, result);\n            }\n\n            default:\n            {\n                auto last_token = get_token_string();\n                return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::msgpack, \"expected length specification (0xA0-0xBF, 0xD9-0xDB); last byte: 0x\" + last_token, \"string\")));\n            }\n        }\n    }\n\n    /*!\n    @param[in] len  the length of the array\n    @return whether array creation completed\n    */\n    bool get_msgpack_array(const std::size_t len)\n    {\n        if (JSON_UNLIKELY(not sax->start_array(len)))\n        {\n            return false;\n        }\n\n        for (std::size_t i = 0; i < len; ++i)\n        {\n            if (JSON_UNLIKELY(not parse_msgpack_internal()))\n            {\n                return false;\n            }\n        }\n\n        return sax->end_array();\n    }\n\n    /*!\n    @param[in] len  the length of the object\n    @return whether object creation completed\n    */\n    bool get_msgpack_object(const std::size_t len)\n    {\n        if (JSON_UNLIKELY(not sax->start_object(len)))\n        {\n            return false;\n        }\n\n        string_t key;\n        for (std::size_t i = 0; i < len; ++i)\n        {\n            get();\n            if (JSON_UNLIKELY(not get_msgpack_string(key) or not sax->key(key)))\n            {\n                return false;\n            }\n\n            if (JSON_UNLIKELY(not parse_msgpack_internal()))\n            {\n                return false;\n            }\n            key.clear();\n        }\n\n        return sax->end_object();\n    }\n\n    ////////////\n    // UBJSON //\n    ////////////\n\n    /*!\n    @param[in] get_char  whether a new character should be retrieved from the\n                         input (true, default) or whether the last read\n                         character should be considered instead\n\n    @return whether a valid UBJSON value was passed to the SAX parser\n    */\n    bool parse_ubjson_internal(const bool get_char = true)\n    {\n        return get_ubjson_value(get_char ? get_ignore_noop() : current);\n    }\n\n    /*!\n    @brief reads a UBJSON string\n\n    This function is either called after reading the 'S' byte explicitly\n    indicating a string, or in case of an object key where the 'S' byte can be\n    left out.\n\n    @param[out] result   created string\n    @param[in] get_char  whether a new character should be retrieved from the\n                         input (true, default) or whether the last read\n                         character should be considered instead\n\n    @return whether string creation completed\n    */\n    bool get_ubjson_string(string_t& result, const bool get_char = true)\n    {\n        if (get_char)\n        {\n            get();  // TODO: may we ignore N here?\n        }\n\n        if (JSON_UNLIKELY(not unexpect_eof(input_format_t::ubjson, \"value\")))\n        {\n            return false;\n        }\n\n        switch (current)\n        {\n            case 'U':\n            {\n                uint8_t len;\n                return get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result);\n            }\n\n            case 'i':\n            {\n                int8_t len;\n                return get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result);\n            }\n\n            case 'I':\n            {\n                int16_t len;\n                return get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result);\n            }\n\n            case 'l':\n            {\n                int32_t len;\n                return get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result);\n            }\n\n            case 'L':\n            {\n                int64_t len;\n                return get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result);\n            }\n\n            default:\n                auto last_token = get_token_string();\n                return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::ubjson, \"expected length type specification (U, i, I, l, L); last byte: 0x\" + last_token, \"string\")));\n        }\n    }\n\n    /*!\n    @param[out] result  determined size\n    @return whether size determination completed\n    */\n    bool get_ubjson_size_value(std::size_t& result)\n    {\n        switch (get_ignore_noop())\n        {\n            case 'U':\n            {\n                uint8_t number;\n                if (JSON_UNLIKELY(not get_number(input_format_t::ubjson, number)))\n                {\n                    return false;\n                }\n                result = static_cast<std::size_t>(number);\n                return true;\n            }\n\n            case 'i':\n            {\n                int8_t number;\n                if (JSON_UNLIKELY(not get_number(input_format_t::ubjson, number)))\n                {\n                    return false;\n                }\n                result = static_cast<std::size_t>(number);\n                return true;\n            }\n\n            case 'I':\n            {\n                int16_t number;\n                if (JSON_UNLIKELY(not get_number(input_format_t::ubjson, number)))\n                {\n                    return false;\n                }\n                result = static_cast<std::size_t>(number);\n                return true;\n            }\n\n            case 'l':\n            {\n                int32_t number;\n                if (JSON_UNLIKELY(not get_number(input_format_t::ubjson, number)))\n                {\n                    return false;\n                }\n                result = static_cast<std::size_t>(number);\n                return true;\n            }\n\n            case 'L':\n            {\n                int64_t number;\n                if (JSON_UNLIKELY(not get_number(input_format_t::ubjson, number)))\n                {\n                    return false;\n                }\n                result = static_cast<std::size_t>(number);\n                return true;\n            }\n\n            default:\n            {\n                auto last_token = get_token_string();\n                return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::ubjson, \"expected length type specification (U, i, I, l, L) after '#'; last byte: 0x\" + last_token, \"size\")));\n            }\n        }\n    }\n\n    /*!\n    @brief determine the type and size for a container\n\n    In the optimized UBJSON format, a type and a size can be provided to allow\n    for a more compact representation.\n\n    @param[out] result  pair of the size and the type\n\n    @return whether pair creation completed\n    */\n    bool get_ubjson_size_type(std::pair<std::size_t, int>& result)\n    {\n        result.first = string_t::npos; // size\n        result.second = 0; // type\n\n        get_ignore_noop();\n\n        if (current == '$')\n        {\n            result.second = get();  // must not ignore 'N', because 'N' maybe the type\n            if (JSON_UNLIKELY(not unexpect_eof(input_format_t::ubjson, \"type\")))\n            {\n                return false;\n            }\n\n            get_ignore_noop();\n            if (JSON_UNLIKELY(current != '#'))\n            {\n                if (JSON_UNLIKELY(not unexpect_eof(input_format_t::ubjson, \"value\")))\n                {\n                    return false;\n                }\n                auto last_token = get_token_string();\n                return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::ubjson, \"expected '#' after type information; last byte: 0x\" + last_token, \"size\")));\n            }\n\n            return get_ubjson_size_value(result.first);\n        }\n        else if (current == '#')\n        {\n            return get_ubjson_size_value(result.first);\n        }\n        return true;\n    }\n\n    /*!\n    @param prefix  the previously read or set type prefix\n    @return whether value creation completed\n    */\n    bool get_ubjson_value(const int prefix)\n    {\n        switch (prefix)\n        {\n            case std::char_traits<char>::eof():  // EOF\n                return unexpect_eof(input_format_t::ubjson, \"value\");\n\n            case 'T':  // true\n                return sax->boolean(true);\n            case 'F':  // false\n                return sax->boolean(false);\n\n            case 'Z':  // null\n                return sax->null();\n\n            case 'U':\n            {\n                uint8_t number;\n                return get_number(input_format_t::ubjson, number) and sax->number_unsigned(number);\n            }\n\n            case 'i':\n            {\n                int8_t number;\n                return get_number(input_format_t::ubjson, number) and sax->number_integer(number);\n            }\n\n            case 'I':\n            {\n                int16_t number;\n                return get_number(input_format_t::ubjson, number) and sax->number_integer(number);\n            }\n\n            case 'l':\n            {\n                int32_t number;\n                return get_number(input_format_t::ubjson, number) and sax->number_integer(number);\n            }\n\n            case 'L':\n            {\n                int64_t number;\n                return get_number(input_format_t::ubjson, number) and sax->number_integer(number);\n            }\n\n            case 'd':\n            {\n                float number;\n                return get_number(input_format_t::ubjson, number) and sax->number_float(static_cast<number_float_t>(number), \"\");\n            }\n\n            case 'D':\n            {\n                double number;\n                return get_number(input_format_t::ubjson, number) and sax->number_float(static_cast<number_float_t>(number), \"\");\n            }\n\n            case 'C':  // char\n            {\n                get();\n                if (JSON_UNLIKELY(not unexpect_eof(input_format_t::ubjson, \"char\")))\n                {\n                    return false;\n                }\n                if (JSON_UNLIKELY(current > 127))\n                {\n                    auto last_token = get_token_string();\n                    return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::ubjson, \"byte after 'C' must be in range 0x00..0x7F; last byte: 0x\" + last_token, \"char\")));\n                }\n                string_t s(1, static_cast<char>(current));\n                return sax->string(s);\n            }\n\n            case 'S':  // string\n            {\n                string_t s;\n                return get_ubjson_string(s) and sax->string(s);\n            }\n\n            case '[':  // array\n                return get_ubjson_array();\n\n            case '{':  // object\n                return get_ubjson_object();\n\n            default: // anything else\n            {\n                auto last_token = get_token_string();\n                return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::ubjson, \"invalid byte: 0x\" + last_token, \"value\")));\n            }\n        }\n    }\n\n    /*!\n    @return whether array creation completed\n    */\n    bool get_ubjson_array()\n    {\n        std::pair<std::size_t, int> size_and_type;\n        if (JSON_UNLIKELY(not get_ubjson_size_type(size_and_type)))\n        {\n            return false;\n        }\n\n        if (size_and_type.first != string_t::npos)\n        {\n            if (JSON_UNLIKELY(not sax->start_array(size_and_type.first)))\n            {\n                return false;\n            }\n\n            if (size_and_type.second != 0)\n            {\n                if (size_and_type.second != 'N')\n                {\n                    for (std::size_t i = 0; i < size_and_type.first; ++i)\n                    {\n                        if (JSON_UNLIKELY(not get_ubjson_value(size_and_type.second)))\n                        {\n                            return false;\n                        }\n                    }\n                }\n            }\n            else\n            {\n                for (std::size_t i = 0; i < size_and_type.first; ++i)\n                {\n                    if (JSON_UNLIKELY(not parse_ubjson_internal()))\n                    {\n                        return false;\n                    }\n                }\n            }\n        }\n        else\n        {\n            if (JSON_UNLIKELY(not sax->start_array(std::size_t(-1))))\n            {\n                return false;\n            }\n\n            while (current != ']')\n            {\n                if (JSON_UNLIKELY(not parse_ubjson_internal(false)))\n                {\n                    return false;\n                }\n                get_ignore_noop();\n            }\n        }\n\n        return sax->end_array();\n    }\n\n    /*!\n    @return whether object creation completed\n    */\n    bool get_ubjson_object()\n    {\n        std::pair<std::size_t, int> size_and_type;\n        if (JSON_UNLIKELY(not get_ubjson_size_type(size_and_type)))\n        {\n            return false;\n        }\n\n        string_t key;\n        if (size_and_type.first != string_t::npos)\n        {\n            if (JSON_UNLIKELY(not sax->start_object(size_and_type.first)))\n            {\n                return false;\n            }\n\n            if (size_and_type.second != 0)\n            {\n                for (std::size_t i = 0; i < size_and_type.first; ++i)\n                {\n                    if (JSON_UNLIKELY(not get_ubjson_string(key) or not sax->key(key)))\n                    {\n                        return false;\n                    }\n                    if (JSON_UNLIKELY(not get_ubjson_value(size_and_type.second)))\n                    {\n                        return false;\n                    }\n                    key.clear();\n                }\n            }\n            else\n            {\n                for (std::size_t i = 0; i < size_and_type.first; ++i)\n                {\n                    if (JSON_UNLIKELY(not get_ubjson_string(key) or not sax->key(key)))\n                    {\n                        return false;\n                    }\n                    if (JSON_UNLIKELY(not parse_ubjson_internal()))\n                    {\n                        return false;\n                    }\n                    key.clear();\n                }\n            }\n        }\n        else\n        {\n            if (JSON_UNLIKELY(not sax->start_object(std::size_t(-1))))\n            {\n                return false;\n            }\n\n            while (current != '}')\n            {\n                if (JSON_UNLIKELY(not get_ubjson_string(key, false) or not sax->key(key)))\n                {\n                    return false;\n                }\n                if (JSON_UNLIKELY(not parse_ubjson_internal()))\n                {\n                    return false;\n                }\n                get_ignore_noop();\n                key.clear();\n            }\n        }\n\n        return sax->end_object();\n    }\n\n    ///////////////////////\n    // Utility functions //\n    ///////////////////////\n\n    /*!\n    @brief get next character from the input\n\n    This function provides the interface to the used input adapter. It does\n    not throw in case the input reached EOF, but returns a -'ve valued\n    `std::char_traits<char>::eof()` in that case.\n\n    @return character read from the input\n    */\n    int get()\n    {\n        ++chars_read;\n        return (current = ia->get_character());\n    }\n\n    /*!\n    @return character read from the input after ignoring all 'N' entries\n    */\n    int get_ignore_noop()\n    {\n        do\n        {\n            get();\n        }\n        while (current == 'N');\n\n        return current;\n    }\n\n    /*\n    @brief read a number from the input\n\n    @tparam NumberType the type of the number\n    @param[in] format   the current format (for diagnostics)\n    @param[out] result  number of type @a NumberType\n\n    @return whether conversion completed\n\n    @note This function needs to respect the system's endianess, because\n          bytes in CBOR, MessagePack, and UBJSON are stored in network order\n          (big endian) and therefore need reordering on little endian systems.\n    */\n    template<typename NumberType, bool InputIsLittleEndian = false>\n    bool get_number(const input_format_t format, NumberType& result)\n    {\n        // step 1: read input into array with system's byte order\n        std::array<uint8_t, sizeof(NumberType)> vec;\n        for (std::size_t i = 0; i < sizeof(NumberType); ++i)\n        {\n            get();\n            if (JSON_UNLIKELY(not unexpect_eof(format, \"number\")))\n            {\n                return false;\n            }\n\n            // reverse byte order prior to conversion if necessary\n            if (is_little_endian && !InputIsLittleEndian)\n            {\n                vec[sizeof(NumberType) - i - 1] = static_cast<uint8_t>(current);\n            }\n            else\n            {\n                vec[i] = static_cast<uint8_t>(current); // LCOV_EXCL_LINE\n            }\n        }\n\n        // step 2: convert array into number of type T and return\n        std::memcpy(&result, vec.data(), sizeof(NumberType));\n        return true;\n    }\n\n    /*!\n    @brief create a string by reading characters from the input\n\n    @tparam NumberType the type of the number\n    @param[in] format the current format (for diagnostics)\n    @param[in] len number of characters to read\n    @param[out] result string created by reading @a len bytes\n\n    @return whether string creation completed\n\n    @note We can not reserve @a len bytes for the result, because @a len\n          may be too large. Usually, @ref unexpect_eof() detects the end of\n          the input before we run out of string memory.\n    */\n    template<typename NumberType>\n    bool get_string(const input_format_t format,\n                    const NumberType len,\n                    string_t& result)\n    {\n        bool success = true;\n        std::generate_n(std::back_inserter(result), len, [this, &success, &format]()\n        {\n            get();\n            if (JSON_UNLIKELY(not unexpect_eof(format, \"string\")))\n            {\n                success = false;\n            }\n            return static_cast<char>(current);\n        });\n        return success;\n    }\n\n    /*!\n    @param[in] format   the current format (for diagnostics)\n    @param[in] context  further context information (for diagnostics)\n    @return whether the last read character is not EOF\n    */\n    bool unexpect_eof(const input_format_t format, const char* context) const\n    {\n        if (JSON_UNLIKELY(current == std::char_traits<char>::eof()))\n        {\n            return sax->parse_error(chars_read, \"<end of file>\",\n                                    parse_error::create(110, chars_read, exception_message(format, \"unexpected end of input\", context)));\n        }\n        return true;\n    }\n\n    /*!\n    @return a string representation of the last read byte\n    */\n    std::string get_token_string() const\n    {\n        char cr[3];\n        (std::snprintf)(cr, 3, \"%.2hhX\", static_cast<unsigned char>(current));\n        return std::string{cr};\n    }\n\n    /*!\n    @param[in] format   the current format\n    @param[in] detail   a detailed error message\n    @param[in] context  further contect information\n    @return a message string to use in the parse_error exceptions\n    */\n    std::string exception_message(const input_format_t format,\n                                  const std::string& detail,\n                                  const std::string& context) const\n    {\n        std::string error_msg = \"syntax error while parsing \";\n\n        switch (format)\n        {\n            case input_format_t::cbor:\n                error_msg += \"CBOR\";\n                break;\n\n            case input_format_t::msgpack:\n                error_msg += \"MessagePack\";\n                break;\n\n            case input_format_t::ubjson:\n                error_msg += \"UBJSON\";\n                break;\n\n            case input_format_t::bson:\n                error_msg += \"BSON\";\n                break;\n\n            // LCOV_EXCL_START\n            default:\n                assert(false);\n                // LCOV_EXCL_STOP\n        }\n\n        return error_msg + \" \" + context + \": \" + detail;\n    }\n\n  private:\n    /// input adapter\n    input_adapter_t ia = nullptr;\n\n    /// the current character\n    int current = std::char_traits<char>::eof();\n\n    /// the number of characters read\n    std::size_t chars_read = 0;\n\n    /// whether we can assume little endianess\n    const bool is_little_endian = little_endianess();\n\n    /// the SAX parser\n    json_sax_t* sax = nullptr;\n};\n}  // namespace detail\n}  // namespace nlohmann\n"
  },
  {
    "path": "nlohmann_json/include/nlohmann/detail/input/input_adapters.hpp",
    "content": "#pragma once\n\n#include <cassert> // assert\n#include <cstddef> // size_t\n#include <cstring> // strlen\n#include <istream> // istream\n#include <iterator> // begin, end, iterator_traits, random_access_iterator_tag, distance, next\n#include <memory> // shared_ptr, make_shared, addressof\n#include <numeric> // accumulate\n#include <string> // string, char_traits\n#include <type_traits> // enable_if, is_base_of, is_pointer, is_integral, remove_pointer\n#include <utility> // pair, declval\n#include <cstdio> //FILE *\n\n#include <nlohmann/detail/macro_scope.hpp>\n\nnamespace nlohmann\n{\nnamespace detail\n{\n/// the supported input formats\nenum class input_format_t { json, cbor, msgpack, ubjson, bson };\n\n////////////////////\n// input adapters //\n////////////////////\n\n/*!\n@brief abstract input adapter interface\n\nProduces a stream of std::char_traits<char>::int_type characters from a\nstd::istream, a buffer, or some other input type. Accepts the return of\nexactly one non-EOF character for future input. The int_type characters\nreturned consist of all valid char values as positive values (typically\nunsigned char), plus an EOF value outside that range, specified by the value\nof the function std::char_traits<char>::eof(). This value is typically -1, but\ncould be any arbitrary value which is not a valid char value.\n*/\nstruct input_adapter_protocol\n{\n    /// get a character [0,255] or std::char_traits<char>::eof().\n    virtual std::char_traits<char>::int_type get_character() = 0;\n    virtual ~input_adapter_protocol() = default;\n};\n\n/// a type to simplify interfaces\nusing input_adapter_t = std::shared_ptr<input_adapter_protocol>;\n\n/*!\nInput adapter for stdio file access. This adapter read only 1 byte and do not use any\n buffer. This adapter is a very low level adapter.\n*/\nclass file_input_adapter : public input_adapter_protocol\n{\n  public:\n    explicit file_input_adapter(std::FILE* f)  noexcept\n        : m_file(f)\n    {}\n\n    std::char_traits<char>::int_type get_character() noexcept override\n    {\n        return std::fgetc(m_file);\n    }\n  private:\n    /// the file pointer to read from\n    std::FILE* m_file;\n};\n\n\n/*!\nInput adapter for a (caching) istream. Ignores a UFT Byte Order Mark at\nbeginning of input. Does not support changing the underlying std::streambuf\nin mid-input. Maintains underlying std::istream and std::streambuf to support\nsubsequent use of standard std::istream operations to process any input\ncharacters following those used in parsing the JSON input.  Clears the\nstd::istream flags; any input errors (e.g., EOF) will be detected by the first\nsubsequent call for input from the std::istream.\n*/\nclass input_stream_adapter : public input_adapter_protocol\n{\n  public:\n    ~input_stream_adapter() override\n    {\n        // clear stream flags; we use underlying streambuf I/O, do not\n        // maintain ifstream flags, except eof\n        is.clear(is.rdstate() & std::ios::eofbit);\n    }\n\n    explicit input_stream_adapter(std::istream& i)\n        : is(i), sb(*i.rdbuf())\n    {}\n\n    // delete because of pointer members\n    input_stream_adapter(const input_stream_adapter&) = delete;\n    input_stream_adapter& operator=(input_stream_adapter&) = delete;\n    input_stream_adapter(input_stream_adapter&&) = delete;\n    input_stream_adapter& operator=(input_stream_adapter&&) = delete;\n\n    // std::istream/std::streambuf use std::char_traits<char>::to_int_type, to\n    // ensure that std::char_traits<char>::eof() and the character 0xFF do not\n    // end up as the same value, eg. 0xFFFFFFFF.\n    std::char_traits<char>::int_type get_character() override\n    {\n        auto res = sb.sbumpc();\n        // set eof manually, as we don't use the istream interface.\n        if (res == EOF)\n        {\n            is.clear(is.rdstate() | std::ios::eofbit);\n        }\n        return res;\n    }\n\n  private:\n    /// the associated input stream\n    std::istream& is;\n    std::streambuf& sb;\n};\n\n/// input adapter for buffer input\nclass input_buffer_adapter : public input_adapter_protocol\n{\n  public:\n    input_buffer_adapter(const char* b, const std::size_t l) noexcept\n        : cursor(b), limit(b + l)\n    {}\n\n    // delete because of pointer members\n    input_buffer_adapter(const input_buffer_adapter&) = delete;\n    input_buffer_adapter& operator=(input_buffer_adapter&) = delete;\n    input_buffer_adapter(input_buffer_adapter&&) = delete;\n    input_buffer_adapter& operator=(input_buffer_adapter&&) = delete;\n    ~input_buffer_adapter() override = default;\n\n    std::char_traits<char>::int_type get_character() noexcept override\n    {\n        if (JSON_LIKELY(cursor < limit))\n        {\n            return std::char_traits<char>::to_int_type(*(cursor++));\n        }\n\n        return std::char_traits<char>::eof();\n    }\n\n  private:\n    /// pointer to the current character\n    const char* cursor;\n    /// pointer past the last character\n    const char* const limit;\n};\n\ntemplate<typename WideStringType, size_t T>\nstruct wide_string_input_helper\n{\n    // UTF-32\n    static void fill_buffer(const WideStringType& str, size_t& current_wchar, std::array<std::char_traits<char>::int_type, 4>& utf8_bytes, size_t& utf8_bytes_index, size_t& utf8_bytes_filled)\n    {\n        utf8_bytes_index = 0;\n\n        if (current_wchar == str.size())\n        {\n            utf8_bytes[0] = std::char_traits<char>::eof();\n            utf8_bytes_filled = 1;\n        }\n        else\n        {\n            // get the current character\n            const auto wc = static_cast<int>(str[current_wchar++]);\n\n            // UTF-32 to UTF-8 encoding\n            if (wc < 0x80)\n            {\n                utf8_bytes[0] = wc;\n                utf8_bytes_filled = 1;\n            }\n            else if (wc <= 0x7FF)\n            {\n                utf8_bytes[0] = 0xC0 | ((wc >> 6) & 0x1F);\n                utf8_bytes[1] = 0x80 | (wc & 0x3F);\n                utf8_bytes_filled = 2;\n            }\n            else if (wc <= 0xFFFF)\n            {\n                utf8_bytes[0] = 0xE0 | ((wc >> 12) & 0x0F);\n                utf8_bytes[1] = 0x80 | ((wc >> 6) & 0x3F);\n                utf8_bytes[2] = 0x80 | (wc & 0x3F);\n                utf8_bytes_filled = 3;\n            }\n            else if (wc <= 0x10FFFF)\n            {\n                utf8_bytes[0] = 0xF0 | ((wc >> 18) & 0x07);\n                utf8_bytes[1] = 0x80 | ((wc >> 12) & 0x3F);\n                utf8_bytes[2] = 0x80 | ((wc >> 6) & 0x3F);\n                utf8_bytes[3] = 0x80 | (wc & 0x3F);\n                utf8_bytes_filled = 4;\n            }\n            else\n            {\n                // unknown character\n                utf8_bytes[0] = wc;\n                utf8_bytes_filled = 1;\n            }\n        }\n    }\n};\n\ntemplate<typename WideStringType>\nstruct wide_string_input_helper<WideStringType, 2>\n{\n    // UTF-16\n    static void fill_buffer(const WideStringType& str, size_t& current_wchar, std::array<std::char_traits<char>::int_type, 4>& utf8_bytes, size_t& utf8_bytes_index, size_t& utf8_bytes_filled)\n    {\n        utf8_bytes_index = 0;\n\n        if (current_wchar == str.size())\n        {\n            utf8_bytes[0] = std::char_traits<char>::eof();\n            utf8_bytes_filled = 1;\n        }\n        else\n        {\n            // get the current character\n            const auto wc = static_cast<int>(str[current_wchar++]);\n\n            // UTF-16 to UTF-8 encoding\n            if (wc < 0x80)\n            {\n                utf8_bytes[0] = wc;\n                utf8_bytes_filled = 1;\n            }\n            else if (wc <= 0x7FF)\n            {\n                utf8_bytes[0] = 0xC0 | ((wc >> 6));\n                utf8_bytes[1] = 0x80 | (wc & 0x3F);\n                utf8_bytes_filled = 2;\n            }\n            else if (0xD800 > wc or wc >= 0xE000)\n            {\n                utf8_bytes[0] = 0xE0 | ((wc >> 12));\n                utf8_bytes[1] = 0x80 | ((wc >> 6) & 0x3F);\n                utf8_bytes[2] = 0x80 | (wc & 0x3F);\n                utf8_bytes_filled = 3;\n            }\n            else\n            {\n                if (current_wchar < str.size())\n                {\n                    const auto wc2 = static_cast<int>(str[current_wchar++]);\n                    const int charcode = 0x10000 + (((wc & 0x3FF) << 10) | (wc2 & 0x3FF));\n                    utf8_bytes[0] = 0xf0 | (charcode >> 18);\n                    utf8_bytes[1] = 0x80 | ((charcode >> 12) & 0x3F);\n                    utf8_bytes[2] = 0x80 | ((charcode >> 6) & 0x3F);\n                    utf8_bytes[3] = 0x80 | (charcode & 0x3F);\n                    utf8_bytes_filled = 4;\n                }\n                else\n                {\n                    // unknown character\n                    ++current_wchar;\n                    utf8_bytes[0] = wc;\n                    utf8_bytes_filled = 1;\n                }\n            }\n        }\n    }\n};\n\ntemplate<typename WideStringType>\nclass wide_string_input_adapter : public input_adapter_protocol\n{\n  public:\n    explicit wide_string_input_adapter(const WideStringType& w)  noexcept\n        : str(w)\n    {}\n\n    std::char_traits<char>::int_type get_character() noexcept override\n    {\n        // check if buffer needs to be filled\n        if (utf8_bytes_index == utf8_bytes_filled)\n        {\n            fill_buffer<sizeof(typename WideStringType::value_type)>();\n\n            assert(utf8_bytes_filled > 0);\n            assert(utf8_bytes_index == 0);\n        }\n\n        // use buffer\n        assert(utf8_bytes_filled > 0);\n        assert(utf8_bytes_index < utf8_bytes_filled);\n        return utf8_bytes[utf8_bytes_index++];\n    }\n\n  private:\n    template<size_t T>\n    void fill_buffer()\n    {\n        wide_string_input_helper<WideStringType, T>::fill_buffer(str, current_wchar, utf8_bytes, utf8_bytes_index, utf8_bytes_filled);\n    }\n\n    /// the wstring to process\n    const WideStringType& str;\n\n    /// index of the current wchar in str\n    std::size_t current_wchar = 0;\n\n    /// a buffer for UTF-8 bytes\n    std::array<std::char_traits<char>::int_type, 4> utf8_bytes = {{0, 0, 0, 0}};\n\n    /// index to the utf8_codes array for the next valid byte\n    std::size_t utf8_bytes_index = 0;\n    /// number of valid bytes in the utf8_codes array\n    std::size_t utf8_bytes_filled = 0;\n};\n\nclass input_adapter\n{\n  public:\n    // native support\n    input_adapter(std::FILE* file)\n        : ia(std::make_shared<file_input_adapter>(file)) {}\n    /// input adapter for input stream\n    input_adapter(std::istream& i)\n        : ia(std::make_shared<input_stream_adapter>(i)) {}\n\n    /// input adapter for input stream\n    input_adapter(std::istream&& i)\n        : ia(std::make_shared<input_stream_adapter>(i)) {}\n\n    input_adapter(const std::wstring& ws)\n        : ia(std::make_shared<wide_string_input_adapter<std::wstring>>(ws)) {}\n\n    input_adapter(const std::u16string& ws)\n        : ia(std::make_shared<wide_string_input_adapter<std::u16string>>(ws)) {}\n\n    input_adapter(const std::u32string& ws)\n        : ia(std::make_shared<wide_string_input_adapter<std::u32string>>(ws)) {}\n\n    /// input adapter for buffer\n    template<typename CharT,\n             typename std::enable_if<\n                 std::is_pointer<CharT>::value and\n                 std::is_integral<typename std::remove_pointer<CharT>::type>::value and\n                 sizeof(typename std::remove_pointer<CharT>::type) == 1,\n                 int>::type = 0>\n    input_adapter(CharT b, std::size_t l)\n        : ia(std::make_shared<input_buffer_adapter>(reinterpret_cast<const char*>(b), l)) {}\n\n    // derived support\n\n    /// input adapter for string literal\n    template<typename CharT,\n             typename std::enable_if<\n                 std::is_pointer<CharT>::value and\n                 std::is_integral<typename std::remove_pointer<CharT>::type>::value and\n                 sizeof(typename std::remove_pointer<CharT>::type) == 1,\n                 int>::type = 0>\n    input_adapter(CharT b)\n        : input_adapter(reinterpret_cast<const char*>(b),\n                        std::strlen(reinterpret_cast<const char*>(b))) {}\n\n    /// input adapter for iterator range with contiguous storage\n    template<class IteratorType,\n             typename std::enable_if<\n                 std::is_same<typename iterator_traits<IteratorType>::iterator_category, std::random_access_iterator_tag>::value,\n                 int>::type = 0>\n    input_adapter(IteratorType first, IteratorType last)\n    {\n#ifndef NDEBUG\n        // assertion to check that the iterator range is indeed contiguous,\n        // see http://stackoverflow.com/a/35008842/266378 for more discussion\n        const auto is_contiguous = std::accumulate(\n                                       first, last, std::pair<bool, int>(true, 0),\n                                       [&first](std::pair<bool, int> res, decltype(*first) val)\n        {\n            res.first &= (val == *(std::next(std::addressof(*first), res.second++)));\n            return res;\n        }).first;\n        assert(is_contiguous);\n#endif\n\n        // assertion to check that each element is 1 byte long\n        static_assert(\n            sizeof(typename iterator_traits<IteratorType>::value_type) == 1,\n            \"each element in the iterator range must have the size of 1 byte\");\n\n        const auto len = static_cast<size_t>(std::distance(first, last));\n        if (JSON_LIKELY(len > 0))\n        {\n            // there is at least one element: use the address of first\n            ia = std::make_shared<input_buffer_adapter>(reinterpret_cast<const char*>(&(*first)), len);\n        }\n        else\n        {\n            // the address of first cannot be used: use nullptr\n            ia = std::make_shared<input_buffer_adapter>(nullptr, len);\n        }\n    }\n\n    /// input adapter for array\n    template<class T, std::size_t N>\n    input_adapter(T (&array)[N])\n        : input_adapter(std::begin(array), std::end(array)) {}\n\n    /// input adapter for contiguous container\n    template<class ContiguousContainer, typename\n             std::enable_if<not std::is_pointer<ContiguousContainer>::value and\n                            std::is_base_of<std::random_access_iterator_tag, typename iterator_traits<decltype(std::begin(std::declval<ContiguousContainer const>()))>::iterator_category>::value,\n                            int>::type = 0>\n    input_adapter(const ContiguousContainer& c)\n        : input_adapter(std::begin(c), std::end(c)) {}\n\n    operator input_adapter_t()\n    {\n        return ia;\n    }\n\n  private:\n    /// the actual adapter\n    input_adapter_t ia = nullptr;\n};\n}  // namespace detail\n}  // namespace nlohmann\n"
  },
  {
    "path": "nlohmann_json/include/nlohmann/detail/input/json_sax.hpp",
    "content": "#pragma once\n\n#include <cstddef>\n#include <string>\n#include <vector>\n\n#include <nlohmann/detail/input/parser.hpp>\n#include <nlohmann/detail/exceptions.hpp>\n\nnamespace nlohmann\n{\n\n/*!\n@brief SAX interface\n\nThis class describes the SAX interface used by @ref nlohmann::json::sax_parse.\nEach function is called in different situations while the input is parsed. The\nboolean return value informs the parser whether to continue processing the\ninput.\n*/\ntemplate<typename BasicJsonType>\nstruct json_sax\n{\n    /// type for (signed) integers\n    using number_integer_t = typename BasicJsonType::number_integer_t;\n    /// type for unsigned integers\n    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n    /// type for floating-point numbers\n    using number_float_t = typename BasicJsonType::number_float_t;\n    /// type for strings\n    using string_t = typename BasicJsonType::string_t;\n\n    /*!\n    @brief a null value was read\n    @return whether parsing should proceed\n    */\n    virtual bool null() = 0;\n\n    /*!\n    @brief a boolean value was read\n    @param[in] val  boolean value\n    @return whether parsing should proceed\n    */\n    virtual bool boolean(bool val) = 0;\n\n    /*!\n    @brief an integer number was read\n    @param[in] val  integer value\n    @return whether parsing should proceed\n    */\n    virtual bool number_integer(number_integer_t val) = 0;\n\n    /*!\n    @brief an unsigned integer number was read\n    @param[in] val  unsigned integer value\n    @return whether parsing should proceed\n    */\n    virtual bool number_unsigned(number_unsigned_t val) = 0;\n\n    /*!\n    @brief an floating-point number was read\n    @param[in] val  floating-point value\n    @param[in] s    raw token value\n    @return whether parsing should proceed\n    */\n    virtual bool number_float(number_float_t val, const string_t& s) = 0;\n\n    /*!\n    @brief a string was read\n    @param[in] val  string value\n    @return whether parsing should proceed\n    @note It is safe to move the passed string.\n    */\n    virtual bool string(string_t& val) = 0;\n\n    /*!\n    @brief the beginning of an object was read\n    @param[in] elements  number of object elements or -1 if unknown\n    @return whether parsing should proceed\n    @note binary formats may report the number of elements\n    */\n    virtual bool start_object(std::size_t elements) = 0;\n\n    /*!\n    @brief an object key was read\n    @param[in] val  object key\n    @return whether parsing should proceed\n    @note It is safe to move the passed string.\n    */\n    virtual bool key(string_t& val) = 0;\n\n    /*!\n    @brief the end of an object was read\n    @return whether parsing should proceed\n    */\n    virtual bool end_object() = 0;\n\n    /*!\n    @brief the beginning of an array was read\n    @param[in] elements  number of array elements or -1 if unknown\n    @return whether parsing should proceed\n    @note binary formats may report the number of elements\n    */\n    virtual bool start_array(std::size_t elements) = 0;\n\n    /*!\n    @brief the end of an array was read\n    @return whether parsing should proceed\n    */\n    virtual bool end_array() = 0;\n\n    /*!\n    @brief a parse error occurred\n    @param[in] position    the position in the input where the error occurs\n    @param[in] last_token  the last read token\n    @param[in] ex          an exception object describing the error\n    @return whether parsing should proceed (must return false)\n    */\n    virtual bool parse_error(std::size_t position,\n                             const std::string& last_token,\n                             const detail::exception& ex) = 0;\n\n    virtual ~json_sax() = default;\n};\n\n\nnamespace detail\n{\n/*!\n@brief SAX implementation to create a JSON value from SAX events\n\nThis class implements the @ref json_sax interface and processes the SAX events\nto create a JSON value which makes it basically a DOM parser. The structure or\nhierarchy of the JSON value is managed by the stack `ref_stack` which contains\na pointer to the respective array or object for each recursion depth.\n\nAfter successful parsing, the value that is passed by reference to the\nconstructor contains the parsed value.\n\n@tparam BasicJsonType  the JSON type\n*/\ntemplate<typename BasicJsonType>\nclass json_sax_dom_parser\n{\n  public:\n    using number_integer_t = typename BasicJsonType::number_integer_t;\n    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n    using number_float_t = typename BasicJsonType::number_float_t;\n    using string_t = typename BasicJsonType::string_t;\n\n    /*!\n    @param[in, out] r  reference to a JSON value that is manipulated while\n                       parsing\n    @param[in] allow_exceptions_  whether parse errors yield exceptions\n    */\n    explicit json_sax_dom_parser(BasicJsonType& r, const bool allow_exceptions_ = true)\n        : root(r), allow_exceptions(allow_exceptions_)\n    {}\n\n    bool null()\n    {\n        handle_value(nullptr);\n        return true;\n    }\n\n    bool boolean(bool val)\n    {\n        handle_value(val);\n        return true;\n    }\n\n    bool number_integer(number_integer_t val)\n    {\n        handle_value(val);\n        return true;\n    }\n\n    bool number_unsigned(number_unsigned_t val)\n    {\n        handle_value(val);\n        return true;\n    }\n\n    bool number_float(number_float_t val, const string_t& /*unused*/)\n    {\n        handle_value(val);\n        return true;\n    }\n\n    bool string(string_t& val)\n    {\n        handle_value(val);\n        return true;\n    }\n\n    bool start_object(std::size_t len)\n    {\n        ref_stack.push_back(handle_value(BasicJsonType::value_t::object));\n\n        if (JSON_UNLIKELY(len != std::size_t(-1) and len > ref_stack.back()->max_size()))\n        {\n            JSON_THROW(out_of_range::create(408,\n                                            \"excessive object size: \" + std::to_string(len)));\n        }\n\n        return true;\n    }\n\n    bool key(string_t& val)\n    {\n        // add null at given key and store the reference for later\n        object_element = &(ref_stack.back()->m_value.object->operator[](val));\n        return true;\n    }\n\n    bool end_object()\n    {\n        ref_stack.pop_back();\n        return true;\n    }\n\n    bool start_array(std::size_t len)\n    {\n        ref_stack.push_back(handle_value(BasicJsonType::value_t::array));\n\n        if (JSON_UNLIKELY(len != std::size_t(-1) and len > ref_stack.back()->max_size()))\n        {\n            JSON_THROW(out_of_range::create(408,\n                                            \"excessive array size: \" + std::to_string(len)));\n        }\n\n        return true;\n    }\n\n    bool end_array()\n    {\n        ref_stack.pop_back();\n        return true;\n    }\n\n    bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/,\n                     const detail::exception& ex)\n    {\n        errored = true;\n        if (allow_exceptions)\n        {\n            // determine the proper exception type from the id\n            switch ((ex.id / 100) % 100)\n            {\n                case 1:\n                    JSON_THROW(*reinterpret_cast<const detail::parse_error*>(&ex));\n                case 4:\n                    JSON_THROW(*reinterpret_cast<const detail::out_of_range*>(&ex));\n                // LCOV_EXCL_START\n                case 2:\n                    JSON_THROW(*reinterpret_cast<const detail::invalid_iterator*>(&ex));\n                case 3:\n                    JSON_THROW(*reinterpret_cast<const detail::type_error*>(&ex));\n                case 5:\n                    JSON_THROW(*reinterpret_cast<const detail::other_error*>(&ex));\n                default:\n                    assert(false);\n                    // LCOV_EXCL_STOP\n            }\n        }\n        return false;\n    }\n\n    constexpr bool is_errored() const\n    {\n        return errored;\n    }\n\n  private:\n    /*!\n    @invariant If the ref stack is empty, then the passed value will be the new\n               root.\n    @invariant If the ref stack contains a value, then it is an array or an\n               object to which we can add elements\n    */\n    template<typename Value>\n    BasicJsonType* handle_value(Value&& v)\n    {\n        if (ref_stack.empty())\n        {\n            root = BasicJsonType(std::forward<Value>(v));\n            return &root;\n        }\n\n        assert(ref_stack.back()->is_array() or ref_stack.back()->is_object());\n\n        if (ref_stack.back()->is_array())\n        {\n            ref_stack.back()->m_value.array->emplace_back(std::forward<Value>(v));\n            return &(ref_stack.back()->m_value.array->back());\n        }\n        else\n        {\n            assert(object_element);\n            *object_element = BasicJsonType(std::forward<Value>(v));\n            return object_element;\n        }\n    }\n\n    /// the parsed JSON value\n    BasicJsonType& root;\n    /// stack to model hierarchy of values\n    std::vector<BasicJsonType*> ref_stack;\n    /// helper to hold the reference for the next object element\n    BasicJsonType* object_element = nullptr;\n    /// whether a syntax error occurred\n    bool errored = false;\n    /// whether to throw exceptions in case of errors\n    const bool allow_exceptions = true;\n};\n\ntemplate<typename BasicJsonType>\nclass json_sax_dom_callback_parser\n{\n  public:\n    using number_integer_t = typename BasicJsonType::number_integer_t;\n    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n    using number_float_t = typename BasicJsonType::number_float_t;\n    using string_t = typename BasicJsonType::string_t;\n    using parser_callback_t = typename BasicJsonType::parser_callback_t;\n    using parse_event_t = typename BasicJsonType::parse_event_t;\n\n    json_sax_dom_callback_parser(BasicJsonType& r,\n                                 const parser_callback_t cb,\n                                 const bool allow_exceptions_ = true)\n        : root(r), callback(cb), allow_exceptions(allow_exceptions_)\n    {\n        keep_stack.push_back(true);\n    }\n\n    bool null()\n    {\n        handle_value(nullptr);\n        return true;\n    }\n\n    bool boolean(bool val)\n    {\n        handle_value(val);\n        return true;\n    }\n\n    bool number_integer(number_integer_t val)\n    {\n        handle_value(val);\n        return true;\n    }\n\n    bool number_unsigned(number_unsigned_t val)\n    {\n        handle_value(val);\n        return true;\n    }\n\n    bool number_float(number_float_t val, const string_t& /*unused*/)\n    {\n        handle_value(val);\n        return true;\n    }\n\n    bool string(string_t& val)\n    {\n        handle_value(val);\n        return true;\n    }\n\n    bool start_object(std::size_t len)\n    {\n        // check callback for object start\n        const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::object_start, discarded);\n        keep_stack.push_back(keep);\n\n        auto val = handle_value(BasicJsonType::value_t::object, true);\n        ref_stack.push_back(val.second);\n\n        // check object limit\n        if (ref_stack.back())\n        {\n            if (JSON_UNLIKELY(len != std::size_t(-1) and len > ref_stack.back()->max_size()))\n            {\n                JSON_THROW(out_of_range::create(408,\n                                                \"excessive object size: \" + std::to_string(len)));\n            }\n        }\n\n        return true;\n    }\n\n    bool key(string_t& val)\n    {\n        BasicJsonType k = BasicJsonType(val);\n\n        // check callback for key\n        const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::key, k);\n        key_keep_stack.push_back(keep);\n\n        // add discarded value at given key and store the reference for later\n        if (keep and ref_stack.back())\n        {\n            object_element = &(ref_stack.back()->m_value.object->operator[](val) = discarded);\n        }\n\n        return true;\n    }\n\n    bool end_object()\n    {\n        if (ref_stack.back())\n        {\n            if (not callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::object_end, *ref_stack.back()))\n            {\n                // discard object\n                *ref_stack.back() = discarded;\n            }\n        }\n\n        assert(not ref_stack.empty());\n        assert(not keep_stack.empty());\n        ref_stack.pop_back();\n        keep_stack.pop_back();\n\n        if (not ref_stack.empty() and ref_stack.back())\n        {\n            // remove discarded value\n            if (ref_stack.back()->is_object())\n            {\n                for (auto it = ref_stack.back()->begin(); it != ref_stack.back()->end(); ++it)\n                {\n                    if (it->is_discarded())\n                    {\n                        ref_stack.back()->erase(it);\n                        break;\n                    }\n                }\n            }\n        }\n\n        return true;\n    }\n\n    bool start_array(std::size_t len)\n    {\n        const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::array_start, discarded);\n        keep_stack.push_back(keep);\n\n        auto val = handle_value(BasicJsonType::value_t::array, true);\n        ref_stack.push_back(val.second);\n\n        // check array limit\n        if (ref_stack.back())\n        {\n            if (JSON_UNLIKELY(len != std::size_t(-1) and len > ref_stack.back()->max_size()))\n            {\n                JSON_THROW(out_of_range::create(408,\n                                                \"excessive array size: \" + std::to_string(len)));\n            }\n        }\n\n        return true;\n    }\n\n    bool end_array()\n    {\n        bool keep = true;\n\n        if (ref_stack.back())\n        {\n            keep = callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::array_end, *ref_stack.back());\n            if (not keep)\n            {\n                // discard array\n                *ref_stack.back() = discarded;\n            }\n        }\n\n        assert(not ref_stack.empty());\n        assert(not keep_stack.empty());\n        ref_stack.pop_back();\n        keep_stack.pop_back();\n\n        // remove discarded value\n        if (not keep and not ref_stack.empty())\n        {\n            if (ref_stack.back()->is_array())\n            {\n                ref_stack.back()->m_value.array->pop_back();\n            }\n        }\n\n        return true;\n    }\n\n    bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/,\n                     const detail::exception& ex)\n    {\n        errored = true;\n        if (allow_exceptions)\n        {\n            // determine the proper exception type from the id\n            switch ((ex.id / 100) % 100)\n            {\n                case 1:\n                    JSON_THROW(*reinterpret_cast<const detail::parse_error*>(&ex));\n                case 4:\n                    JSON_THROW(*reinterpret_cast<const detail::out_of_range*>(&ex));\n                // LCOV_EXCL_START\n                case 2:\n                    JSON_THROW(*reinterpret_cast<const detail::invalid_iterator*>(&ex));\n                case 3:\n                    JSON_THROW(*reinterpret_cast<const detail::type_error*>(&ex));\n                case 5:\n                    JSON_THROW(*reinterpret_cast<const detail::other_error*>(&ex));\n                default:\n                    assert(false);\n                    // LCOV_EXCL_STOP\n            }\n        }\n        return false;\n    }\n\n    constexpr bool is_errored() const\n    {\n        return errored;\n    }\n\n  private:\n    /*!\n    @param[in] v  value to add to the JSON value we build during parsing\n    @param[in] skip_callback  whether we should skip calling the callback\n               function; this is required after start_array() and\n               start_object() SAX events, because otherwise we would call the\n               callback function with an empty array or object, respectively.\n\n    @invariant If the ref stack is empty, then the passed value will be the new\n               root.\n    @invariant If the ref stack contains a value, then it is an array or an\n               object to which we can add elements\n\n    @return pair of boolean (whether value should be kept) and pointer (to the\n            passed value in the ref_stack hierarchy; nullptr if not kept)\n    */\n    template<typename Value>\n    std::pair<bool, BasicJsonType*> handle_value(Value&& v, const bool skip_callback = false)\n    {\n        assert(not keep_stack.empty());\n\n        // do not handle this value if we know it would be added to a discarded\n        // container\n        if (not keep_stack.back())\n        {\n            return {false, nullptr};\n        }\n\n        // create value\n        auto value = BasicJsonType(std::forward<Value>(v));\n\n        // check callback\n        const bool keep = skip_callback or callback(static_cast<int>(ref_stack.size()), parse_event_t::value, value);\n\n        // do not handle this value if we just learnt it shall be discarded\n        if (not keep)\n        {\n            return {false, nullptr};\n        }\n\n        if (ref_stack.empty())\n        {\n            root = std::move(value);\n            return {true, &root};\n        }\n\n        // skip this value if we already decided to skip the parent\n        // (https://github.com/nlohmann/json/issues/971#issuecomment-413678360)\n        if (not ref_stack.back())\n        {\n            return {false, nullptr};\n        }\n\n        // we now only expect arrays and objects\n        assert(ref_stack.back()->is_array() or ref_stack.back()->is_object());\n\n        if (ref_stack.back()->is_array())\n        {\n            ref_stack.back()->m_value.array->push_back(std::move(value));\n            return {true, &(ref_stack.back()->m_value.array->back())};\n        }\n        else\n        {\n            // check if we should store an element for the current key\n            assert(not key_keep_stack.empty());\n            const bool store_element = key_keep_stack.back();\n            key_keep_stack.pop_back();\n\n            if (not store_element)\n            {\n                return {false, nullptr};\n            }\n\n            assert(object_element);\n            *object_element = std::move(value);\n            return {true, object_element};\n        }\n    }\n\n    /// the parsed JSON value\n    BasicJsonType& root;\n    /// stack to model hierarchy of values\n    std::vector<BasicJsonType*> ref_stack;\n    /// stack to manage which values to keep\n    std::vector<bool> keep_stack;\n    /// stack to manage which object keys to keep\n    std::vector<bool> key_keep_stack;\n    /// helper to hold the reference for the next object element\n    BasicJsonType* object_element = nullptr;\n    /// whether a syntax error occurred\n    bool errored = false;\n    /// callback function\n    const parser_callback_t callback = nullptr;\n    /// whether to throw exceptions in case of errors\n    const bool allow_exceptions = true;\n    /// a discarded value for the callback\n    BasicJsonType discarded = BasicJsonType::value_t::discarded;\n};\n\ntemplate<typename BasicJsonType>\nclass json_sax_acceptor\n{\n  public:\n    using number_integer_t = typename BasicJsonType::number_integer_t;\n    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n    using number_float_t = typename BasicJsonType::number_float_t;\n    using string_t = typename BasicJsonType::string_t;\n\n    bool null()\n    {\n        return true;\n    }\n\n    bool boolean(bool /*unused*/)\n    {\n        return true;\n    }\n\n    bool number_integer(number_integer_t /*unused*/)\n    {\n        return true;\n    }\n\n    bool number_unsigned(number_unsigned_t /*unused*/)\n    {\n        return true;\n    }\n\n    bool number_float(number_float_t /*unused*/, const string_t& /*unused*/)\n    {\n        return true;\n    }\n\n    bool string(string_t& /*unused*/)\n    {\n        return true;\n    }\n\n    bool start_object(std::size_t  /*unused*/ = std::size_t(-1))\n    {\n        return true;\n    }\n\n    bool key(string_t& /*unused*/)\n    {\n        return true;\n    }\n\n    bool end_object()\n    {\n        return true;\n    }\n\n    bool start_array(std::size_t  /*unused*/ = std::size_t(-1))\n    {\n        return true;\n    }\n\n    bool end_array()\n    {\n        return true;\n    }\n\n    bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const detail::exception& /*unused*/)\n    {\n        return false;\n    }\n};\n}  // namespace detail\n\n}  // namespace nlohmann\n"
  },
  {
    "path": "nlohmann_json/include/nlohmann/detail/input/lexer.hpp",
    "content": "#pragma once\n\n#include <clocale> // localeconv\n#include <cstddef> // size_t\n#include <cstdlib> // strtof, strtod, strtold, strtoll, strtoull\n#include <cstdio> // snprintf\n#include <initializer_list> // initializer_list\n#include <string> // char_traits, string\n#include <vector> // vector\n\n#include <nlohmann/detail/macro_scope.hpp>\n#include <nlohmann/detail/input/input_adapters.hpp>\n#include <nlohmann/detail/input/position_t.hpp>\n\nnamespace nlohmann\n{\nnamespace detail\n{\n///////////\n// lexer //\n///////////\n\n/*!\n@brief lexical analysis\n\nThis class organizes the lexical analysis during JSON deserialization.\n*/\ntemplate<typename BasicJsonType>\nclass lexer\n{\n    using number_integer_t = typename BasicJsonType::number_integer_t;\n    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n    using number_float_t = typename BasicJsonType::number_float_t;\n    using string_t = typename BasicJsonType::string_t;\n\n  public:\n    /// token types for the parser\n    enum class token_type\n    {\n        uninitialized,    ///< indicating the scanner is uninitialized\n        literal_true,     ///< the `true` literal\n        literal_false,    ///< the `false` literal\n        literal_null,     ///< the `null` literal\n        value_string,     ///< a string -- use get_string() for actual value\n        value_unsigned,   ///< an unsigned integer -- use get_number_unsigned() for actual value\n        value_integer,    ///< a signed integer -- use get_number_integer() for actual value\n        value_float,      ///< an floating point number -- use get_number_float() for actual value\n        begin_array,      ///< the character for array begin `[`\n        begin_object,     ///< the character for object begin `{`\n        end_array,        ///< the character for array end `]`\n        end_object,       ///< the character for object end `}`\n        name_separator,   ///< the name separator `:`\n        value_separator,  ///< the value separator `,`\n        parse_error,      ///< indicating a parse error\n        end_of_input,     ///< indicating the end of the input buffer\n        literal_or_value  ///< a literal or the begin of a value (only for diagnostics)\n    };\n\n    /// return name of values of type token_type (only used for errors)\n    static const char* token_type_name(const token_type t) noexcept\n    {\n        switch (t)\n        {\n            case token_type::uninitialized:\n                return \"<uninitialized>\";\n            case token_type::literal_true:\n                return \"true literal\";\n            case token_type::literal_false:\n                return \"false literal\";\n            case token_type::literal_null:\n                return \"null literal\";\n            case token_type::value_string:\n                return \"string literal\";\n            case lexer::token_type::value_unsigned:\n            case lexer::token_type::value_integer:\n            case lexer::token_type::value_float:\n                return \"number literal\";\n            case token_type::begin_array:\n                return \"'['\";\n            case token_type::begin_object:\n                return \"'{'\";\n            case token_type::end_array:\n                return \"']'\";\n            case token_type::end_object:\n                return \"'}'\";\n            case token_type::name_separator:\n                return \"':'\";\n            case token_type::value_separator:\n                return \"','\";\n            case token_type::parse_error:\n                return \"<parse error>\";\n            case token_type::end_of_input:\n                return \"end of input\";\n            case token_type::literal_or_value:\n                return \"'[', '{', or a literal\";\n            // LCOV_EXCL_START\n            default: // catch non-enum values\n                return \"unknown token\";\n                // LCOV_EXCL_STOP\n        }\n    }\n\n    explicit lexer(detail::input_adapter_t&& adapter)\n        : ia(std::move(adapter)), decimal_point_char(get_decimal_point()) {}\n\n    // delete because of pointer members\n    lexer(const lexer&) = delete;\n    lexer(lexer&&) = delete;\n    lexer& operator=(lexer&) = delete;\n    lexer& operator=(lexer&&) = delete;\n    ~lexer() = default;\n\n  private:\n    /////////////////////\n    // locales\n    /////////////////////\n\n    /// return the locale-dependent decimal point\n    static char get_decimal_point() noexcept\n    {\n        const auto loc = localeconv();\n        assert(loc != nullptr);\n        return (loc->decimal_point == nullptr) ? '.' : *(loc->decimal_point);\n    }\n\n    /////////////////////\n    // scan functions\n    /////////////////////\n\n    /*!\n    @brief get codepoint from 4 hex characters following `\\u`\n\n    For input \"\\u c1 c2 c3 c4\" the codepoint is:\n      (c1 * 0x1000) + (c2 * 0x0100) + (c3 * 0x0010) + c4\n    = (c1 << 12) + (c2 << 8) + (c3 << 4) + (c4 << 0)\n\n    Furthermore, the possible characters '0'..'9', 'A'..'F', and 'a'..'f'\n    must be converted to the integers 0x0..0x9, 0xA..0xF, 0xA..0xF, resp. The\n    conversion is done by subtracting the offset (0x30, 0x37, and 0x57)\n    between the ASCII value of the character and the desired integer value.\n\n    @return codepoint (0x0000..0xFFFF) or -1 in case of an error (e.g. EOF or\n            non-hex character)\n    */\n    int get_codepoint()\n    {\n        // this function only makes sense after reading `\\u`\n        assert(current == 'u');\n        int codepoint = 0;\n\n        const auto factors = { 12, 8, 4, 0 };\n        for (const auto factor : factors)\n        {\n            get();\n\n            if (current >= '0' and current <= '9')\n            {\n                codepoint += ((current - 0x30) << factor);\n            }\n            else if (current >= 'A' and current <= 'F')\n            {\n                codepoint += ((current - 0x37) << factor);\n            }\n            else if (current >= 'a' and current <= 'f')\n            {\n                codepoint += ((current - 0x57) << factor);\n            }\n            else\n            {\n                return -1;\n            }\n        }\n\n        assert(0x0000 <= codepoint and codepoint <= 0xFFFF);\n        return codepoint;\n    }\n\n    /*!\n    @brief check if the next byte(s) are inside a given range\n\n    Adds the current byte and, for each passed range, reads a new byte and\n    checks if it is inside the range. If a violation was detected, set up an\n    error message and return false. Otherwise, return true.\n\n    @param[in] ranges  list of integers; interpreted as list of pairs of\n                       inclusive lower and upper bound, respectively\n\n    @pre The passed list @a ranges must have 2, 4, or 6 elements; that is,\n         1, 2, or 3 pairs. This precondition is enforced by an assertion.\n\n    @return true if and only if no range violation was detected\n    */\n    bool next_byte_in_range(std::initializer_list<int> ranges)\n    {\n        assert(ranges.size() == 2 or ranges.size() == 4 or ranges.size() == 6);\n        add(current);\n\n        for (auto range = ranges.begin(); range != ranges.end(); ++range)\n        {\n            get();\n            if (JSON_LIKELY(*range <= current and current <= *(++range)))\n            {\n                add(current);\n            }\n            else\n            {\n                error_message = \"invalid string: ill-formed UTF-8 byte\";\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    /*!\n    @brief scan a string literal\n\n    This function scans a string according to Sect. 7 of RFC 7159. While\n    scanning, bytes are escaped and copied into buffer token_buffer. Then the\n    function returns successfully, token_buffer is *not* null-terminated (as it\n    may contain \\0 bytes), and token_buffer.size() is the number of bytes in the\n    string.\n\n    @return token_type::value_string if string could be successfully scanned,\n            token_type::parse_error otherwise\n\n    @note In case of errors, variable error_message contains a textual\n          description.\n    */\n    token_type scan_string()\n    {\n        // reset token_buffer (ignore opening quote)\n        reset();\n\n        // we entered the function by reading an open quote\n        assert(current == '\\\"');\n\n        while (true)\n        {\n            // get next character\n            switch (get())\n            {\n                // end of file while parsing string\n                case std::char_traits<char>::eof():\n                {\n                    error_message = \"invalid string: missing closing quote\";\n                    return token_type::parse_error;\n                }\n\n                // closing quote\n                case '\\\"':\n                {\n                    return token_type::value_string;\n                }\n\n                // escapes\n                case '\\\\':\n                {\n                    switch (get())\n                    {\n                        // quotation mark\n                        case '\\\"':\n                            add('\\\"');\n                            break;\n                        // reverse solidus\n                        case '\\\\':\n                            add('\\\\');\n                            break;\n                        // solidus\n                        case '/':\n                            add('/');\n                            break;\n                        // backspace\n                        case 'b':\n                            add('\\b');\n                            break;\n                        // form feed\n                        case 'f':\n                            add('\\f');\n                            break;\n                        // line feed\n                        case 'n':\n                            add('\\n');\n                            break;\n                        // carriage return\n                        case 'r':\n                            add('\\r');\n                            break;\n                        // tab\n                        case 't':\n                            add('\\t');\n                            break;\n\n                        // unicode escapes\n                        case 'u':\n                        {\n                            const int codepoint1 = get_codepoint();\n                            int codepoint = codepoint1; // start with codepoint1\n\n                            if (JSON_UNLIKELY(codepoint1 == -1))\n                            {\n                                error_message = \"invalid string: '\\\\u' must be followed by 4 hex digits\";\n                                return token_type::parse_error;\n                            }\n\n                            // check if code point is a high surrogate\n                            if (0xD800 <= codepoint1 and codepoint1 <= 0xDBFF)\n                            {\n                                // expect next \\uxxxx entry\n                                if (JSON_LIKELY(get() == '\\\\' and get() == 'u'))\n                                {\n                                    const int codepoint2 = get_codepoint();\n\n                                    if (JSON_UNLIKELY(codepoint2 == -1))\n                                    {\n                                        error_message = \"invalid string: '\\\\u' must be followed by 4 hex digits\";\n                                        return token_type::parse_error;\n                                    }\n\n                                    // check if codepoint2 is a low surrogate\n                                    if (JSON_LIKELY(0xDC00 <= codepoint2 and codepoint2 <= 0xDFFF))\n                                    {\n                                        // overwrite codepoint\n                                        codepoint =\n                                            // high surrogate occupies the most significant 22 bits\n                                            (codepoint1 << 10)\n                                            // low surrogate occupies the least significant 15 bits\n                                            + codepoint2\n                                            // there is still the 0xD800, 0xDC00 and 0x10000 noise\n                                            // in the result so we have to subtract with:\n                                            // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00\n                                            - 0x35FDC00;\n                                    }\n                                    else\n                                    {\n                                        error_message = \"invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF\";\n                                        return token_type::parse_error;\n                                    }\n                                }\n                                else\n                                {\n                                    error_message = \"invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF\";\n                                    return token_type::parse_error;\n                                }\n                            }\n                            else\n                            {\n                                if (JSON_UNLIKELY(0xDC00 <= codepoint1 and codepoint1 <= 0xDFFF))\n                                {\n                                    error_message = \"invalid string: surrogate U+DC00..U+DFFF must follow U+D800..U+DBFF\";\n                                    return token_type::parse_error;\n                                }\n                            }\n\n                            // result of the above calculation yields a proper codepoint\n                            assert(0x00 <= codepoint and codepoint <= 0x10FFFF);\n\n                            // translate codepoint into bytes\n                            if (codepoint < 0x80)\n                            {\n                                // 1-byte characters: 0xxxxxxx (ASCII)\n                                add(codepoint);\n                            }\n                            else if (codepoint <= 0x7FF)\n                            {\n                                // 2-byte characters: 110xxxxx 10xxxxxx\n                                add(0xC0 | (codepoint >> 6));\n                                add(0x80 | (codepoint & 0x3F));\n                            }\n                            else if (codepoint <= 0xFFFF)\n                            {\n                                // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx\n                                add(0xE0 | (codepoint >> 12));\n                                add(0x80 | ((codepoint >> 6) & 0x3F));\n                                add(0x80 | (codepoint & 0x3F));\n                            }\n                            else\n                            {\n                                // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx\n                                add(0xF0 | (codepoint >> 18));\n                                add(0x80 | ((codepoint >> 12) & 0x3F));\n                                add(0x80 | ((codepoint >> 6) & 0x3F));\n                                add(0x80 | (codepoint & 0x3F));\n                            }\n\n                            break;\n                        }\n\n                        // other characters after escape\n                        default:\n                            error_message = \"invalid string: forbidden character after backslash\";\n                            return token_type::parse_error;\n                    }\n\n                    break;\n                }\n\n                // invalid control characters\n                case 0x00:\n                {\n                    error_message = \"invalid string: control character U+0000 (NUL) must be escaped to \\\\u0000\";\n                    return token_type::parse_error;\n                }\n\n                case 0x01:\n                {\n                    error_message = \"invalid string: control character U+0001 (SOH) must be escaped to \\\\u0001\";\n                    return token_type::parse_error;\n                }\n\n                case 0x02:\n                {\n                    error_message = \"invalid string: control character U+0002 (STX) must be escaped to \\\\u0002\";\n                    return token_type::parse_error;\n                }\n\n                case 0x03:\n                {\n                    error_message = \"invalid string: control character U+0003 (ETX) must be escaped to \\\\u0003\";\n                    return token_type::parse_error;\n                }\n\n                case 0x04:\n                {\n                    error_message = \"invalid string: control character U+0004 (EOT) must be escaped to \\\\u0004\";\n                    return token_type::parse_error;\n                }\n\n                case 0x05:\n                {\n                    error_message = \"invalid string: control character U+0005 (ENQ) must be escaped to \\\\u0005\";\n                    return token_type::parse_error;\n                }\n\n                case 0x06:\n                {\n                    error_message = \"invalid string: control character U+0006 (ACK) must be escaped to \\\\u0006\";\n                    return token_type::parse_error;\n                }\n\n                case 0x07:\n                {\n                    error_message = \"invalid string: control character U+0007 (BEL) must be escaped to \\\\u0007\";\n                    return token_type::parse_error;\n                }\n\n                case 0x08:\n                {\n                    error_message = \"invalid string: control character U+0008 (BS) must be escaped to \\\\u0008 or \\\\b\";\n                    return token_type::parse_error;\n                }\n\n                case 0x09:\n                {\n                    error_message = \"invalid string: control character U+0009 (HT) must be escaped to \\\\u0009 or \\\\t\";\n                    return token_type::parse_error;\n                }\n\n                case 0x0A:\n                {\n                    error_message = \"invalid string: control character U+000A (LF) must be escaped to \\\\u000A or \\\\n\";\n                    return token_type::parse_error;\n                }\n\n                case 0x0B:\n                {\n                    error_message = \"invalid string: control character U+000B (VT) must be escaped to \\\\u000B\";\n                    return token_type::parse_error;\n                }\n\n                case 0x0C:\n                {\n                    error_message = \"invalid string: control character U+000C (FF) must be escaped to \\\\u000C or \\\\f\";\n                    return token_type::parse_error;\n                }\n\n                case 0x0D:\n                {\n                    error_message = \"invalid string: control character U+000D (CR) must be escaped to \\\\u000D or \\\\r\";\n                    return token_type::parse_error;\n                }\n\n                case 0x0E:\n                {\n                    error_message = \"invalid string: control character U+000E (SO) must be escaped to \\\\u000E\";\n                    return token_type::parse_error;\n                }\n\n                case 0x0F:\n                {\n                    error_message = \"invalid string: control character U+000F (SI) must be escaped to \\\\u000F\";\n                    return token_type::parse_error;\n                }\n\n                case 0x10:\n                {\n                    error_message = \"invalid string: control character U+0010 (DLE) must be escaped to \\\\u0010\";\n                    return token_type::parse_error;\n                }\n\n                case 0x11:\n                {\n                    error_message = \"invalid string: control character U+0011 (DC1) must be escaped to \\\\u0011\";\n                    return token_type::parse_error;\n                }\n\n                case 0x12:\n                {\n                    error_message = \"invalid string: control character U+0012 (DC2) must be escaped to \\\\u0012\";\n                    return token_type::parse_error;\n                }\n\n                case 0x13:\n                {\n                    error_message = \"invalid string: control character U+0013 (DC3) must be escaped to \\\\u0013\";\n                    return token_type::parse_error;\n                }\n\n                case 0x14:\n                {\n                    error_message = \"invalid string: control character U+0014 (DC4) must be escaped to \\\\u0014\";\n                    return token_type::parse_error;\n                }\n\n                case 0x15:\n                {\n                    error_message = \"invalid string: control character U+0015 (NAK) must be escaped to \\\\u0015\";\n                    return token_type::parse_error;\n                }\n\n                case 0x16:\n                {\n                    error_message = \"invalid string: control character U+0016 (SYN) must be escaped to \\\\u0016\";\n                    return token_type::parse_error;\n                }\n\n                case 0x17:\n                {\n                    error_message = \"invalid string: control character U+0017 (ETB) must be escaped to \\\\u0017\";\n                    return token_type::parse_error;\n                }\n\n                case 0x18:\n                {\n                    error_message = \"invalid string: control character U+0018 (CAN) must be escaped to \\\\u0018\";\n                    return token_type::parse_error;\n                }\n\n                case 0x19:\n                {\n                    error_message = \"invalid string: control character U+0019 (EM) must be escaped to \\\\u0019\";\n                    return token_type::parse_error;\n                }\n\n                case 0x1A:\n                {\n                    error_message = \"invalid string: control character U+001A (SUB) must be escaped to \\\\u001A\";\n                    return token_type::parse_error;\n                }\n\n                case 0x1B:\n                {\n                    error_message = \"invalid string: control character U+001B (ESC) must be escaped to \\\\u001B\";\n                    return token_type::parse_error;\n                }\n\n                case 0x1C:\n                {\n                    error_message = \"invalid string: control character U+001C (FS) must be escaped to \\\\u001C\";\n                    return token_type::parse_error;\n                }\n\n                case 0x1D:\n                {\n                    error_message = \"invalid string: control character U+001D (GS) must be escaped to \\\\u001D\";\n                    return token_type::parse_error;\n                }\n\n                case 0x1E:\n                {\n                    error_message = \"invalid string: control character U+001E (RS) must be escaped to \\\\u001E\";\n                    return token_type::parse_error;\n                }\n\n                case 0x1F:\n                {\n                    error_message = \"invalid string: control character U+001F (US) must be escaped to \\\\u001F\";\n                    return token_type::parse_error;\n                }\n\n                // U+0020..U+007F (except U+0022 (quote) and U+005C (backspace))\n                case 0x20:\n                case 0x21:\n                case 0x23:\n                case 0x24:\n                case 0x25:\n                case 0x26:\n                case 0x27:\n                case 0x28:\n                case 0x29:\n                case 0x2A:\n                case 0x2B:\n                case 0x2C:\n                case 0x2D:\n                case 0x2E:\n                case 0x2F:\n                case 0x30:\n                case 0x31:\n                case 0x32:\n                case 0x33:\n                case 0x34:\n                case 0x35:\n                case 0x36:\n                case 0x37:\n                case 0x38:\n                case 0x39:\n                case 0x3A:\n                case 0x3B:\n                case 0x3C:\n                case 0x3D:\n                case 0x3E:\n                case 0x3F:\n                case 0x40:\n                case 0x41:\n                case 0x42:\n                case 0x43:\n                case 0x44:\n                case 0x45:\n                case 0x46:\n                case 0x47:\n                case 0x48:\n                case 0x49:\n                case 0x4A:\n                case 0x4B:\n                case 0x4C:\n                case 0x4D:\n                case 0x4E:\n                case 0x4F:\n                case 0x50:\n                case 0x51:\n                case 0x52:\n                case 0x53:\n                case 0x54:\n                case 0x55:\n                case 0x56:\n                case 0x57:\n                case 0x58:\n                case 0x59:\n                case 0x5A:\n                case 0x5B:\n                case 0x5D:\n                case 0x5E:\n                case 0x5F:\n                case 0x60:\n                case 0x61:\n                case 0x62:\n                case 0x63:\n                case 0x64:\n                case 0x65:\n                case 0x66:\n                case 0x67:\n                case 0x68:\n                case 0x69:\n                case 0x6A:\n                case 0x6B:\n                case 0x6C:\n                case 0x6D:\n                case 0x6E:\n                case 0x6F:\n                case 0x70:\n                case 0x71:\n                case 0x72:\n                case 0x73:\n                case 0x74:\n                case 0x75:\n                case 0x76:\n                case 0x77:\n                case 0x78:\n                case 0x79:\n                case 0x7A:\n                case 0x7B:\n                case 0x7C:\n                case 0x7D:\n                case 0x7E:\n                case 0x7F:\n                {\n                    add(current);\n                    break;\n                }\n\n                // U+0080..U+07FF: bytes C2..DF 80..BF\n                case 0xC2:\n                case 0xC3:\n                case 0xC4:\n                case 0xC5:\n                case 0xC6:\n                case 0xC7:\n                case 0xC8:\n                case 0xC9:\n                case 0xCA:\n                case 0xCB:\n                case 0xCC:\n                case 0xCD:\n                case 0xCE:\n                case 0xCF:\n                case 0xD0:\n                case 0xD1:\n                case 0xD2:\n                case 0xD3:\n                case 0xD4:\n                case 0xD5:\n                case 0xD6:\n                case 0xD7:\n                case 0xD8:\n                case 0xD9:\n                case 0xDA:\n                case 0xDB:\n                case 0xDC:\n                case 0xDD:\n                case 0xDE:\n                case 0xDF:\n                {\n                    if (JSON_UNLIKELY(not next_byte_in_range({0x80, 0xBF})))\n                    {\n                        return token_type::parse_error;\n                    }\n                    break;\n                }\n\n                // U+0800..U+0FFF: bytes E0 A0..BF 80..BF\n                case 0xE0:\n                {\n                    if (JSON_UNLIKELY(not (next_byte_in_range({0xA0, 0xBF, 0x80, 0xBF}))))\n                    {\n                        return token_type::parse_error;\n                    }\n                    break;\n                }\n\n                // U+1000..U+CFFF: bytes E1..EC 80..BF 80..BF\n                // U+E000..U+FFFF: bytes EE..EF 80..BF 80..BF\n                case 0xE1:\n                case 0xE2:\n                case 0xE3:\n                case 0xE4:\n                case 0xE5:\n                case 0xE6:\n                case 0xE7:\n                case 0xE8:\n                case 0xE9:\n                case 0xEA:\n                case 0xEB:\n                case 0xEC:\n                case 0xEE:\n                case 0xEF:\n                {\n                    if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0xBF, 0x80, 0xBF}))))\n                    {\n                        return token_type::parse_error;\n                    }\n                    break;\n                }\n\n                // U+D000..U+D7FF: bytes ED 80..9F 80..BF\n                case 0xED:\n                {\n                    if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0x9F, 0x80, 0xBF}))))\n                    {\n                        return token_type::parse_error;\n                    }\n                    break;\n                }\n\n                // U+10000..U+3FFFF F0 90..BF 80..BF 80..BF\n                case 0xF0:\n                {\n                    if (JSON_UNLIKELY(not (next_byte_in_range({0x90, 0xBF, 0x80, 0xBF, 0x80, 0xBF}))))\n                    {\n                        return token_type::parse_error;\n                    }\n                    break;\n                }\n\n                // U+40000..U+FFFFF F1..F3 80..BF 80..BF 80..BF\n                case 0xF1:\n                case 0xF2:\n                case 0xF3:\n                {\n                    if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF}))))\n                    {\n                        return token_type::parse_error;\n                    }\n                    break;\n                }\n\n                // U+100000..U+10FFFF F4 80..8F 80..BF 80..BF\n                case 0xF4:\n                {\n                    if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0x8F, 0x80, 0xBF, 0x80, 0xBF}))))\n                    {\n                        return token_type::parse_error;\n                    }\n                    break;\n                }\n\n                // remaining bytes (80..C1 and F5..FF) are ill-formed\n                default:\n                {\n                    error_message = \"invalid string: ill-formed UTF-8 byte\";\n                    return token_type::parse_error;\n                }\n            }\n        }\n    }\n\n    static void strtof(float& f, const char* str, char** endptr) noexcept\n    {\n        f = std::strtof(str, endptr);\n    }\n\n    static void strtof(double& f, const char* str, char** endptr) noexcept\n    {\n        f = std::strtod(str, endptr);\n    }\n\n    static void strtof(long double& f, const char* str, char** endptr) noexcept\n    {\n        f = std::strtold(str, endptr);\n    }\n\n    /*!\n    @brief scan a number literal\n\n    This function scans a string according to Sect. 6 of RFC 7159.\n\n    The function is realized with a deterministic finite state machine derived\n    from the grammar described in RFC 7159. Starting in state \"init\", the\n    input is read and used to determined the next state. Only state \"done\"\n    accepts the number. State \"error\" is a trap state to model errors. In the\n    table below, \"anything\" means any character but the ones listed before.\n\n    state    | 0        | 1-9      | e E      | +       | -       | .        | anything\n    ---------|----------|----------|----------|---------|---------|----------|-----------\n    init     | zero     | any1     | [error]  | [error] | minus   | [error]  | [error]\n    minus    | zero     | any1     | [error]  | [error] | [error] | [error]  | [error]\n    zero     | done     | done     | exponent | done    | done    | decimal1 | done\n    any1     | any1     | any1     | exponent | done    | done    | decimal1 | done\n    decimal1 | decimal2 | [error]  | [error]  | [error] | [error] | [error]  | [error]\n    decimal2 | decimal2 | decimal2 | exponent | done    | done    | done     | done\n    exponent | any2     | any2     | [error]  | sign    | sign    | [error]  | [error]\n    sign     | any2     | any2     | [error]  | [error] | [error] | [error]  | [error]\n    any2     | any2     | any2     | done     | done    | done    | done     | done\n\n    The state machine is realized with one label per state (prefixed with\n    \"scan_number_\") and `goto` statements between them. The state machine\n    contains cycles, but any cycle can be left when EOF is read. Therefore,\n    the function is guaranteed to terminate.\n\n    During scanning, the read bytes are stored in token_buffer. This string is\n    then converted to a signed integer, an unsigned integer, or a\n    floating-point number.\n\n    @return token_type::value_unsigned, token_type::value_integer, or\n            token_type::value_float if number could be successfully scanned,\n            token_type::parse_error otherwise\n\n    @note The scanner is independent of the current locale. Internally, the\n          locale's decimal point is used instead of `.` to work with the\n          locale-dependent converters.\n    */\n    token_type scan_number()  // lgtm [cpp/use-of-goto]\n    {\n        // reset token_buffer to store the number's bytes\n        reset();\n\n        // the type of the parsed number; initially set to unsigned; will be\n        // changed if minus sign, decimal point or exponent is read\n        token_type number_type = token_type::value_unsigned;\n\n        // state (init): we just found out we need to scan a number\n        switch (current)\n        {\n            case '-':\n            {\n                add(current);\n                goto scan_number_minus;\n            }\n\n            case '0':\n            {\n                add(current);\n                goto scan_number_zero;\n            }\n\n            case '1':\n            case '2':\n            case '3':\n            case '4':\n            case '5':\n            case '6':\n            case '7':\n            case '8':\n            case '9':\n            {\n                add(current);\n                goto scan_number_any1;\n            }\n\n            // LCOV_EXCL_START\n            default:\n            {\n                // all other characters are rejected outside scan_number()\n                assert(false);\n            }\n                // LCOV_EXCL_STOP\n        }\n\nscan_number_minus:\n        // state: we just parsed a leading minus sign\n        number_type = token_type::value_integer;\n        switch (get())\n        {\n            case '0':\n            {\n                add(current);\n                goto scan_number_zero;\n            }\n\n            case '1':\n            case '2':\n            case '3':\n            case '4':\n            case '5':\n            case '6':\n            case '7':\n            case '8':\n            case '9':\n            {\n                add(current);\n                goto scan_number_any1;\n            }\n\n            default:\n            {\n                error_message = \"invalid number; expected digit after '-'\";\n                return token_type::parse_error;\n            }\n        }\n\nscan_number_zero:\n        // state: we just parse a zero (maybe with a leading minus sign)\n        switch (get())\n        {\n            case '.':\n            {\n                add(decimal_point_char);\n                goto scan_number_decimal1;\n            }\n\n            case 'e':\n            case 'E':\n            {\n                add(current);\n                goto scan_number_exponent;\n            }\n\n            default:\n                goto scan_number_done;\n        }\n\nscan_number_any1:\n        // state: we just parsed a number 0-9 (maybe with a leading minus sign)\n        switch (get())\n        {\n            case '0':\n            case '1':\n            case '2':\n            case '3':\n            case '4':\n            case '5':\n            case '6':\n            case '7':\n            case '8':\n            case '9':\n            {\n                add(current);\n                goto scan_number_any1;\n            }\n\n            case '.':\n            {\n                add(decimal_point_char);\n                goto scan_number_decimal1;\n            }\n\n            case 'e':\n            case 'E':\n            {\n                add(current);\n                goto scan_number_exponent;\n            }\n\n            default:\n                goto scan_number_done;\n        }\n\nscan_number_decimal1:\n        // state: we just parsed a decimal point\n        number_type = token_type::value_float;\n        switch (get())\n        {\n            case '0':\n            case '1':\n            case '2':\n            case '3':\n            case '4':\n            case '5':\n            case '6':\n            case '7':\n            case '8':\n            case '9':\n            {\n                add(current);\n                goto scan_number_decimal2;\n            }\n\n            default:\n            {\n                error_message = \"invalid number; expected digit after '.'\";\n                return token_type::parse_error;\n            }\n        }\n\nscan_number_decimal2:\n        // we just parsed at least one number after a decimal point\n        switch (get())\n        {\n            case '0':\n            case '1':\n            case '2':\n            case '3':\n            case '4':\n            case '5':\n            case '6':\n            case '7':\n            case '8':\n            case '9':\n            {\n                add(current);\n                goto scan_number_decimal2;\n            }\n\n            case 'e':\n            case 'E':\n            {\n                add(current);\n                goto scan_number_exponent;\n            }\n\n            default:\n                goto scan_number_done;\n        }\n\nscan_number_exponent:\n        // we just parsed an exponent\n        number_type = token_type::value_float;\n        switch (get())\n        {\n            case '+':\n            case '-':\n            {\n                add(current);\n                goto scan_number_sign;\n            }\n\n            case '0':\n            case '1':\n            case '2':\n            case '3':\n            case '4':\n            case '5':\n            case '6':\n            case '7':\n            case '8':\n            case '9':\n            {\n                add(current);\n                goto scan_number_any2;\n            }\n\n            default:\n            {\n                error_message =\n                    \"invalid number; expected '+', '-', or digit after exponent\";\n                return token_type::parse_error;\n            }\n        }\n\nscan_number_sign:\n        // we just parsed an exponent sign\n        switch (get())\n        {\n            case '0':\n            case '1':\n            case '2':\n            case '3':\n            case '4':\n            case '5':\n            case '6':\n            case '7':\n            case '8':\n            case '9':\n            {\n                add(current);\n                goto scan_number_any2;\n            }\n\n            default:\n            {\n                error_message = \"invalid number; expected digit after exponent sign\";\n                return token_type::parse_error;\n            }\n        }\n\nscan_number_any2:\n        // we just parsed a number after the exponent or exponent sign\n        switch (get())\n        {\n            case '0':\n            case '1':\n            case '2':\n            case '3':\n            case '4':\n            case '5':\n            case '6':\n            case '7':\n            case '8':\n            case '9':\n            {\n                add(current);\n                goto scan_number_any2;\n            }\n\n            default:\n                goto scan_number_done;\n        }\n\nscan_number_done:\n        // unget the character after the number (we only read it to know that\n        // we are done scanning a number)\n        unget();\n\n        char* endptr = nullptr;\n        errno = 0;\n\n        // try to parse integers first and fall back to floats\n        if (number_type == token_type::value_unsigned)\n        {\n            const auto x = std::strtoull(token_buffer.data(), &endptr, 10);\n\n            // we checked the number format before\n            assert(endptr == token_buffer.data() + token_buffer.size());\n\n            if (errno == 0)\n            {\n                value_unsigned = static_cast<number_unsigned_t>(x);\n                if (value_unsigned == x)\n                {\n                    return token_type::value_unsigned;\n                }\n            }\n        }\n        else if (number_type == token_type::value_integer)\n        {\n            const auto x = std::strtoll(token_buffer.data(), &endptr, 10);\n\n            // we checked the number format before\n            assert(endptr == token_buffer.data() + token_buffer.size());\n\n            if (errno == 0)\n            {\n                value_integer = static_cast<number_integer_t>(x);\n                if (value_integer == x)\n                {\n                    return token_type::value_integer;\n                }\n            }\n        }\n\n        // this code is reached if we parse a floating-point number or if an\n        // integer conversion above failed\n        strtof(value_float, token_buffer.data(), &endptr);\n\n        // we checked the number format before\n        assert(endptr == token_buffer.data() + token_buffer.size());\n\n        return token_type::value_float;\n    }\n\n    /*!\n    @param[in] literal_text  the literal text to expect\n    @param[in] length        the length of the passed literal text\n    @param[in] return_type   the token type to return on success\n    */\n    token_type scan_literal(const char* literal_text, const std::size_t length,\n                            token_type return_type)\n    {\n        assert(current == literal_text[0]);\n        for (std::size_t i = 1; i < length; ++i)\n        {\n            if (JSON_UNLIKELY(get() != literal_text[i]))\n            {\n                error_message = \"invalid literal\";\n                return token_type::parse_error;\n            }\n        }\n        return return_type;\n    }\n\n    /////////////////////\n    // input management\n    /////////////////////\n\n    /// reset token_buffer; current character is beginning of token\n    void reset() noexcept\n    {\n        token_buffer.clear();\n        token_string.clear();\n        token_string.push_back(std::char_traits<char>::to_char_type(current));\n    }\n\n    /*\n    @brief get next character from the input\n\n    This function provides the interface to the used input adapter. It does\n    not throw in case the input reached EOF, but returns a\n    `std::char_traits<char>::eof()` in that case.  Stores the scanned characters\n    for use in error messages.\n\n    @return character read from the input\n    */\n    std::char_traits<char>::int_type get()\n    {\n        ++position.chars_read_total;\n        ++position.chars_read_current_line;\n\n        if (next_unget)\n        {\n            // just reset the next_unget variable and work with current\n            next_unget = false;\n        }\n        else\n        {\n            current = ia->get_character();\n        }\n\n        if (JSON_LIKELY(current != std::char_traits<char>::eof()))\n        {\n            token_string.push_back(std::char_traits<char>::to_char_type(current));\n        }\n\n        if (current == '\\n')\n        {\n            ++position.lines_read;\n            ++position.chars_read_current_line = 0;\n        }\n\n        return current;\n    }\n\n    /*!\n    @brief unget current character (read it again on next get)\n\n    We implement unget by setting variable next_unget to true. The input is not\n    changed - we just simulate ungetting by modifying chars_read_total,\n    chars_read_current_line, and token_string. The next call to get() will\n    behave as if the unget character is read again.\n    */\n    void unget()\n    {\n        next_unget = true;\n\n        --position.chars_read_total;\n\n        // in case we \"unget\" a newline, we have to also decrement the lines_read\n        if (position.chars_read_current_line == 0)\n        {\n            if (position.lines_read > 0)\n            {\n                --position.lines_read;\n            }\n        }\n        else\n        {\n            --position.chars_read_current_line;\n        }\n\n        if (JSON_LIKELY(current != std::char_traits<char>::eof()))\n        {\n            assert(token_string.size() != 0);\n            token_string.pop_back();\n        }\n    }\n\n    /// add a character to token_buffer\n    void add(int c)\n    {\n        token_buffer.push_back(std::char_traits<char>::to_char_type(c));\n    }\n\n  public:\n    /////////////////////\n    // value getters\n    /////////////////////\n\n    /// return integer value\n    constexpr number_integer_t get_number_integer() const noexcept\n    {\n        return value_integer;\n    }\n\n    /// return unsigned integer value\n    constexpr number_unsigned_t get_number_unsigned() const noexcept\n    {\n        return value_unsigned;\n    }\n\n    /// return floating-point value\n    constexpr number_float_t get_number_float() const noexcept\n    {\n        return value_float;\n    }\n\n    /// return current string value (implicitly resets the token; useful only once)\n    string_t& get_string()\n    {\n        return token_buffer;\n    }\n\n    /////////////////////\n    // diagnostics\n    /////////////////////\n\n    /// return position of last read token\n    constexpr position_t get_position() const noexcept\n    {\n        return position;\n    }\n\n    /// return the last read token (for errors only).  Will never contain EOF\n    /// (an arbitrary value that is not a valid char value, often -1), because\n    /// 255 may legitimately occur.  May contain NUL, which should be escaped.\n    std::string get_token_string() const\n    {\n        // escape control characters\n        std::string result;\n        for (const auto c : token_string)\n        {\n            if ('\\x00' <= c and c <= '\\x1F')\n            {\n                // escape control characters\n                char cs[9];\n                (std::snprintf)(cs, 9, \"<U+%.4X>\", static_cast<unsigned char>(c));\n                result += cs;\n            }\n            else\n            {\n                // add character as is\n                result.push_back(c);\n            }\n        }\n\n        return result;\n    }\n\n    /// return syntax error message\n    constexpr const char* get_error_message() const noexcept\n    {\n        return error_message;\n    }\n\n    /////////////////////\n    // actual scanner\n    /////////////////////\n\n    /*!\n    @brief skip the UTF-8 byte order mark\n    @return true iff there is no BOM or the correct BOM has been skipped\n    */\n    bool skip_bom()\n    {\n        if (get() == 0xEF)\n        {\n            // check if we completely parse the BOM\n            return get() == 0xBB and get() == 0xBF;\n        }\n\n        // the first character is not the beginning of the BOM; unget it to\n        // process is later\n        unget();\n        return true;\n    }\n\n    token_type scan()\n    {\n        // initially, skip the BOM\n        if (position.chars_read_total == 0 and not skip_bom())\n        {\n            error_message = \"invalid BOM; must be 0xEF 0xBB 0xBF if given\";\n            return token_type::parse_error;\n        }\n\n        // read next character and ignore whitespace\n        do\n        {\n            get();\n        }\n        while (current == ' ' or current == '\\t' or current == '\\n' or current == '\\r');\n\n        switch (current)\n        {\n            // structural characters\n            case '[':\n                return token_type::begin_array;\n            case ']':\n                return token_type::end_array;\n            case '{':\n                return token_type::begin_object;\n            case '}':\n                return token_type::end_object;\n            case ':':\n                return token_type::name_separator;\n            case ',':\n                return token_type::value_separator;\n\n            // literals\n            case 't':\n                return scan_literal(\"true\", 4, token_type::literal_true);\n            case 'f':\n                return scan_literal(\"false\", 5, token_type::literal_false);\n            case 'n':\n                return scan_literal(\"null\", 4, token_type::literal_null);\n\n            // string\n            case '\\\"':\n                return scan_string();\n\n            // number\n            case '-':\n            case '0':\n            case '1':\n            case '2':\n            case '3':\n            case '4':\n            case '5':\n            case '6':\n            case '7':\n            case '8':\n            case '9':\n                return scan_number();\n\n            // end of input (the null byte is needed when parsing from\n            // string literals)\n            case '\\0':\n            case std::char_traits<char>::eof():\n                return token_type::end_of_input;\n\n            // error\n            default:\n                error_message = \"invalid literal\";\n                return token_type::parse_error;\n        }\n    }\n\n  private:\n    /// input adapter\n    detail::input_adapter_t ia = nullptr;\n\n    /// the current character\n    std::char_traits<char>::int_type current = std::char_traits<char>::eof();\n\n    /// whether the next get() call should just return current\n    bool next_unget = false;\n\n    /// the start position of the current token\n    position_t position;\n\n    /// raw input token string (for error messages)\n    std::vector<char> token_string {};\n\n    /// buffer for variable-length tokens (numbers, strings)\n    string_t token_buffer {};\n\n    /// a description of occurred lexer errors\n    const char* error_message = \"\";\n\n    // number values\n    number_integer_t value_integer = 0;\n    number_unsigned_t value_unsigned = 0;\n    number_float_t value_float = 0;\n\n    /// the decimal point\n    const char decimal_point_char = '.';\n};\n}  // namespace detail\n}  // namespace nlohmann\n"
  },
  {
    "path": "nlohmann_json/include/nlohmann/detail/input/parser.hpp",
    "content": "#pragma once\n\n#include <cassert> // assert\n#include <cmath> // isfinite\n#include <cstdint> // uint8_t\n#include <functional> // function\n#include <string> // string\n#include <utility> // move\n\n#include <nlohmann/detail/exceptions.hpp>\n#include <nlohmann/detail/macro_scope.hpp>\n#include <nlohmann/detail/meta/is_sax.hpp>\n#include <nlohmann/detail/input/input_adapters.hpp>\n#include <nlohmann/detail/input/json_sax.hpp>\n#include <nlohmann/detail/input/lexer.hpp>\n#include <nlohmann/detail/value_t.hpp>\n\nnamespace nlohmann\n{\nnamespace detail\n{\n////////////\n// parser //\n////////////\n\n/*!\n@brief syntax analysis\n\nThis class implements a recursive decent parser.\n*/\ntemplate<typename BasicJsonType>\nclass parser\n{\n    using number_integer_t = typename BasicJsonType::number_integer_t;\n    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n    using number_float_t = typename BasicJsonType::number_float_t;\n    using string_t = typename BasicJsonType::string_t;\n    using lexer_t = lexer<BasicJsonType>;\n    using token_type = typename lexer_t::token_type;\n\n  public:\n    enum class parse_event_t : uint8_t\n    {\n        /// the parser read `{` and started to process a JSON object\n        object_start,\n        /// the parser read `}` and finished processing a JSON object\n        object_end,\n        /// the parser read `[` and started to process a JSON array\n        array_start,\n        /// the parser read `]` and finished processing a JSON array\n        array_end,\n        /// the parser read a key of a value in an object\n        key,\n        /// the parser finished reading a JSON value\n        value\n    };\n\n    using parser_callback_t =\n        std::function<bool(int depth, parse_event_t event, BasicJsonType& parsed)>;\n\n    /// a parser reading from an input adapter\n    explicit parser(detail::input_adapter_t&& adapter,\n                    const parser_callback_t cb = nullptr,\n                    const bool allow_exceptions_ = true)\n        : callback(cb), m_lexer(std::move(adapter)), allow_exceptions(allow_exceptions_)\n    {\n        // read first token\n        get_token();\n    }\n\n    /*!\n    @brief public parser interface\n\n    @param[in] strict      whether to expect the last token to be EOF\n    @param[in,out] result  parsed JSON value\n\n    @throw parse_error.101 in case of an unexpected token\n    @throw parse_error.102 if to_unicode fails or surrogate error\n    @throw parse_error.103 if to_unicode fails\n    */\n    void parse(const bool strict, BasicJsonType& result)\n    {\n        if (callback)\n        {\n            json_sax_dom_callback_parser<BasicJsonType> sdp(result, callback, allow_exceptions);\n            sax_parse_internal(&sdp);\n            result.assert_invariant();\n\n            // in strict mode, input must be completely read\n            if (strict and (get_token() != token_type::end_of_input))\n            {\n                sdp.parse_error(m_lexer.get_position(),\n                                m_lexer.get_token_string(),\n                                parse_error::create(101, m_lexer.get_position(),\n                                                    exception_message(token_type::end_of_input, \"value\")));\n            }\n\n            // in case of an error, return discarded value\n            if (sdp.is_errored())\n            {\n                result = value_t::discarded;\n                return;\n            }\n\n            // set top-level value to null if it was discarded by the callback\n            // function\n            if (result.is_discarded())\n            {\n                result = nullptr;\n            }\n        }\n        else\n        {\n            json_sax_dom_parser<BasicJsonType> sdp(result, allow_exceptions);\n            sax_parse_internal(&sdp);\n            result.assert_invariant();\n\n            // in strict mode, input must be completely read\n            if (strict and (get_token() != token_type::end_of_input))\n            {\n                sdp.parse_error(m_lexer.get_position(),\n                                m_lexer.get_token_string(),\n                                parse_error::create(101, m_lexer.get_position(),\n                                                    exception_message(token_type::end_of_input, \"value\")));\n            }\n\n            // in case of an error, return discarded value\n            if (sdp.is_errored())\n            {\n                result = value_t::discarded;\n                return;\n            }\n        }\n    }\n\n    /*!\n    @brief public accept interface\n\n    @param[in] strict  whether to expect the last token to be EOF\n    @return whether the input is a proper JSON text\n    */\n    bool accept(const bool strict = true)\n    {\n        json_sax_acceptor<BasicJsonType> sax_acceptor;\n        return sax_parse(&sax_acceptor, strict);\n    }\n\n    template <typename SAX>\n    bool sax_parse(SAX* sax, const bool strict = true)\n    {\n        (void)detail::is_sax_static_asserts<SAX, BasicJsonType> {};\n        const bool result = sax_parse_internal(sax);\n\n        // strict mode: next byte must be EOF\n        if (result and strict and (get_token() != token_type::end_of_input))\n        {\n            return sax->parse_error(m_lexer.get_position(),\n                                    m_lexer.get_token_string(),\n                                    parse_error::create(101, m_lexer.get_position(),\n                                            exception_message(token_type::end_of_input, \"value\")));\n        }\n\n        return result;\n    }\n\n  private:\n    template <typename SAX>\n    bool sax_parse_internal(SAX* sax)\n    {\n        // stack to remember the hierarchy of structured values we are parsing\n        // true = array; false = object\n        std::vector<bool> states;\n        // value to avoid a goto (see comment where set to true)\n        bool skip_to_state_evaluation = false;\n\n        while (true)\n        {\n            if (not skip_to_state_evaluation)\n            {\n                // invariant: get_token() was called before each iteration\n                switch (last_token)\n                {\n                    case token_type::begin_object:\n                    {\n                        if (JSON_UNLIKELY(not sax->start_object(std::size_t(-1))))\n                        {\n                            return false;\n                        }\n\n                        // closing } -> we are done\n                        if (get_token() == token_type::end_object)\n                        {\n                            if (JSON_UNLIKELY(not sax->end_object()))\n                            {\n                                return false;\n                            }\n                            break;\n                        }\n\n                        // parse key\n                        if (JSON_UNLIKELY(last_token != token_type::value_string))\n                        {\n                            return sax->parse_error(m_lexer.get_position(),\n                                                    m_lexer.get_token_string(),\n                                                    parse_error::create(101, m_lexer.get_position(),\n                                                            exception_message(token_type::value_string, \"object key\")));\n                        }\n                        if (JSON_UNLIKELY(not sax->key(m_lexer.get_string())))\n                        {\n                            return false;\n                        }\n\n                        // parse separator (:)\n                        if (JSON_UNLIKELY(get_token() != token_type::name_separator))\n                        {\n                            return sax->parse_error(m_lexer.get_position(),\n                                                    m_lexer.get_token_string(),\n                                                    parse_error::create(101, m_lexer.get_position(),\n                                                            exception_message(token_type::name_separator, \"object separator\")));\n                        }\n\n                        // remember we are now inside an object\n                        states.push_back(false);\n\n                        // parse values\n                        get_token();\n                        continue;\n                    }\n\n                    case token_type::begin_array:\n                    {\n                        if (JSON_UNLIKELY(not sax->start_array(std::size_t(-1))))\n                        {\n                            return false;\n                        }\n\n                        // closing ] -> we are done\n                        if (get_token() == token_type::end_array)\n                        {\n                            if (JSON_UNLIKELY(not sax->end_array()))\n                            {\n                                return false;\n                            }\n                            break;\n                        }\n\n                        // remember we are now inside an array\n                        states.push_back(true);\n\n                        // parse values (no need to call get_token)\n                        continue;\n                    }\n\n                    case token_type::value_float:\n                    {\n                        const auto res = m_lexer.get_number_float();\n\n                        if (JSON_UNLIKELY(not std::isfinite(res)))\n                        {\n                            return sax->parse_error(m_lexer.get_position(),\n                                                    m_lexer.get_token_string(),\n                                                    out_of_range::create(406, \"number overflow parsing '\" + m_lexer.get_token_string() + \"'\"));\n                        }\n                        else\n                        {\n                            if (JSON_UNLIKELY(not sax->number_float(res, m_lexer.get_string())))\n                            {\n                                return false;\n                            }\n                            break;\n                        }\n                    }\n\n                    case token_type::literal_false:\n                    {\n                        if (JSON_UNLIKELY(not sax->boolean(false)))\n                        {\n                            return false;\n                        }\n                        break;\n                    }\n\n                    case token_type::literal_null:\n                    {\n                        if (JSON_UNLIKELY(not sax->null()))\n                        {\n                            return false;\n                        }\n                        break;\n                    }\n\n                    case token_type::literal_true:\n                    {\n                        if (JSON_UNLIKELY(not sax->boolean(true)))\n                        {\n                            return false;\n                        }\n                        break;\n                    }\n\n                    case token_type::value_integer:\n                    {\n                        if (JSON_UNLIKELY(not sax->number_integer(m_lexer.get_number_integer())))\n                        {\n                            return false;\n                        }\n                        break;\n                    }\n\n                    case token_type::value_string:\n                    {\n                        if (JSON_UNLIKELY(not sax->string(m_lexer.get_string())))\n                        {\n                            return false;\n                        }\n                        break;\n                    }\n\n                    case token_type::value_unsigned:\n                    {\n                        if (JSON_UNLIKELY(not sax->number_unsigned(m_lexer.get_number_unsigned())))\n                        {\n                            return false;\n                        }\n                        break;\n                    }\n\n                    case token_type::parse_error:\n                    {\n                        // using \"uninitialized\" to avoid \"expected\" message\n                        return sax->parse_error(m_lexer.get_position(),\n                                                m_lexer.get_token_string(),\n                                                parse_error::create(101, m_lexer.get_position(),\n                                                        exception_message(token_type::uninitialized, \"value\")));\n                    }\n\n                    default: // the last token was unexpected\n                    {\n                        return sax->parse_error(m_lexer.get_position(),\n                                                m_lexer.get_token_string(),\n                                                parse_error::create(101, m_lexer.get_position(),\n                                                        exception_message(token_type::literal_or_value, \"value\")));\n                    }\n                }\n            }\n            else\n            {\n                skip_to_state_evaluation = false;\n            }\n\n            // we reached this line after we successfully parsed a value\n            if (states.empty())\n            {\n                // empty stack: we reached the end of the hierarchy: done\n                return true;\n            }\n            else\n            {\n                if (states.back())  // array\n                {\n                    // comma -> next value\n                    if (get_token() == token_type::value_separator)\n                    {\n                        // parse a new value\n                        get_token();\n                        continue;\n                    }\n\n                    // closing ]\n                    if (JSON_LIKELY(last_token == token_type::end_array))\n                    {\n                        if (JSON_UNLIKELY(not sax->end_array()))\n                        {\n                            return false;\n                        }\n\n                        // We are done with this array. Before we can parse a\n                        // new value, we need to evaluate the new state first.\n                        // By setting skip_to_state_evaluation to false, we\n                        // are effectively jumping to the beginning of this if.\n                        assert(not states.empty());\n                        states.pop_back();\n                        skip_to_state_evaluation = true;\n                        continue;\n                    }\n                    else\n                    {\n                        return sax->parse_error(m_lexer.get_position(),\n                                                m_lexer.get_token_string(),\n                                                parse_error::create(101, m_lexer.get_position(),\n                                                        exception_message(token_type::end_array, \"array\")));\n                    }\n                }\n                else  // object\n                {\n                    // comma -> next value\n                    if (get_token() == token_type::value_separator)\n                    {\n                        // parse key\n                        if (JSON_UNLIKELY(get_token() != token_type::value_string))\n                        {\n                            return sax->parse_error(m_lexer.get_position(),\n                                                    m_lexer.get_token_string(),\n                                                    parse_error::create(101, m_lexer.get_position(),\n                                                            exception_message(token_type::value_string, \"object key\")));\n                        }\n                        else\n                        {\n                            if (JSON_UNLIKELY(not sax->key(m_lexer.get_string())))\n                            {\n                                return false;\n                            }\n                        }\n\n                        // parse separator (:)\n                        if (JSON_UNLIKELY(get_token() != token_type::name_separator))\n                        {\n                            return sax->parse_error(m_lexer.get_position(),\n                                                    m_lexer.get_token_string(),\n                                                    parse_error::create(101, m_lexer.get_position(),\n                                                            exception_message(token_type::name_separator, \"object separator\")));\n                        }\n\n                        // parse values\n                        get_token();\n                        continue;\n                    }\n\n                    // closing }\n                    if (JSON_LIKELY(last_token == token_type::end_object))\n                    {\n                        if (JSON_UNLIKELY(not sax->end_object()))\n                        {\n                            return false;\n                        }\n\n                        // We are done with this object. Before we can parse a\n                        // new value, we need to evaluate the new state first.\n                        // By setting skip_to_state_evaluation to false, we\n                        // are effectively jumping to the beginning of this if.\n                        assert(not states.empty());\n                        states.pop_back();\n                        skip_to_state_evaluation = true;\n                        continue;\n                    }\n                    else\n                    {\n                        return sax->parse_error(m_lexer.get_position(),\n                                                m_lexer.get_token_string(),\n                                                parse_error::create(101, m_lexer.get_position(),\n                                                        exception_message(token_type::end_object, \"object\")));\n                    }\n                }\n            }\n        }\n    }\n\n    /// get next token from lexer\n    token_type get_token()\n    {\n        return (last_token = m_lexer.scan());\n    }\n\n    std::string exception_message(const token_type expected, const std::string& context)\n    {\n        std::string error_msg = \"syntax error \";\n\n        if (not context.empty())\n        {\n            error_msg += \"while parsing \" + context + \" \";\n        }\n\n        error_msg += \"- \";\n\n        if (last_token == token_type::parse_error)\n        {\n            error_msg += std::string(m_lexer.get_error_message()) + \"; last read: '\" +\n                         m_lexer.get_token_string() + \"'\";\n        }\n        else\n        {\n            error_msg += \"unexpected \" + std::string(lexer_t::token_type_name(last_token));\n        }\n\n        if (expected != token_type::uninitialized)\n        {\n            error_msg += \"; expected \" + std::string(lexer_t::token_type_name(expected));\n        }\n\n        return error_msg;\n    }\n\n  private:\n    /// callback function\n    const parser_callback_t callback = nullptr;\n    /// the type of the last read token\n    token_type last_token = token_type::uninitialized;\n    /// the lexer\n    lexer_t m_lexer;\n    /// whether to throw exceptions in case of errors\n    const bool allow_exceptions = true;\n};\n}  // namespace detail\n}  // namespace nlohmann\n"
  },
  {
    "path": "nlohmann_json/include/nlohmann/detail/input/position_t.hpp",
    "content": "#pragma once\n\n#include <cstddef> // size_t\n\nnamespace nlohmann\n{\nnamespace detail\n{\n/// struct to capture the start position of the current token\nstruct position_t\n{\n    /// the total number of characters read\n    std::size_t chars_read_total = 0;\n    /// the number of characters read in the current line\n    std::size_t chars_read_current_line = 0;\n    /// the number of lines read\n    std::size_t lines_read = 0;\n\n    /// conversion to size_t to preserve SAX interface\n    constexpr operator size_t() const\n    {\n        return chars_read_total;\n    }\n};\n\n}\n}\n"
  },
  {
    "path": "nlohmann_json/include/nlohmann/detail/iterators/internal_iterator.hpp",
    "content": "#pragma once\n\n#include <nlohmann/detail/iterators/primitive_iterator.hpp>\n\nnamespace nlohmann\n{\nnamespace detail\n{\n/*!\n@brief an iterator value\n\n@note This structure could easily be a union, but MSVC currently does not allow\nunions members with complex constructors, see https://github.com/nlohmann/json/pull/105.\n*/\ntemplate<typename BasicJsonType> struct internal_iterator\n{\n    /// iterator for JSON objects\n    typename BasicJsonType::object_t::iterator object_iterator {};\n    /// iterator for JSON arrays\n    typename BasicJsonType::array_t::iterator array_iterator {};\n    /// generic iterator for all other types\n    primitive_iterator_t primitive_iterator {};\n};\n}  // namespace detail\n}  // namespace nlohmann\n"
  },
  {
    "path": "nlohmann_json/include/nlohmann/detail/iterators/iter_impl.hpp",
    "content": "#pragma once\n\n#include <ciso646> // not\n#include <iterator> // iterator, random_access_iterator_tag, bidirectional_iterator_tag, advance, next\n#include <type_traits> // conditional, is_const, remove_const\n\n#include <nlohmann/detail/exceptions.hpp>\n#include <nlohmann/detail/iterators/internal_iterator.hpp>\n#include <nlohmann/detail/iterators/primitive_iterator.hpp>\n#include <nlohmann/detail/macro_scope.hpp>\n#include <nlohmann/detail/meta/cpp_future.hpp>\n#include <nlohmann/detail/value_t.hpp>\n\nnamespace nlohmann\n{\nnamespace detail\n{\n// forward declare, to be able to friend it later on\ntemplate<typename IteratorType> class iteration_proxy;\ntemplate<typename IteratorType> class iteration_proxy_value;\n\n/*!\n@brief a template for a bidirectional iterator for the @ref basic_json class\nThis class implements a both iterators (iterator and const_iterator) for the\n@ref basic_json class.\n@note An iterator is called *initialized* when a pointer to a JSON value has\n      been set (e.g., by a constructor or a copy assignment). If the iterator is\n      default-constructed, it is *uninitialized* and most methods are undefined.\n      **The library uses assertions to detect calls on uninitialized iterators.**\n@requirement The class satisfies the following concept requirements:\n-\n[BidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator):\n  The iterator that can be moved can be moved in both directions (i.e.\n  incremented and decremented).\n@since version 1.0.0, simplified in version 2.0.9, change to bidirectional\n       iterators in version 3.0.0 (see https://github.com/nlohmann/json/issues/593)\n*/\ntemplate<typename BasicJsonType>\nclass iter_impl\n{\n    /// allow basic_json to access private members\n    friend iter_impl<typename std::conditional<std::is_const<BasicJsonType>::value, typename std::remove_const<BasicJsonType>::type, const BasicJsonType>::type>;\n    friend BasicJsonType;\n    friend iteration_proxy<iter_impl>;\n    friend iteration_proxy_value<iter_impl>;\n\n    using object_t = typename BasicJsonType::object_t;\n    using array_t = typename BasicJsonType::array_t;\n    // make sure BasicJsonType is basic_json or const basic_json\n    static_assert(is_basic_json<typename std::remove_const<BasicJsonType>::type>::value,\n                  \"iter_impl only accepts (const) basic_json\");\n\n  public:\n\n    /// The std::iterator class template (used as a base class to provide typedefs) is deprecated in C++17.\n    /// The C++ Standard has never required user-defined iterators to derive from std::iterator.\n    /// A user-defined iterator should provide publicly accessible typedefs named\n    /// iterator_category, value_type, difference_type, pointer, and reference.\n    /// Note that value_type is required to be non-const, even for constant iterators.\n    using iterator_category = std::bidirectional_iterator_tag;\n\n    /// the type of the values when the iterator is dereferenced\n    using value_type = typename BasicJsonType::value_type;\n    /// a type to represent differences between iterators\n    using difference_type = typename BasicJsonType::difference_type;\n    /// defines a pointer to the type iterated over (value_type)\n    using pointer = typename std::conditional<std::is_const<BasicJsonType>::value,\n          typename BasicJsonType::const_pointer,\n          typename BasicJsonType::pointer>::type;\n    /// defines a reference to the type iterated over (value_type)\n    using reference =\n        typename std::conditional<std::is_const<BasicJsonType>::value,\n        typename BasicJsonType::const_reference,\n        typename BasicJsonType::reference>::type;\n\n    /// default constructor\n    iter_impl() = default;\n\n    /*!\n    @brief constructor for a given JSON instance\n    @param[in] object  pointer to a JSON object for this iterator\n    @pre object != nullptr\n    @post The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    explicit iter_impl(pointer object) noexcept : m_object(object)\n    {\n        assert(m_object != nullptr);\n\n        switch (m_object->m_type)\n        {\n            case value_t::object:\n            {\n                m_it.object_iterator = typename object_t::iterator();\n                break;\n            }\n\n            case value_t::array:\n            {\n                m_it.array_iterator = typename array_t::iterator();\n                break;\n            }\n\n            default:\n            {\n                m_it.primitive_iterator = primitive_iterator_t();\n                break;\n            }\n        }\n    }\n\n    /*!\n    @note The conventional copy constructor and copy assignment are implicitly\n          defined. Combined with the following converting constructor and\n          assignment, they support: (1) copy from iterator to iterator, (2)\n          copy from const iterator to const iterator, and (3) conversion from\n          iterator to const iterator. However conversion from const iterator\n          to iterator is not defined.\n    */\n\n    /*!\n    @brief converting constructor\n    @param[in] other  non-const iterator to copy from\n    @note It is not checked whether @a other is initialized.\n    */\n    iter_impl(const iter_impl<typename std::remove_const<BasicJsonType>::type>& other) noexcept\n        : m_object(other.m_object), m_it(other.m_it) {}\n\n    /*!\n    @brief converting assignment\n    @param[in,out] other  non-const iterator to copy from\n    @return const/non-const iterator\n    @note It is not checked whether @a other is initialized.\n    */\n    iter_impl& operator=(const iter_impl<typename std::remove_const<BasicJsonType>::type>& other) noexcept\n    {\n        m_object = other.m_object;\n        m_it = other.m_it;\n        return *this;\n    }\n\n  private:\n    /*!\n    @brief set the iterator to the first value\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    void set_begin() noexcept\n    {\n        assert(m_object != nullptr);\n\n        switch (m_object->m_type)\n        {\n            case value_t::object:\n            {\n                m_it.object_iterator = m_object->m_value.object->begin();\n                break;\n            }\n\n            case value_t::array:\n            {\n                m_it.array_iterator = m_object->m_value.array->begin();\n                break;\n            }\n\n            case value_t::null:\n            {\n                // set to end so begin()==end() is true: null is empty\n                m_it.primitive_iterator.set_end();\n                break;\n            }\n\n            default:\n            {\n                m_it.primitive_iterator.set_begin();\n                break;\n            }\n        }\n    }\n\n    /*!\n    @brief set the iterator past the last value\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    void set_end() noexcept\n    {\n        assert(m_object != nullptr);\n\n        switch (m_object->m_type)\n        {\n            case value_t::object:\n            {\n                m_it.object_iterator = m_object->m_value.object->end();\n                break;\n            }\n\n            case value_t::array:\n            {\n                m_it.array_iterator = m_object->m_value.array->end();\n                break;\n            }\n\n            default:\n            {\n                m_it.primitive_iterator.set_end();\n                break;\n            }\n        }\n    }\n\n  public:\n    /*!\n    @brief return a reference to the value pointed to by the iterator\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    reference operator*() const\n    {\n        assert(m_object != nullptr);\n\n        switch (m_object->m_type)\n        {\n            case value_t::object:\n            {\n                assert(m_it.object_iterator != m_object->m_value.object->end());\n                return m_it.object_iterator->second;\n            }\n\n            case value_t::array:\n            {\n                assert(m_it.array_iterator != m_object->m_value.array->end());\n                return *m_it.array_iterator;\n            }\n\n            case value_t::null:\n                JSON_THROW(invalid_iterator::create(214, \"cannot get value\"));\n\n            default:\n            {\n                if (JSON_LIKELY(m_it.primitive_iterator.is_begin()))\n                {\n                    return *m_object;\n                }\n\n                JSON_THROW(invalid_iterator::create(214, \"cannot get value\"));\n            }\n        }\n    }\n\n    /*!\n    @brief dereference the iterator\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    pointer operator->() const\n    {\n        assert(m_object != nullptr);\n\n        switch (m_object->m_type)\n        {\n            case value_t::object:\n            {\n                assert(m_it.object_iterator != m_object->m_value.object->end());\n                return &(m_it.object_iterator->second);\n            }\n\n            case value_t::array:\n            {\n                assert(m_it.array_iterator != m_object->m_value.array->end());\n                return &*m_it.array_iterator;\n            }\n\n            default:\n            {\n                if (JSON_LIKELY(m_it.primitive_iterator.is_begin()))\n                {\n                    return m_object;\n                }\n\n                JSON_THROW(invalid_iterator::create(214, \"cannot get value\"));\n            }\n        }\n    }\n\n    /*!\n    @brief post-increment (it++)\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    iter_impl const operator++(int)\n    {\n        auto result = *this;\n        ++(*this);\n        return result;\n    }\n\n    /*!\n    @brief pre-increment (++it)\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    iter_impl& operator++()\n    {\n        assert(m_object != nullptr);\n\n        switch (m_object->m_type)\n        {\n            case value_t::object:\n            {\n                std::advance(m_it.object_iterator, 1);\n                break;\n            }\n\n            case value_t::array:\n            {\n                std::advance(m_it.array_iterator, 1);\n                break;\n            }\n\n            default:\n            {\n                ++m_it.primitive_iterator;\n                break;\n            }\n        }\n\n        return *this;\n    }\n\n    /*!\n    @brief post-decrement (it--)\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    iter_impl const operator--(int)\n    {\n        auto result = *this;\n        --(*this);\n        return result;\n    }\n\n    /*!\n    @brief pre-decrement (--it)\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    iter_impl& operator--()\n    {\n        assert(m_object != nullptr);\n\n        switch (m_object->m_type)\n        {\n            case value_t::object:\n            {\n                std::advance(m_it.object_iterator, -1);\n                break;\n            }\n\n            case value_t::array:\n            {\n                std::advance(m_it.array_iterator, -1);\n                break;\n            }\n\n            default:\n            {\n                --m_it.primitive_iterator;\n                break;\n            }\n        }\n\n        return *this;\n    }\n\n    /*!\n    @brief  comparison: equal\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    bool operator==(const iter_impl& other) const\n    {\n        // if objects are not the same, the comparison is undefined\n        if (JSON_UNLIKELY(m_object != other.m_object))\n        {\n            JSON_THROW(invalid_iterator::create(212, \"cannot compare iterators of different containers\"));\n        }\n\n        assert(m_object != nullptr);\n\n        switch (m_object->m_type)\n        {\n            case value_t::object:\n                return (m_it.object_iterator == other.m_it.object_iterator);\n\n            case value_t::array:\n                return (m_it.array_iterator == other.m_it.array_iterator);\n\n            default:\n                return (m_it.primitive_iterator == other.m_it.primitive_iterator);\n        }\n    }\n\n    /*!\n    @brief  comparison: not equal\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    bool operator!=(const iter_impl& other) const\n    {\n        return not operator==(other);\n    }\n\n    /*!\n    @brief  comparison: smaller\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    bool operator<(const iter_impl& other) const\n    {\n        // if objects are not the same, the comparison is undefined\n        if (JSON_UNLIKELY(m_object != other.m_object))\n        {\n            JSON_THROW(invalid_iterator::create(212, \"cannot compare iterators of different containers\"));\n        }\n\n        assert(m_object != nullptr);\n\n        switch (m_object->m_type)\n        {\n            case value_t::object:\n                JSON_THROW(invalid_iterator::create(213, \"cannot compare order of object iterators\"));\n\n            case value_t::array:\n                return (m_it.array_iterator < other.m_it.array_iterator);\n\n            default:\n                return (m_it.primitive_iterator < other.m_it.primitive_iterator);\n        }\n    }\n\n    /*!\n    @brief  comparison: less than or equal\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    bool operator<=(const iter_impl& other) const\n    {\n        return not other.operator < (*this);\n    }\n\n    /*!\n    @brief  comparison: greater than\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    bool operator>(const iter_impl& other) const\n    {\n        return not operator<=(other);\n    }\n\n    /*!\n    @brief  comparison: greater than or equal\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    bool operator>=(const iter_impl& other) const\n    {\n        return not operator<(other);\n    }\n\n    /*!\n    @brief  add to iterator\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    iter_impl& operator+=(difference_type i)\n    {\n        assert(m_object != nullptr);\n\n        switch (m_object->m_type)\n        {\n            case value_t::object:\n                JSON_THROW(invalid_iterator::create(209, \"cannot use offsets with object iterators\"));\n\n            case value_t::array:\n            {\n                std::advance(m_it.array_iterator, i);\n                break;\n            }\n\n            default:\n            {\n                m_it.primitive_iterator += i;\n                break;\n            }\n        }\n\n        return *this;\n    }\n\n    /*!\n    @brief  subtract from iterator\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    iter_impl& operator-=(difference_type i)\n    {\n        return operator+=(-i);\n    }\n\n    /*!\n    @brief  add to iterator\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    iter_impl operator+(difference_type i) const\n    {\n        auto result = *this;\n        result += i;\n        return result;\n    }\n\n    /*!\n    @brief  addition of distance and iterator\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    friend iter_impl operator+(difference_type i, const iter_impl& it)\n    {\n        auto result = it;\n        result += i;\n        return result;\n    }\n\n    /*!\n    @brief  subtract from iterator\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    iter_impl operator-(difference_type i) const\n    {\n        auto result = *this;\n        result -= i;\n        return result;\n    }\n\n    /*!\n    @brief  return difference\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    difference_type operator-(const iter_impl& other) const\n    {\n        assert(m_object != nullptr);\n\n        switch (m_object->m_type)\n        {\n            case value_t::object:\n                JSON_THROW(invalid_iterator::create(209, \"cannot use offsets with object iterators\"));\n\n            case value_t::array:\n                return m_it.array_iterator - other.m_it.array_iterator;\n\n            default:\n                return m_it.primitive_iterator - other.m_it.primitive_iterator;\n        }\n    }\n\n    /*!\n    @brief  access to successor\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    reference operator[](difference_type n) const\n    {\n        assert(m_object != nullptr);\n\n        switch (m_object->m_type)\n        {\n            case value_t::object:\n                JSON_THROW(invalid_iterator::create(208, \"cannot use operator[] for object iterators\"));\n\n            case value_t::array:\n                return *std::next(m_it.array_iterator, n);\n\n            case value_t::null:\n                JSON_THROW(invalid_iterator::create(214, \"cannot get value\"));\n\n            default:\n            {\n                if (JSON_LIKELY(m_it.primitive_iterator.get_value() == -n))\n                {\n                    return *m_object;\n                }\n\n                JSON_THROW(invalid_iterator::create(214, \"cannot get value\"));\n            }\n        }\n    }\n\n    /*!\n    @brief  return the key of an object iterator\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    const typename object_t::key_type& key() const\n    {\n        assert(m_object != nullptr);\n\n        if (JSON_LIKELY(m_object->is_object()))\n        {\n            return m_it.object_iterator->first;\n        }\n\n        JSON_THROW(invalid_iterator::create(207, \"cannot use key() for non-object iterators\"));\n    }\n\n    /*!\n    @brief  return the value of an iterator\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    reference value() const\n    {\n        return operator*();\n    }\n\n  private:\n    /// associated JSON instance\n    pointer m_object = nullptr;\n    /// the actual iterator of the associated instance\n    internal_iterator<typename std::remove_const<BasicJsonType>::type> m_it;\n};\n}  // namespace detail\n} // namespace nlohmann"
  },
  {
    "path": "nlohmann_json/include/nlohmann/detail/iterators/iteration_proxy.hpp",
    "content": "#pragma once\n\n#include <cstddef> // size_t\n#include <string> // string, to_string\n#include <iterator> // input_iterator_tag\n#include <tuple> // tuple_size, get, tuple_element\n\n#include <nlohmann/detail/value_t.hpp>\n#include <nlohmann/detail/meta/type_traits.hpp>\n\nnamespace nlohmann\n{\nnamespace detail\n{\ntemplate <typename IteratorType> class iteration_proxy_value\n{\n  public:\n    using difference_type = std::ptrdiff_t;\n    using value_type = iteration_proxy_value;\n    using pointer = value_type * ;\n    using reference = value_type & ;\n    using iterator_category = std::input_iterator_tag;\n\n  private:\n    /// the iterator\n    IteratorType anchor;\n    /// an index for arrays (used to create key names)\n    std::size_t array_index = 0;\n    /// last stringified array index\n    mutable std::size_t array_index_last = 0;\n    /// a string representation of the array index\n    mutable std::string array_index_str = \"0\";\n    /// an empty string (to return a reference for primitive values)\n    const std::string empty_str = \"\";\n\n  public:\n    explicit iteration_proxy_value(IteratorType it) noexcept : anchor(it) {}\n\n    /// dereference operator (needed for range-based for)\n    iteration_proxy_value& operator*()\n    {\n        return *this;\n    }\n\n    /// increment operator (needed for range-based for)\n    iteration_proxy_value& operator++()\n    {\n        ++anchor;\n        ++array_index;\n\n        return *this;\n    }\n\n    /// equality operator (needed for InputIterator)\n    bool operator==(const iteration_proxy_value& o) const noexcept\n    {\n        return anchor == o.anchor;\n    }\n\n    /// inequality operator (needed for range-based for)\n    bool operator!=(const iteration_proxy_value& o) const noexcept\n    {\n        return anchor != o.anchor;\n    }\n\n    /// return key of the iterator\n    const std::string& key() const\n    {\n        assert(anchor.m_object != nullptr);\n\n        switch (anchor.m_object->type())\n        {\n            // use integer array index as key\n            case value_t::array:\n            {\n                if (array_index != array_index_last)\n                {\n                    array_index_str = std::to_string(array_index);\n                    array_index_last = array_index;\n                }\n                return array_index_str;\n            }\n\n            // use key from the object\n            case value_t::object:\n                return anchor.key();\n\n            // use an empty key for all primitive types\n            default:\n                return empty_str;\n        }\n    }\n\n    /// return value of the iterator\n    typename IteratorType::reference value() const\n    {\n        return anchor.value();\n    }\n};\n\n/// proxy class for the items() function\ntemplate<typename IteratorType> class iteration_proxy\n{\n  private:\n    /// the container to iterate\n    typename IteratorType::reference container;\n\n  public:\n    /// construct iteration proxy from a container\n    explicit iteration_proxy(typename IteratorType::reference cont) noexcept\n        : container(cont) {}\n\n    /// return iterator begin (needed for range-based for)\n    iteration_proxy_value<IteratorType> begin() noexcept\n    {\n        return iteration_proxy_value<IteratorType>(container.begin());\n    }\n\n    /// return iterator end (needed for range-based for)\n    iteration_proxy_value<IteratorType> end() noexcept\n    {\n        return iteration_proxy_value<IteratorType>(container.end());\n    }\n};\n// Structured Bindings Support\n// For further reference see https://blog.tartanllama.xyz/structured-bindings/\n// And see https://github.com/nlohmann/json/pull/1391\ntemplate <std::size_t N, typename IteratorType, enable_if_t<N == 0, int> = 0>\nauto get(const nlohmann::detail::iteration_proxy_value<IteratorType>& i) -> decltype(i.key())\n{\n    return i.key();\n}\n// Structured Bindings Support\n// For further reference see https://blog.tartanllama.xyz/structured-bindings/\n// And see https://github.com/nlohmann/json/pull/1391\ntemplate <std::size_t N, typename IteratorType, enable_if_t<N == 1, int> = 0>\nauto get(const nlohmann::detail::iteration_proxy_value<IteratorType>& i) -> decltype(i.value())\n{\n    return i.value();\n}\n}  // namespace detail\n}  // namespace nlohmann\n\n// The Addition to the STD Namespace is required to add\n// Structured Bindings Support to the iteration_proxy_value class\n// For further reference see https://blog.tartanllama.xyz/structured-bindings/\n// And see https://github.com/nlohmann/json/pull/1391\nnamespace std\n{\ntemplate <typename IteratorType>\nclass tuple_size<::nlohmann::detail::iteration_proxy_value<IteratorType>>\n            : public std::integral_constant<std::size_t, 2> {};\n\ntemplate <std::size_t N, typename IteratorType>\nclass tuple_element<N, ::nlohmann::detail::iteration_proxy_value<IteratorType >>\n{\n  public:\n    using type = decltype(\n                     get<N>(std::declval <\n                            ::nlohmann::detail::iteration_proxy_value<IteratorType >> ()));\n};\n}"
  },
  {
    "path": "nlohmann_json/include/nlohmann/detail/iterators/iterator_traits.hpp",
    "content": "#pragma once\n\n#include <iterator> // random_access_iterator_tag\n\n#include <nlohmann/detail/meta/void_t.hpp>\n#include <nlohmann/detail/meta/cpp_future.hpp>\n\nnamespace nlohmann\n{\nnamespace detail\n{\ntemplate <typename It, typename = void>\nstruct iterator_types {};\n\ntemplate <typename It>\nstruct iterator_types<\n    It,\n    void_t<typename It::difference_type, typename It::value_type, typename It::pointer,\n           typename It::reference, typename It::iterator_category>> {\n  using difference_type = typename It::difference_type;\n  using value_type = typename It::value_type;\n  using pointer = typename It::pointer;\n  using reference = typename It::reference;\n  using iterator_category = typename It::iterator_category;\n};\n\n// This is required as some compilers implement std::iterator_traits in a way that\n// doesn't work with SFINAE. See https://github.com/nlohmann/json/issues/1341.\ntemplate <typename T, typename = void>\nstruct iterator_traits\n{\n};\n\ntemplate <typename T>\nstruct iterator_traits<T, enable_if_t<!std::is_pointer<T>::value>>\n  : iterator_types<T>\n{\n};\n\ntemplate <typename T>\nstruct iterator_traits<T*, enable_if_t<std::is_object<T>::value>> {\n  using iterator_category = std::random_access_iterator_tag;\n  using value_type = T;\n  using difference_type = ptrdiff_t;\n  using pointer = T*;\n  using reference = T&;\n};\n}\n}\n"
  },
  {
    "path": "nlohmann_json/include/nlohmann/detail/iterators/json_reverse_iterator.hpp",
    "content": "#pragma once\n\n#include <cstddef> // ptrdiff_t\n#include <iterator> // reverse_iterator\n#include <utility> // declval\n\nnamespace nlohmann\n{\nnamespace detail\n{\n//////////////////////\n// reverse_iterator //\n//////////////////////\n\n/*!\n@brief a template for a reverse iterator class\n\n@tparam Base the base iterator type to reverse. Valid types are @ref\niterator (to create @ref reverse_iterator) and @ref const_iterator (to\ncreate @ref const_reverse_iterator).\n\n@requirement The class satisfies the following concept requirements:\n-\n[BidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator):\n  The iterator that can be moved can be moved in both directions (i.e.\n  incremented and decremented).\n- [OutputIterator](https://en.cppreference.com/w/cpp/named_req/OutputIterator):\n  It is possible to write to the pointed-to element (only if @a Base is\n  @ref iterator).\n\n@since version 1.0.0\n*/\ntemplate<typename Base>\nclass json_reverse_iterator : public std::reverse_iterator<Base>\n{\n  public:\n    using difference_type = std::ptrdiff_t;\n    /// shortcut to the reverse iterator adapter\n    using base_iterator = std::reverse_iterator<Base>;\n    /// the reference type for the pointed-to element\n    using reference = typename Base::reference;\n\n    /// create reverse iterator from iterator\n    explicit json_reverse_iterator(const typename base_iterator::iterator_type& it) noexcept\n        : base_iterator(it) {}\n\n    /// create reverse iterator from base class\n    explicit json_reverse_iterator(const base_iterator& it) noexcept : base_iterator(it) {}\n\n    /// post-increment (it++)\n    json_reverse_iterator const operator++(int)\n    {\n        return static_cast<json_reverse_iterator>(base_iterator::operator++(1));\n    }\n\n    /// pre-increment (++it)\n    json_reverse_iterator& operator++()\n    {\n        return static_cast<json_reverse_iterator&>(base_iterator::operator++());\n    }\n\n    /// post-decrement (it--)\n    json_reverse_iterator const operator--(int)\n    {\n        return static_cast<json_reverse_iterator>(base_iterator::operator--(1));\n    }\n\n    /// pre-decrement (--it)\n    json_reverse_iterator& operator--()\n    {\n        return static_cast<json_reverse_iterator&>(base_iterator::operator--());\n    }\n\n    /// add to iterator\n    json_reverse_iterator& operator+=(difference_type i)\n    {\n        return static_cast<json_reverse_iterator&>(base_iterator::operator+=(i));\n    }\n\n    /// add to iterator\n    json_reverse_iterator operator+(difference_type i) const\n    {\n        return static_cast<json_reverse_iterator>(base_iterator::operator+(i));\n    }\n\n    /// subtract from iterator\n    json_reverse_iterator operator-(difference_type i) const\n    {\n        return static_cast<json_reverse_iterator>(base_iterator::operator-(i));\n    }\n\n    /// return difference\n    difference_type operator-(const json_reverse_iterator& other) const\n    {\n        return base_iterator(*this) - base_iterator(other);\n    }\n\n    /// access to successor\n    reference operator[](difference_type n) const\n    {\n        return *(this->operator+(n));\n    }\n\n    /// return the key of an object iterator\n    auto key() const -> decltype(std::declval<Base>().key())\n    {\n        auto it = --this->base();\n        return it.key();\n    }\n\n    /// return the value of an iterator\n    reference value() const\n    {\n        auto it = --this->base();\n        return it.operator * ();\n    }\n};\n}  // namespace detail\n}  // namespace nlohmann\n"
  },
  {
    "path": "nlohmann_json/include/nlohmann/detail/iterators/primitive_iterator.hpp",
    "content": "#pragma once\n\n#include <cstddef> // ptrdiff_t\n#include <limits>  // numeric_limits\n\nnamespace nlohmann\n{\nnamespace detail\n{\n/*\n@brief an iterator for primitive JSON types\n\nThis class models an iterator for primitive JSON types (boolean, number,\nstring). It's only purpose is to allow the iterator/const_iterator classes\nto \"iterate\" over primitive values. Internally, the iterator is modeled by\na `difference_type` variable. Value begin_value (`0`) models the begin,\nend_value (`1`) models past the end.\n*/\nclass primitive_iterator_t\n{\n  private:\n    using difference_type = std::ptrdiff_t;\n    static constexpr difference_type begin_value = 0;\n    static constexpr difference_type end_value = begin_value + 1;\n\n    /// iterator as signed integer type\n    difference_type m_it = (std::numeric_limits<std::ptrdiff_t>::min)();\n\n  public:\n    constexpr difference_type get_value() const noexcept\n    {\n        return m_it;\n    }\n\n    /// set iterator to a defined beginning\n    void set_begin() noexcept\n    {\n        m_it = begin_value;\n    }\n\n    /// set iterator to a defined past the end\n    void set_end() noexcept\n    {\n        m_it = end_value;\n    }\n\n    /// return whether the iterator can be dereferenced\n    constexpr bool is_begin() const noexcept\n    {\n        return m_it == begin_value;\n    }\n\n    /// return whether the iterator is at end\n    constexpr bool is_end() const noexcept\n    {\n        return m_it == end_value;\n    }\n\n    friend constexpr bool operator==(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept\n    {\n        return lhs.m_it == rhs.m_it;\n    }\n\n    friend constexpr bool operator<(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept\n    {\n        return lhs.m_it < rhs.m_it;\n    }\n\n    primitive_iterator_t operator+(difference_type n) noexcept\n    {\n        auto result = *this;\n        result += n;\n        return result;\n    }\n\n    friend constexpr difference_type operator-(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept\n    {\n        return lhs.m_it - rhs.m_it;\n    }\n\n    primitive_iterator_t& operator++() noexcept\n    {\n        ++m_it;\n        return *this;\n    }\n\n    primitive_iterator_t const operator++(int) noexcept\n    {\n        auto result = *this;\n        ++m_it;\n        return result;\n    }\n\n    primitive_iterator_t& operator--() noexcept\n    {\n        --m_it;\n        return *this;\n    }\n\n    primitive_iterator_t const operator--(int) noexcept\n    {\n        auto result = *this;\n        --m_it;\n        return result;\n    }\n\n    primitive_iterator_t& operator+=(difference_type n) noexcept\n    {\n        m_it += n;\n        return *this;\n    }\n\n    primitive_iterator_t& operator-=(difference_type n) noexcept\n    {\n        m_it -= n;\n        return *this;\n    }\n};\n}  // namespace detail\n}  // namespace nlohmann\n"
  },
  {
    "path": "nlohmann_json/include/nlohmann/detail/json_pointer.hpp",
    "content": "#pragma once\n\n#include <cassert> // assert\n#include <numeric> // accumulate\n#include <string> // string\n#include <vector> // vector\n\n#include <nlohmann/detail/macro_scope.hpp>\n#include <nlohmann/detail/exceptions.hpp>\n#include <nlohmann/detail/value_t.hpp>\n\nnamespace nlohmann\n{\ntemplate<typename BasicJsonType>\nclass json_pointer\n{\n    // allow basic_json to access private members\n    NLOHMANN_BASIC_JSON_TPL_DECLARATION\n    friend class basic_json;\n\n  public:\n    /*!\n    @brief create JSON pointer\n\n    Create a JSON pointer according to the syntax described in\n    [Section 3 of RFC6901](https://tools.ietf.org/html/rfc6901#section-3).\n\n    @param[in] s  string representing the JSON pointer; if omitted, the empty\n                  string is assumed which references the whole JSON value\n\n    @throw parse_error.107 if the given JSON pointer @a s is nonempty and does\n                           not begin with a slash (`/`); see example below\n\n    @throw parse_error.108 if a tilde (`~`) in the given JSON pointer @a s is\n    not followed by `0` (representing `~`) or `1` (representing `/`); see\n    example below\n\n    @liveexample{The example shows the construction several valid JSON pointers\n    as well as the exceptional behavior.,json_pointer}\n\n    @since version 2.0.0\n    */\n    explicit json_pointer(const std::string& s = \"\")\n        : reference_tokens(split(s))\n    {}\n\n    /*!\n    @brief return a string representation of the JSON pointer\n\n    @invariant For each JSON pointer `ptr`, it holds:\n    @code {.cpp}\n    ptr == json_pointer(ptr.to_string());\n    @endcode\n\n    @return a string representation of the JSON pointer\n\n    @liveexample{The example shows the result of `to_string`.,\n    json_pointer__to_string}\n\n    @since version 2.0.0\n    */\n    std::string to_string() const\n    {\n        return std::accumulate(reference_tokens.begin(), reference_tokens.end(),\n                               std::string{},\n                               [](const std::string & a, const std::string & b)\n        {\n            return a + \"/\" + escape(b);\n        });\n    }\n\n    /// @copydoc to_string()\n    operator std::string() const\n    {\n        return to_string();\n    }\n\n    /*!\n    @param[in] s  reference token to be converted into an array index\n\n    @return integer representation of @a s\n\n    @throw out_of_range.404 if string @a s could not be converted to an integer\n    */\n    static int array_index(const std::string& s)\n    {\n        std::size_t processed_chars = 0;\n        const int res = std::stoi(s, &processed_chars);\n\n        // check if the string was completely read\n        if (JSON_UNLIKELY(processed_chars != s.size()))\n        {\n            JSON_THROW(detail::out_of_range::create(404, \"unresolved reference token '\" + s + \"'\"));\n        }\n\n        return res;\n    }\n\n  private:\n    /*!\n    @brief remove and return last reference pointer\n    @throw out_of_range.405 if JSON pointer has no parent\n    */\n    std::string pop_back()\n    {\n        if (JSON_UNLIKELY(is_root()))\n        {\n            JSON_THROW(detail::out_of_range::create(405, \"JSON pointer has no parent\"));\n        }\n\n        auto last = reference_tokens.back();\n        reference_tokens.pop_back();\n        return last;\n    }\n\n    /// return whether pointer points to the root document\n    bool is_root() const noexcept\n    {\n        return reference_tokens.empty();\n    }\n\n    json_pointer top() const\n    {\n        if (JSON_UNLIKELY(is_root()))\n        {\n            JSON_THROW(detail::out_of_range::create(405, \"JSON pointer has no parent\"));\n        }\n\n        json_pointer result = *this;\n        result.reference_tokens = {reference_tokens[0]};\n        return result;\n    }\n\n    /*!\n    @brief create and return a reference to the pointed to value\n\n    @complexity Linear in the number of reference tokens.\n\n    @throw parse_error.109 if array index is not a number\n    @throw type_error.313 if value cannot be unflattened\n    */\n    BasicJsonType& get_and_create(BasicJsonType& j) const\n    {\n        using size_type = typename BasicJsonType::size_type;\n        auto result = &j;\n\n        // in case no reference tokens exist, return a reference to the JSON value\n        // j which will be overwritten by a primitive value\n        for (const auto& reference_token : reference_tokens)\n        {\n            switch (result->m_type)\n            {\n                case detail::value_t::null:\n                {\n                    if (reference_token == \"0\")\n                    {\n                        // start a new array if reference token is 0\n                        result = &result->operator[](0);\n                    }\n                    else\n                    {\n                        // start a new object otherwise\n                        result = &result->operator[](reference_token);\n                    }\n                    break;\n                }\n\n                case detail::value_t::object:\n                {\n                    // create an entry in the object\n                    result = &result->operator[](reference_token);\n                    break;\n                }\n\n                case detail::value_t::array:\n                {\n                    // create an entry in the array\n                    JSON_TRY\n                    {\n                        result = &result->operator[](static_cast<size_type>(array_index(reference_token)));\n                    }\n                    JSON_CATCH(std::invalid_argument&)\n                    {\n                        JSON_THROW(detail::parse_error::create(109, 0, \"array index '\" + reference_token + \"' is not a number\"));\n                    }\n                    break;\n                }\n\n                /*\n                The following code is only reached if there exists a reference\n                token _and_ the current value is primitive. In this case, we have\n                an error situation, because primitive values may only occur as\n                single value; that is, with an empty list of reference tokens.\n                */\n                default:\n                    JSON_THROW(detail::type_error::create(313, \"invalid value to unflatten\"));\n            }\n        }\n\n        return *result;\n    }\n\n    /*!\n    @brief return a reference to the pointed to value\n\n    @note This version does not throw if a value is not present, but tries to\n          create nested values instead. For instance, calling this function\n          with pointer `\"/this/that\"` on a null value is equivalent to calling\n          `operator[](\"this\").operator[](\"that\")` on that value, effectively\n          changing the null value to an object.\n\n    @param[in] ptr  a JSON value\n\n    @return reference to the JSON value pointed to by the JSON pointer\n\n    @complexity Linear in the length of the JSON pointer.\n\n    @throw parse_error.106   if an array index begins with '0'\n    @throw parse_error.109   if an array index was not a number\n    @throw out_of_range.404  if the JSON pointer can not be resolved\n    */\n    BasicJsonType& get_unchecked(BasicJsonType* ptr) const\n    {\n        using size_type = typename BasicJsonType::size_type;\n        for (const auto& reference_token : reference_tokens)\n        {\n            // convert null values to arrays or objects before continuing\n            if (ptr->m_type == detail::value_t::null)\n            {\n                // check if reference token is a number\n                const bool nums =\n                    std::all_of(reference_token.begin(), reference_token.end(),\n                                [](const char x)\n                {\n                    return (x >= '0' and x <= '9');\n                });\n\n                // change value to array for numbers or \"-\" or to object otherwise\n                *ptr = (nums or reference_token == \"-\")\n                       ? detail::value_t::array\n                       : detail::value_t::object;\n            }\n\n            switch (ptr->m_type)\n            {\n                case detail::value_t::object:\n                {\n                    // use unchecked object access\n                    ptr = &ptr->operator[](reference_token);\n                    break;\n                }\n\n                case detail::value_t::array:\n                {\n                    // error condition (cf. RFC 6901, Sect. 4)\n                    if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0'))\n                    {\n                        JSON_THROW(detail::parse_error::create(106, 0,\n                                                               \"array index '\" + reference_token +\n                                                               \"' must not begin with '0'\"));\n                    }\n\n                    if (reference_token == \"-\")\n                    {\n                        // explicitly treat \"-\" as index beyond the end\n                        ptr = &ptr->operator[](ptr->m_value.array->size());\n                    }\n                    else\n                    {\n                        // convert array index to number; unchecked access\n                        JSON_TRY\n                        {\n                            ptr = &ptr->operator[](\n                                static_cast<size_type>(array_index(reference_token)));\n                        }\n                        JSON_CATCH(std::invalid_argument&)\n                        {\n                            JSON_THROW(detail::parse_error::create(109, 0, \"array index '\" + reference_token + \"' is not a number\"));\n                        }\n                    }\n                    break;\n                }\n\n                default:\n                    JSON_THROW(detail::out_of_range::create(404, \"unresolved reference token '\" + reference_token + \"'\"));\n            }\n        }\n\n        return *ptr;\n    }\n\n    /*!\n    @throw parse_error.106   if an array index begins with '0'\n    @throw parse_error.109   if an array index was not a number\n    @throw out_of_range.402  if the array index '-' is used\n    @throw out_of_range.404  if the JSON pointer can not be resolved\n    */\n    BasicJsonType& get_checked(BasicJsonType* ptr) const\n    {\n        using size_type = typename BasicJsonType::size_type;\n        for (const auto& reference_token : reference_tokens)\n        {\n            switch (ptr->m_type)\n            {\n                case detail::value_t::object:\n                {\n                    // note: at performs range check\n                    ptr = &ptr->at(reference_token);\n                    break;\n                }\n\n                case detail::value_t::array:\n                {\n                    if (JSON_UNLIKELY(reference_token == \"-\"))\n                    {\n                        // \"-\" always fails the range check\n                        JSON_THROW(detail::out_of_range::create(402,\n                                                                \"array index '-' (\" + std::to_string(ptr->m_value.array->size()) +\n                                                                \") is out of range\"));\n                    }\n\n                    // error condition (cf. RFC 6901, Sect. 4)\n                    if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0'))\n                    {\n                        JSON_THROW(detail::parse_error::create(106, 0,\n                                                               \"array index '\" + reference_token +\n                                                               \"' must not begin with '0'\"));\n                    }\n\n                    // note: at performs range check\n                    JSON_TRY\n                    {\n                        ptr = &ptr->at(static_cast<size_type>(array_index(reference_token)));\n                    }\n                    JSON_CATCH(std::invalid_argument&)\n                    {\n                        JSON_THROW(detail::parse_error::create(109, 0, \"array index '\" + reference_token + \"' is not a number\"));\n                    }\n                    break;\n                }\n\n                default:\n                    JSON_THROW(detail::out_of_range::create(404, \"unresolved reference token '\" + reference_token + \"'\"));\n            }\n        }\n\n        return *ptr;\n    }\n\n    /*!\n    @brief return a const reference to the pointed to value\n\n    @param[in] ptr  a JSON value\n\n    @return const reference to the JSON value pointed to by the JSON\n    pointer\n\n    @throw parse_error.106   if an array index begins with '0'\n    @throw parse_error.109   if an array index was not a number\n    @throw out_of_range.402  if the array index '-' is used\n    @throw out_of_range.404  if the JSON pointer can not be resolved\n    */\n    const BasicJsonType& get_unchecked(const BasicJsonType* ptr) const\n    {\n        using size_type = typename BasicJsonType::size_type;\n        for (const auto& reference_token : reference_tokens)\n        {\n            switch (ptr->m_type)\n            {\n                case detail::value_t::object:\n                {\n                    // use unchecked object access\n                    ptr = &ptr->operator[](reference_token);\n                    break;\n                }\n\n                case detail::value_t::array:\n                {\n                    if (JSON_UNLIKELY(reference_token == \"-\"))\n                    {\n                        // \"-\" cannot be used for const access\n                        JSON_THROW(detail::out_of_range::create(402,\n                                                                \"array index '-' (\" + std::to_string(ptr->m_value.array->size()) +\n                                                                \") is out of range\"));\n                    }\n\n                    // error condition (cf. RFC 6901, Sect. 4)\n                    if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0'))\n                    {\n                        JSON_THROW(detail::parse_error::create(106, 0,\n                                                               \"array index '\" + reference_token +\n                                                               \"' must not begin with '0'\"));\n                    }\n\n                    // use unchecked array access\n                    JSON_TRY\n                    {\n                        ptr = &ptr->operator[](\n                            static_cast<size_type>(array_index(reference_token)));\n                    }\n                    JSON_CATCH(std::invalid_argument&)\n                    {\n                        JSON_THROW(detail::parse_error::create(109, 0, \"array index '\" + reference_token + \"' is not a number\"));\n                    }\n                    break;\n                }\n\n                default:\n                    JSON_THROW(detail::out_of_range::create(404, \"unresolved reference token '\" + reference_token + \"'\"));\n            }\n        }\n\n        return *ptr;\n    }\n\n    /*!\n    @throw parse_error.106   if an array index begins with '0'\n    @throw parse_error.109   if an array index was not a number\n    @throw out_of_range.402  if the array index '-' is used\n    @throw out_of_range.404  if the JSON pointer can not be resolved\n    */\n    const BasicJsonType& get_checked(const BasicJsonType* ptr) const\n    {\n        using size_type = typename BasicJsonType::size_type;\n        for (const auto& reference_token : reference_tokens)\n        {\n            switch (ptr->m_type)\n            {\n                case detail::value_t::object:\n                {\n                    // note: at performs range check\n                    ptr = &ptr->at(reference_token);\n                    break;\n                }\n\n                case detail::value_t::array:\n                {\n                    if (JSON_UNLIKELY(reference_token == \"-\"))\n                    {\n                        // \"-\" always fails the range check\n                        JSON_THROW(detail::out_of_range::create(402,\n                                                                \"array index '-' (\" + std::to_string(ptr->m_value.array->size()) +\n                                                                \") is out of range\"));\n                    }\n\n                    // error condition (cf. RFC 6901, Sect. 4)\n                    if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0'))\n                    {\n                        JSON_THROW(detail::parse_error::create(106, 0,\n                                                               \"array index '\" + reference_token +\n                                                               \"' must not begin with '0'\"));\n                    }\n\n                    // note: at performs range check\n                    JSON_TRY\n                    {\n                        ptr = &ptr->at(static_cast<size_type>(array_index(reference_token)));\n                    }\n                    JSON_CATCH(std::invalid_argument&)\n                    {\n                        JSON_THROW(detail::parse_error::create(109, 0, \"array index '\" + reference_token + \"' is not a number\"));\n                    }\n                    break;\n                }\n\n                default:\n                    JSON_THROW(detail::out_of_range::create(404, \"unresolved reference token '\" + reference_token + \"'\"));\n            }\n        }\n\n        return *ptr;\n    }\n\n    /*!\n    @brief split the string input to reference tokens\n\n    @note This function is only called by the json_pointer constructor.\n          All exceptions below are documented there.\n\n    @throw parse_error.107  if the pointer is not empty or begins with '/'\n    @throw parse_error.108  if character '~' is not followed by '0' or '1'\n    */\n    static std::vector<std::string> split(const std::string& reference_string)\n    {\n        std::vector<std::string> result;\n\n        // special case: empty reference string -> no reference tokens\n        if (reference_string.empty())\n        {\n            return result;\n        }\n\n        // check if nonempty reference string begins with slash\n        if (JSON_UNLIKELY(reference_string[0] != '/'))\n        {\n            JSON_THROW(detail::parse_error::create(107, 1,\n                                                   \"JSON pointer must be empty or begin with '/' - was: '\" +\n                                                   reference_string + \"'\"));\n        }\n\n        // extract the reference tokens:\n        // - slash: position of the last read slash (or end of string)\n        // - start: position after the previous slash\n        for (\n            // search for the first slash after the first character\n            std::size_t slash = reference_string.find_first_of('/', 1),\n            // set the beginning of the first reference token\n            start = 1;\n            // we can stop if start == 0 (if slash == std::string::npos)\n            start != 0;\n            // set the beginning of the next reference token\n            // (will eventually be 0 if slash == std::string::npos)\n            start = (slash == std::string::npos) ? 0 : slash + 1,\n            // find next slash\n            slash = reference_string.find_first_of('/', start))\n        {\n            // use the text between the beginning of the reference token\n            // (start) and the last slash (slash).\n            auto reference_token = reference_string.substr(start, slash - start);\n\n            // check reference tokens are properly escaped\n            for (std::size_t pos = reference_token.find_first_of('~');\n                    pos != std::string::npos;\n                    pos = reference_token.find_first_of('~', pos + 1))\n            {\n                assert(reference_token[pos] == '~');\n\n                // ~ must be followed by 0 or 1\n                if (JSON_UNLIKELY(pos == reference_token.size() - 1 or\n                                  (reference_token[pos + 1] != '0' and\n                                   reference_token[pos + 1] != '1')))\n                {\n                    JSON_THROW(detail::parse_error::create(108, 0, \"escape character '~' must be followed with '0' or '1'\"));\n                }\n            }\n\n            // finally, store the reference token\n            unescape(reference_token);\n            result.push_back(reference_token);\n        }\n\n        return result;\n    }\n\n    /*!\n    @brief replace all occurrences of a substring by another string\n\n    @param[in,out] s  the string to manipulate; changed so that all\n                   occurrences of @a f are replaced with @a t\n    @param[in]     f  the substring to replace with @a t\n    @param[in]     t  the string to replace @a f\n\n    @pre The search string @a f must not be empty. **This precondition is\n    enforced with an assertion.**\n\n    @since version 2.0.0\n    */\n    static void replace_substring(std::string& s, const std::string& f,\n                                  const std::string& t)\n    {\n        assert(not f.empty());\n        for (auto pos = s.find(f);                // find first occurrence of f\n                pos != std::string::npos;         // make sure f was found\n                s.replace(pos, f.size(), t),      // replace with t, and\n                pos = s.find(f, pos + t.size()))  // find next occurrence of f\n        {}\n    }\n\n    /// escape \"~\" to \"~0\" and \"/\" to \"~1\"\n    static std::string escape(std::string s)\n    {\n        replace_substring(s, \"~\", \"~0\");\n        replace_substring(s, \"/\", \"~1\");\n        return s;\n    }\n\n    /// unescape \"~1\" to tilde and \"~0\" to slash (order is important!)\n    static void unescape(std::string& s)\n    {\n        replace_substring(s, \"~1\", \"/\");\n        replace_substring(s, \"~0\", \"~\");\n    }\n\n    /*!\n    @param[in] reference_string  the reference string to the current value\n    @param[in] value             the value to consider\n    @param[in,out] result        the result object to insert values to\n\n    @note Empty objects or arrays are flattened to `null`.\n    */\n    static void flatten(const std::string& reference_string,\n                        const BasicJsonType& value,\n                        BasicJsonType& result)\n    {\n        switch (value.m_type)\n        {\n            case detail::value_t::array:\n            {\n                if (value.m_value.array->empty())\n                {\n                    // flatten empty array as null\n                    result[reference_string] = nullptr;\n                }\n                else\n                {\n                    // iterate array and use index as reference string\n                    for (std::size_t i = 0; i < value.m_value.array->size(); ++i)\n                    {\n                        flatten(reference_string + \"/\" + std::to_string(i),\n                                value.m_value.array->operator[](i), result);\n                    }\n                }\n                break;\n            }\n\n            case detail::value_t::object:\n            {\n                if (value.m_value.object->empty())\n                {\n                    // flatten empty object as null\n                    result[reference_string] = nullptr;\n                }\n                else\n                {\n                    // iterate object and use keys as reference string\n                    for (const auto& element : *value.m_value.object)\n                    {\n                        flatten(reference_string + \"/\" + escape(element.first), element.second, result);\n                    }\n                }\n                break;\n            }\n\n            default:\n            {\n                // add primitive value with its reference string\n                result[reference_string] = value;\n                break;\n            }\n        }\n    }\n\n    /*!\n    @param[in] value  flattened JSON\n\n    @return unflattened JSON\n\n    @throw parse_error.109 if array index is not a number\n    @throw type_error.314  if value is not an object\n    @throw type_error.315  if object values are not primitive\n    @throw type_error.313  if value cannot be unflattened\n    */\n    static BasicJsonType\n    unflatten(const BasicJsonType& value)\n    {\n        if (JSON_UNLIKELY(not value.is_object()))\n        {\n            JSON_THROW(detail::type_error::create(314, \"only objects can be unflattened\"));\n        }\n\n        BasicJsonType result;\n\n        // iterate the JSON object values\n        for (const auto& element : *value.m_value.object)\n        {\n            if (JSON_UNLIKELY(not element.second.is_primitive()))\n            {\n                JSON_THROW(detail::type_error::create(315, \"values in object must be primitive\"));\n            }\n\n            // assign value to reference pointed to by JSON pointer; Note that if\n            // the JSON pointer is \"\" (i.e., points to the whole value), function\n            // get_and_create returns a reference to result itself. An assignment\n            // will then create a primitive value.\n            json_pointer(element.first).get_and_create(result) = element.second;\n        }\n\n        return result;\n    }\n\n    friend bool operator==(json_pointer const& lhs,\n                           json_pointer const& rhs) noexcept\n    {\n        return (lhs.reference_tokens == rhs.reference_tokens);\n    }\n\n    friend bool operator!=(json_pointer const& lhs,\n                           json_pointer const& rhs) noexcept\n    {\n        return not (lhs == rhs);\n    }\n\n    /// the reference tokens\n    std::vector<std::string> reference_tokens;\n};\n}  // namespace nlohmann\n"
  },
  {
    "path": "nlohmann_json/include/nlohmann/detail/json_ref.hpp",
    "content": "#pragma once\n\n#include <initializer_list>\n#include <utility>\n\n#include <nlohmann/detail/meta/type_traits.hpp>\n\nnamespace nlohmann\n{\nnamespace detail\n{\ntemplate<typename BasicJsonType>\nclass json_ref\n{\n  public:\n    using value_type = BasicJsonType;\n\n    json_ref(value_type&& value)\n        : owned_value(std::move(value)), value_ref(&owned_value), is_rvalue(true)\n    {}\n\n    json_ref(const value_type& value)\n        : value_ref(const_cast<value_type*>(&value)), is_rvalue(false)\n    {}\n\n    json_ref(std::initializer_list<json_ref> init)\n        : owned_value(init), value_ref(&owned_value), is_rvalue(true)\n    {}\n\n    template <\n        class... Args,\n        enable_if_t<std::is_constructible<value_type, Args...>::value, int> = 0 >\n    json_ref(Args && ... args)\n        : owned_value(std::forward<Args>(args)...), value_ref(&owned_value),\n          is_rvalue(true) {}\n\n    // class should be movable only\n    json_ref(json_ref&&) = default;\n    json_ref(const json_ref&) = delete;\n    json_ref& operator=(const json_ref&) = delete;\n    json_ref& operator=(json_ref&&) = delete;\n    ~json_ref() = default;\n\n    value_type moved_or_copied() const\n    {\n        if (is_rvalue)\n        {\n            return std::move(*value_ref);\n        }\n        return *value_ref;\n    }\n\n    value_type const& operator*() const\n    {\n        return *static_cast<value_type const*>(value_ref);\n    }\n\n    value_type const* operator->() const\n    {\n        return static_cast<value_type const*>(value_ref);\n    }\n\n  private:\n    mutable value_type owned_value = nullptr;\n    value_type* value_ref = nullptr;\n    const bool is_rvalue;\n};\n}  // namespace detail\n}  // namespace nlohmann\n"
  },
  {
    "path": "nlohmann_json/include/nlohmann/detail/macro_scope.hpp",
    "content": "#pragma once\n\n// This file contains all internal macro definitions\n// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them\n\n// exclude unsupported compilers\n#if !defined(JSON_SKIP_UNSUPPORTED_COMPILER_CHECK)\n    #if defined(__clang__)\n        #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400\n            #error \"unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers\"\n        #endif\n    #elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER))\n        #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40800\n            #error \"unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers\"\n        #endif\n    #endif\n#endif\n\n// disable float-equal warnings on GCC/clang\n#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)\n    #pragma GCC diagnostic push\n    #pragma GCC diagnostic ignored \"-Wfloat-equal\"\n#endif\n\n// disable documentation warnings on clang\n#if defined(__clang__)\n    #pragma GCC diagnostic push\n    #pragma GCC diagnostic ignored \"-Wdocumentation\"\n#endif\n\n// allow for portable deprecation warnings\n#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)\n    #define JSON_DEPRECATED __attribute__((deprecated))\n#elif defined(_MSC_VER)\n    #define JSON_DEPRECATED __declspec(deprecated)\n#else\n    #define JSON_DEPRECATED\n#endif\n\n// allow to disable exceptions\n#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION)\n    #define JSON_THROW(exception) throw exception\n    #define JSON_TRY try\n    #define JSON_CATCH(exception) catch(exception)\n    #define JSON_INTERNAL_CATCH(exception) catch(exception)\n#else\n    #define JSON_THROW(exception) std::abort()\n    #define JSON_TRY if(true)\n    #define JSON_CATCH(exception) if(false)\n    #define JSON_INTERNAL_CATCH(exception) if(false)\n#endif\n\n// override exception macros\n#if defined(JSON_THROW_USER)\n    #undef JSON_THROW\n    #define JSON_THROW JSON_THROW_USER\n#endif\n#if defined(JSON_TRY_USER)\n    #undef JSON_TRY\n    #define JSON_TRY JSON_TRY_USER\n#endif\n#if defined(JSON_CATCH_USER)\n    #undef JSON_CATCH\n    #define JSON_CATCH JSON_CATCH_USER\n    #undef JSON_INTERNAL_CATCH\n    #define JSON_INTERNAL_CATCH JSON_CATCH_USER\n#endif\n#if defined(JSON_INTERNAL_CATCH_USER)\n    #undef JSON_INTERNAL_CATCH\n    #define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER\n#endif\n\n// manual branch prediction\n#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)\n    #define JSON_LIKELY(x)      __builtin_expect(!!(x), 1)\n    #define JSON_UNLIKELY(x)    __builtin_expect(!!(x), 0)\n#else\n    #define JSON_LIKELY(x)      x\n    #define JSON_UNLIKELY(x)    x\n#endif\n\n// C++ language standard detection\n#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464\n    #define JSON_HAS_CPP_17\n    #define JSON_HAS_CPP_14\n#elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1)\n    #define JSON_HAS_CPP_14\n#endif\n\n/*!\n@brief macro to briefly define a mapping between an enum and JSON\n@def NLOHMANN_JSON_SERIALIZE_ENUM\n@since version 3.4.0\n*/\n#define NLOHMANN_JSON_SERIALIZE_ENUM(ENUM_TYPE, ...)                                           \\\n    template<typename BasicJsonType>                                                           \\\n    inline void to_json(BasicJsonType& j, const ENUM_TYPE& e)                                  \\\n    {                                                                                          \\\n        static_assert(std::is_enum<ENUM_TYPE>::value, #ENUM_TYPE \" must be an enum!\");         \\\n        static const std::pair<ENUM_TYPE, BasicJsonType> m[] = __VA_ARGS__;                    \\\n        auto it = std::find_if(std::begin(m), std::end(m),                                     \\\n                               [e](const std::pair<ENUM_TYPE, BasicJsonType>& ej_pair) -> bool \\\n        {                                                                                      \\\n            return ej_pair.first == e;                                                         \\\n        });                                                                                    \\\n        j = ((it != std::end(m)) ? it : std::begin(m))->second;                                \\\n    }                                                                                          \\\n    template<typename BasicJsonType>                                                           \\\n    inline void from_json(const BasicJsonType& j, ENUM_TYPE& e)                                \\\n    {                                                                                          \\\n        static_assert(std::is_enum<ENUM_TYPE>::value, #ENUM_TYPE \" must be an enum!\");         \\\n        static const std::pair<ENUM_TYPE, BasicJsonType> m[] = __VA_ARGS__;                    \\\n        auto it = std::find_if(std::begin(m), std::end(m),                                     \\\n                               [j](const std::pair<ENUM_TYPE, BasicJsonType>& ej_pair) -> bool \\\n        {                                                                                      \\\n            return ej_pair.second == j;                                                        \\\n        });                                                                                    \\\n        e = ((it != std::end(m)) ? it : std::begin(m))->first;                                 \\\n    }\n\n// Ugly macros to avoid uglier copy-paste when specializing basic_json. They\n// may be removed in the future once the class is split.\n\n#define NLOHMANN_BASIC_JSON_TPL_DECLARATION                                \\\n    template<template<typename, typename, typename...> class ObjectType,   \\\n             template<typename, typename...> class ArrayType,              \\\n             class StringType, class BooleanType, class NumberIntegerType, \\\n             class NumberUnsignedType, class NumberFloatType,              \\\n             template<typename> class AllocatorType,                       \\\n             template<typename, typename = void> class JSONSerializer>\n\n#define NLOHMANN_BASIC_JSON_TPL                                            \\\n    basic_json<ObjectType, ArrayType, StringType, BooleanType,             \\\n    NumberIntegerType, NumberUnsignedType, NumberFloatType,                \\\n    AllocatorType, JSONSerializer>\n"
  },
  {
    "path": "nlohmann_json/include/nlohmann/detail/macro_unscope.hpp",
    "content": "#pragma once\n\n// restore GCC/clang diagnostic settings\n#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)\n    #pragma GCC diagnostic pop\n#endif\n#if defined(__clang__)\n    #pragma GCC diagnostic pop\n#endif\n\n// clean up\n#undef JSON_INTERNAL_CATCH\n#undef JSON_CATCH\n#undef JSON_THROW\n#undef JSON_TRY\n#undef JSON_LIKELY\n#undef JSON_UNLIKELY\n#undef JSON_DEPRECATED\n#undef JSON_HAS_CPP_14\n#undef JSON_HAS_CPP_17\n#undef NLOHMANN_BASIC_JSON_TPL_DECLARATION\n#undef NLOHMANN_BASIC_JSON_TPL\n"
  },
  {
    "path": "nlohmann_json/include/nlohmann/detail/meta/cpp_future.hpp",
    "content": "#pragma once\n\n#include <ciso646> // not\n#include <cstddef> // size_t\n#include <type_traits> // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type\n\nnamespace nlohmann\n{\nnamespace detail\n{\n// alias templates to reduce boilerplate\ntemplate<bool B, typename T = void>\nusing enable_if_t = typename std::enable_if<B, T>::type;\n\ntemplate<typename T>\nusing uncvref_t = typename std::remove_cv<typename std::remove_reference<T>::type>::type;\n\n// implementation of C++14 index_sequence and affiliates\n// source: https://stackoverflow.com/a/32223343\ntemplate<std::size_t... Ints>\nstruct index_sequence\n{\n    using type = index_sequence;\n    using value_type = std::size_t;\n    static constexpr std::size_t size() noexcept\n    {\n        return sizeof...(Ints);\n    }\n};\n\ntemplate<class Sequence1, class Sequence2>\nstruct merge_and_renumber;\n\ntemplate<std::size_t... I1, std::size_t... I2>\nstruct merge_and_renumber<index_sequence<I1...>, index_sequence<I2...>>\n        : index_sequence < I1..., (sizeof...(I1) + I2)... > {};\n\ntemplate<std::size_t N>\nstruct make_index_sequence\n    : merge_and_renumber < typename make_index_sequence < N / 2 >::type,\n      typename make_index_sequence < N - N / 2 >::type > {};\n\ntemplate<> struct make_index_sequence<0> : index_sequence<> {};\ntemplate<> struct make_index_sequence<1> : index_sequence<0> {};\n\ntemplate<typename... Ts>\nusing index_sequence_for = make_index_sequence<sizeof...(Ts)>;\n\n// dispatch utility (taken from ranges-v3)\ntemplate<unsigned N> struct priority_tag : priority_tag < N - 1 > {};\ntemplate<> struct priority_tag<0> {};\n\n// taken from ranges-v3\ntemplate<typename T>\nstruct static_const\n{\n    static constexpr T value{};\n};\n\ntemplate<typename T>\nconstexpr T static_const<T>::value;\n}  // namespace detail\n}  // namespace nlohmann\n"
  },
  {
    "path": "nlohmann_json/include/nlohmann/detail/meta/detected.hpp",
    "content": "#pragma once\n\n#include <type_traits>\n\n#include <nlohmann/detail/meta/void_t.hpp>\n\n// http://en.cppreference.com/w/cpp/experimental/is_detected\nnamespace nlohmann\n{\nnamespace detail\n{\nstruct nonesuch\n{\n    nonesuch() = delete;\n    ~nonesuch() = delete;\n    nonesuch(nonesuch const&) = delete;\n    void operator=(nonesuch const&) = delete;\n};\n\ntemplate <class Default,\n          class AlwaysVoid,\n          template <class...> class Op,\n          class... Args>\nstruct detector\n{\n    using value_t = std::false_type;\n    using type = Default;\n};\n\ntemplate <class Default, template <class...> class Op, class... Args>\nstruct detector<Default, void_t<Op<Args...>>, Op, Args...>\n{\n    using value_t = std::true_type;\n    using type = Op<Args...>;\n};\n\ntemplate <template <class...> class Op, class... Args>\nusing is_detected = typename detector<nonesuch, void, Op, Args...>::value_t;\n\ntemplate <template <class...> class Op, class... Args>\nusing detected_t = typename detector<nonesuch, void, Op, Args...>::type;\n\ntemplate <class Default, template <class...> class Op, class... Args>\nusing detected_or = detector<Default, void, Op, Args...>;\n\ntemplate <class Default, template <class...> class Op, class... Args>\nusing detected_or_t = typename detected_or<Default, Op, Args...>::type;\n\ntemplate <class Expected, template <class...> class Op, class... Args>\nusing is_detected_exact = std::is_same<Expected, detected_t<Op, Args...>>;\n\ntemplate <class To, template <class...> class Op, class... Args>\nusing is_detected_convertible =\n    std::is_convertible<detected_t<Op, Args...>, To>;\n}  // namespace detail\n}  // namespace nlohmann\n"
  },
  {
    "path": "nlohmann_json/include/nlohmann/detail/meta/is_sax.hpp",
    "content": "#pragma once\n\n#include <cstdint> // size_t\n#include <utility> // declval\n\n#include <nlohmann/detail/meta/detected.hpp>\n#include <nlohmann/detail/meta/type_traits.hpp>\n\nnamespace nlohmann\n{\nnamespace detail\n{\ntemplate <typename T>\nusing null_function_t = decltype(std::declval<T&>().null());\n\ntemplate <typename T>\nusing boolean_function_t =\n    decltype(std::declval<T&>().boolean(std::declval<bool>()));\n\ntemplate <typename T, typename Integer>\nusing number_integer_function_t =\n    decltype(std::declval<T&>().number_integer(std::declval<Integer>()));\n\ntemplate <typename T, typename Unsigned>\nusing number_unsigned_function_t =\n    decltype(std::declval<T &>().number_unsigned(std::declval<Unsigned>()));\n\ntemplate <typename T, typename Float, typename String>\nusing number_float_function_t = decltype(std::declval<T &>().number_float(\n    std::declval<Float>(), std::declval<const String &>()));\n\ntemplate <typename T, typename String>\nusing string_function_t =\n    decltype(std::declval<T &>().string(std::declval<String &>()));\n\ntemplate <typename T>\nusing start_object_function_t =\n    decltype(std::declval<T &>().start_object(std::declval<std::size_t>()));\n\ntemplate <typename T, typename String>\nusing key_function_t =\n    decltype(std::declval<T &>().key(std::declval<String &>()));\n\ntemplate <typename T>\nusing end_object_function_t = decltype(std::declval<T &>().end_object());\n\ntemplate <typename T>\nusing start_array_function_t =\n    decltype(std::declval<T &>().start_array(std::declval<std::size_t>()));\n\ntemplate <typename T>\nusing end_array_function_t = decltype(std::declval<T &>().end_array());\n\ntemplate <typename T, typename Exception>\nusing parse_error_function_t = decltype(std::declval<T &>().parse_error(\n    std::declval<std::size_t>(), std::declval<const std::string &>(),\n    std::declval<const Exception &>()));\n\ntemplate <typename SAX, typename BasicJsonType>\nstruct is_sax\n{\nprivate:\n  static_assert(is_basic_json<BasicJsonType>::value,\n                \"BasicJsonType must be of type basic_json<...>\");\n\n  using number_integer_t = typename BasicJsonType::number_integer_t;\n  using number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n  using number_float_t = typename BasicJsonType::number_float_t;\n  using string_t = typename BasicJsonType::string_t;\n  using exception_t = typename BasicJsonType::exception;\n\npublic:\n  static constexpr bool value =\n      is_detected_exact<bool, null_function_t, SAX>::value &&\n      is_detected_exact<bool, boolean_function_t, SAX>::value &&\n      is_detected_exact<bool, number_integer_function_t, SAX,\n                        number_integer_t>::value &&\n      is_detected_exact<bool, number_unsigned_function_t, SAX,\n                        number_unsigned_t>::value &&\n      is_detected_exact<bool, number_float_function_t, SAX, number_float_t,\n                        string_t>::value &&\n      is_detected_exact<bool, string_function_t, SAX, string_t>::value &&\n      is_detected_exact<bool, start_object_function_t, SAX>::value &&\n      is_detected_exact<bool, key_function_t, SAX, string_t>::value &&\n      is_detected_exact<bool, end_object_function_t, SAX>::value &&\n      is_detected_exact<bool, start_array_function_t, SAX>::value &&\n      is_detected_exact<bool, end_array_function_t, SAX>::value &&\n      is_detected_exact<bool, parse_error_function_t, SAX, exception_t>::value;\n};\n\ntemplate <typename SAX, typename BasicJsonType>\nstruct is_sax_static_asserts\n{\nprivate:\n  static_assert(is_basic_json<BasicJsonType>::value,\n                \"BasicJsonType must be of type basic_json<...>\");\n\n  using number_integer_t = typename BasicJsonType::number_integer_t;\n  using number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n  using number_float_t = typename BasicJsonType::number_float_t;\n  using string_t = typename BasicJsonType::string_t;\n  using exception_t = typename BasicJsonType::exception;\n\npublic:\n  static_assert(is_detected_exact<bool, null_function_t, SAX>::value,\n                \"Missing/invalid function: bool null()\");\n  static_assert(is_detected_exact<bool, boolean_function_t, SAX>::value,\n                \"Missing/invalid function: bool boolean(bool)\");\n  static_assert(is_detected_exact<bool, boolean_function_t, SAX>::value,\n                \"Missing/invalid function: bool boolean(bool)\");\n  static_assert(\n      is_detected_exact<bool, number_integer_function_t, SAX,\n                        number_integer_t>::value,\n      \"Missing/invalid function: bool number_integer(number_integer_t)\");\n  static_assert(\n      is_detected_exact<bool, number_unsigned_function_t, SAX,\n                        number_unsigned_t>::value,\n      \"Missing/invalid function: bool number_unsigned(number_unsigned_t)\");\n  static_assert(is_detected_exact<bool, number_float_function_t, SAX,\n                                  number_float_t, string_t>::value,\n                \"Missing/invalid function: bool number_float(number_float_t, const string_t&)\");\n  static_assert(\n      is_detected_exact<bool, string_function_t, SAX, string_t>::value,\n      \"Missing/invalid function: bool string(string_t&)\");\n  static_assert(is_detected_exact<bool, start_object_function_t, SAX>::value,\n                \"Missing/invalid function: bool start_object(std::size_t)\");\n  static_assert(is_detected_exact<bool, key_function_t, SAX, string_t>::value,\n                \"Missing/invalid function: bool key(string_t&)\");\n  static_assert(is_detected_exact<bool, end_object_function_t, SAX>::value,\n                \"Missing/invalid function: bool end_object()\");\n  static_assert(is_detected_exact<bool, start_array_function_t, SAX>::value,\n                \"Missing/invalid function: bool start_array(std::size_t)\");\n  static_assert(is_detected_exact<bool, end_array_function_t, SAX>::value,\n                \"Missing/invalid function: bool end_array()\");\n  static_assert(\n      is_detected_exact<bool, parse_error_function_t, SAX, exception_t>::value,\n      \"Missing/invalid function: bool parse_error(std::size_t, const \"\n      \"std::string&, const exception&)\");\n};\n}  // namespace detail\n}  // namespace nlohmann\n"
  },
  {
    "path": "nlohmann_json/include/nlohmann/detail/meta/type_traits.hpp",
    "content": "#pragma once\n\n#include <ciso646> // not\n#include <limits> // numeric_limits\n#include <type_traits> // false_type, is_constructible, is_integral, is_same, true_type\n#include <utility> // declval\n\n#include <nlohmann/json_fwd.hpp>\n#include <nlohmann/detail/iterators/iterator_traits.hpp>\n#include <nlohmann/detail/meta/cpp_future.hpp>\n#include <nlohmann/detail/meta/detected.hpp>\n#include <nlohmann/detail/macro_scope.hpp>\n\nnamespace nlohmann\n{\n/*!\n@brief detail namespace with internal helper functions\n\nThis namespace collects functions that should not be exposed,\nimplementations of some @ref basic_json methods, and meta-programming helpers.\n\n@since version 2.1.0\n*/\nnamespace detail\n{\n/////////////\n// helpers //\n/////////////\n\n// Note to maintainers:\n//\n// Every trait in this file expects a non CV-qualified type.\n// The only exceptions are in the 'aliases for detected' section\n// (i.e. those of the form: decltype(T::member_function(std::declval<T>())))\n//\n// In this case, T has to be properly CV-qualified to constraint the function arguments\n// (e.g. to_json(BasicJsonType&, const T&))\n\ntemplate<typename> struct is_basic_json : std::false_type {};\n\nNLOHMANN_BASIC_JSON_TPL_DECLARATION\nstruct is_basic_json<NLOHMANN_BASIC_JSON_TPL> : std::true_type {};\n\n//////////////////////////\n// aliases for detected //\n//////////////////////////\n\ntemplate <typename T>\nusing mapped_type_t = typename T::mapped_type;\n\ntemplate <typename T>\nusing key_type_t = typename T::key_type;\n\ntemplate <typename T>\nusing value_type_t = typename T::value_type;\n\ntemplate <typename T>\nusing difference_type_t = typename T::difference_type;\n\ntemplate <typename T>\nusing pointer_t = typename T::pointer;\n\ntemplate <typename T>\nusing reference_t = typename T::reference;\n\ntemplate <typename T>\nusing iterator_category_t = typename T::iterator_category;\n\ntemplate <typename T>\nusing iterator_t = typename T::iterator;\n\ntemplate <typename T, typename... Args>\nusing to_json_function = decltype(T::to_json(std::declval<Args>()...));\n\ntemplate <typename T, typename... Args>\nusing from_json_function = decltype(T::from_json(std::declval<Args>()...));\n\ntemplate <typename T, typename U>\nusing get_template_function = decltype(std::declval<T>().template get<U>());\n\n// trait checking if JSONSerializer<T>::from_json(json const&, udt&) exists\ntemplate <typename BasicJsonType, typename T, typename = void>\nstruct has_from_json : std::false_type {};\n\ntemplate <typename BasicJsonType, typename T>\nstruct has_from_json<BasicJsonType, T,\n           enable_if_t<not is_basic_json<T>::value>>\n{\n    using serializer = typename BasicJsonType::template json_serializer<T, void>;\n\n    static constexpr bool value =\n        is_detected_exact<void, from_json_function, serializer,\n        const BasicJsonType&, T&>::value;\n};\n\n// This trait checks if JSONSerializer<T>::from_json(json const&) exists\n// this overload is used for non-default-constructible user-defined-types\ntemplate <typename BasicJsonType, typename T, typename = void>\nstruct has_non_default_from_json : std::false_type {};\n\ntemplate<typename BasicJsonType, typename T>\nstruct has_non_default_from_json<BasicJsonType, T, enable_if_t<not is_basic_json<T>::value>>\n{\n    using serializer = typename BasicJsonType::template json_serializer<T, void>;\n\n    static constexpr bool value =\n        is_detected_exact<T, from_json_function, serializer,\n        const BasicJsonType&>::value;\n};\n\n// This trait checks if BasicJsonType::json_serializer<T>::to_json exists\n// Do not evaluate the trait when T is a basic_json type, to avoid template instantiation infinite recursion.\ntemplate <typename BasicJsonType, typename T, typename = void>\nstruct has_to_json : std::false_type {};\n\ntemplate <typename BasicJsonType, typename T>\nstruct has_to_json<BasicJsonType, T, enable_if_t<not is_basic_json<T>::value>>\n{\n    using serializer = typename BasicJsonType::template json_serializer<T, void>;\n\n    static constexpr bool value =\n        is_detected_exact<void, to_json_function, serializer, BasicJsonType&,\n        T>::value;\n};\n\n\n///////////////////\n// is_ functions //\n///////////////////\n\ntemplate <typename T, typename = void>\nstruct is_iterator_traits : std::false_type {};\n\ntemplate <typename T>\nstruct is_iterator_traits<iterator_traits<T>>\n{\n  private:\n    using traits = iterator_traits<T>;\n\n  public:\n    static constexpr auto value =\n        is_detected<value_type_t, traits>::value &&\n        is_detected<difference_type_t, traits>::value &&\n        is_detected<pointer_t, traits>::value &&\n        is_detected<iterator_category_t, traits>::value &&\n        is_detected<reference_t, traits>::value;\n};\n\n// source: https://stackoverflow.com/a/37193089/4116453\n\ntemplate <typename T, typename = void>\nstruct is_complete_type : std::false_type {};\n\ntemplate <typename T>\nstruct is_complete_type<T, decltype(void(sizeof(T)))> : std::true_type {};\n\ntemplate <typename BasicJsonType, typename CompatibleObjectType,\n          typename = void>\nstruct is_compatible_object_type_impl : std::false_type {};\n\ntemplate <typename BasicJsonType, typename CompatibleObjectType>\nstruct is_compatible_object_type_impl <\n    BasicJsonType, CompatibleObjectType,\n    enable_if_t<is_detected<mapped_type_t, CompatibleObjectType>::value and\n    is_detected<key_type_t, CompatibleObjectType>::value >>\n{\n\n    using object_t = typename BasicJsonType::object_t;\n\n    // macOS's is_constructible does not play well with nonesuch...\n    static constexpr bool value =\n        std::is_constructible<typename object_t::key_type,\n        typename CompatibleObjectType::key_type>::value and\n        std::is_constructible<typename object_t::mapped_type,\n        typename CompatibleObjectType::mapped_type>::value;\n};\n\ntemplate <typename BasicJsonType, typename CompatibleObjectType>\nstruct is_compatible_object_type\n    : is_compatible_object_type_impl<BasicJsonType, CompatibleObjectType> {};\n\ntemplate <typename BasicJsonType, typename ConstructibleObjectType,\n          typename = void>\nstruct is_constructible_object_type_impl : std::false_type {};\n\ntemplate <typename BasicJsonType, typename ConstructibleObjectType>\nstruct is_constructible_object_type_impl <\n    BasicJsonType, ConstructibleObjectType,\n    enable_if_t<is_detected<mapped_type_t, ConstructibleObjectType>::value and\n    is_detected<key_type_t, ConstructibleObjectType>::value >>\n{\n    using object_t = typename BasicJsonType::object_t;\n\n    static constexpr bool value =\n        (std::is_constructible<typename ConstructibleObjectType::key_type, typename object_t::key_type>::value and\n         std::is_same<typename object_t::mapped_type, typename ConstructibleObjectType::mapped_type>::value) or\n        (has_from_json<BasicJsonType, typename ConstructibleObjectType::mapped_type>::value or\n         has_non_default_from_json<BasicJsonType, typename ConstructibleObjectType::mapped_type >::value);\n};\n\ntemplate <typename BasicJsonType, typename ConstructibleObjectType>\nstruct is_constructible_object_type\n    : is_constructible_object_type_impl<BasicJsonType,\n      ConstructibleObjectType> {};\n\ntemplate <typename BasicJsonType, typename CompatibleStringType,\n          typename = void>\nstruct is_compatible_string_type_impl : std::false_type {};\n\ntemplate <typename BasicJsonType, typename CompatibleStringType>\nstruct is_compatible_string_type_impl <\n    BasicJsonType, CompatibleStringType,\n    enable_if_t<is_detected_exact<typename BasicJsonType::string_t::value_type,\n    value_type_t, CompatibleStringType>::value >>\n{\n    static constexpr auto value =\n        std::is_constructible<typename BasicJsonType::string_t, CompatibleStringType>::value;\n};\n\ntemplate <typename BasicJsonType, typename ConstructibleStringType>\nstruct is_compatible_string_type\n    : is_compatible_string_type_impl<BasicJsonType, ConstructibleStringType> {};\n\ntemplate <typename BasicJsonType, typename ConstructibleStringType,\n          typename = void>\nstruct is_constructible_string_type_impl : std::false_type {};\n\ntemplate <typename BasicJsonType, typename ConstructibleStringType>\nstruct is_constructible_string_type_impl <\n    BasicJsonType, ConstructibleStringType,\n    enable_if_t<is_detected_exact<typename BasicJsonType::string_t::value_type,\n    value_type_t, ConstructibleStringType>::value >>\n{\n    static constexpr auto value =\n        std::is_constructible<ConstructibleStringType,\n        typename BasicJsonType::string_t>::value;\n};\n\ntemplate <typename BasicJsonType, typename ConstructibleStringType>\nstruct is_constructible_string_type\n    : is_constructible_string_type_impl<BasicJsonType, ConstructibleStringType> {};\n\ntemplate <typename BasicJsonType, typename CompatibleArrayType, typename = void>\nstruct is_compatible_array_type_impl : std::false_type {};\n\ntemplate <typename BasicJsonType, typename CompatibleArrayType>\nstruct is_compatible_array_type_impl <\n    BasicJsonType, CompatibleArrayType,\n    enable_if_t<is_detected<value_type_t, CompatibleArrayType>::value and\n    is_detected<iterator_t, CompatibleArrayType>::value and\n// This is needed because json_reverse_iterator has a ::iterator type...\n// Therefore it is detected as a CompatibleArrayType.\n// The real fix would be to have an Iterable concept.\n    not is_iterator_traits<\n    iterator_traits<CompatibleArrayType>>::value >>\n{\n    static constexpr bool value =\n        std::is_constructible<BasicJsonType,\n        typename CompatibleArrayType::value_type>::value;\n};\n\ntemplate <typename BasicJsonType, typename CompatibleArrayType>\nstruct is_compatible_array_type\n    : is_compatible_array_type_impl<BasicJsonType, CompatibleArrayType> {};\n\ntemplate <typename BasicJsonType, typename ConstructibleArrayType, typename = void>\nstruct is_constructible_array_type_impl : std::false_type {};\n\ntemplate <typename BasicJsonType, typename ConstructibleArrayType>\nstruct is_constructible_array_type_impl <\n    BasicJsonType, ConstructibleArrayType,\n    enable_if_t<std::is_same<ConstructibleArrayType,\n    typename BasicJsonType::value_type>::value >>\n            : std::true_type {};\n\ntemplate <typename BasicJsonType, typename ConstructibleArrayType>\nstruct is_constructible_array_type_impl <\n    BasicJsonType, ConstructibleArrayType,\n    enable_if_t<not std::is_same<ConstructibleArrayType,\n    typename BasicJsonType::value_type>::value and\n    is_detected<value_type_t, ConstructibleArrayType>::value and\n    is_detected<iterator_t, ConstructibleArrayType>::value and\n    is_complete_type<\n    detected_t<value_type_t, ConstructibleArrayType>>::value >>\n{\n    static constexpr bool value =\n        // This is needed because json_reverse_iterator has a ::iterator type,\n        // furthermore, std::back_insert_iterator (and other iterators) have a base class `iterator`...\n        // Therefore it is detected as a ConstructibleArrayType.\n        // The real fix would be to have an Iterable concept.\n        not is_iterator_traits <\n        iterator_traits<ConstructibleArrayType >>::value and\n\n        (std::is_same<typename ConstructibleArrayType::value_type, typename BasicJsonType::array_t::value_type>::value or\n         has_from_json<BasicJsonType,\n         typename ConstructibleArrayType::value_type>::value or\n         has_non_default_from_json <\n         BasicJsonType, typename ConstructibleArrayType::value_type >::value);\n};\n\ntemplate <typename BasicJsonType, typename ConstructibleArrayType>\nstruct is_constructible_array_type\n    : is_constructible_array_type_impl<BasicJsonType, ConstructibleArrayType> {};\n\ntemplate <typename RealIntegerType, typename CompatibleNumberIntegerType,\n          typename = void>\nstruct is_compatible_integer_type_impl : std::false_type {};\n\ntemplate <typename RealIntegerType, typename CompatibleNumberIntegerType>\nstruct is_compatible_integer_type_impl <\n    RealIntegerType, CompatibleNumberIntegerType,\n    enable_if_t<std::is_integral<RealIntegerType>::value and\n    std::is_integral<CompatibleNumberIntegerType>::value and\n    not std::is_same<bool, CompatibleNumberIntegerType>::value >>\n{\n    // is there an assert somewhere on overflows?\n    using RealLimits = std::numeric_limits<RealIntegerType>;\n    using CompatibleLimits = std::numeric_limits<CompatibleNumberIntegerType>;\n\n    static constexpr auto value =\n        std::is_constructible<RealIntegerType,\n        CompatibleNumberIntegerType>::value and\n        CompatibleLimits::is_integer and\n        RealLimits::is_signed == CompatibleLimits::is_signed;\n};\n\ntemplate <typename RealIntegerType, typename CompatibleNumberIntegerType>\nstruct is_compatible_integer_type\n    : is_compatible_integer_type_impl<RealIntegerType,\n      CompatibleNumberIntegerType> {};\n\ntemplate <typename BasicJsonType, typename CompatibleType, typename = void>\nstruct is_compatible_type_impl: std::false_type {};\n\ntemplate <typename BasicJsonType, typename CompatibleType>\nstruct is_compatible_type_impl <\n    BasicJsonType, CompatibleType,\n    enable_if_t<is_complete_type<CompatibleType>::value >>\n{\n    static constexpr bool value =\n        has_to_json<BasicJsonType, CompatibleType>::value;\n};\n\ntemplate <typename BasicJsonType, typename CompatibleType>\nstruct is_compatible_type\n    : is_compatible_type_impl<BasicJsonType, CompatibleType> {};\n}  // namespace detail\n}  // namespace nlohmann\n"
  },
  {
    "path": "nlohmann_json/include/nlohmann/detail/meta/void_t.hpp",
    "content": "#pragma once\n\nnamespace nlohmann\n{\nnamespace detail\n{\ntemplate <typename ...Ts> struct make_void\n{\n    using type = void;\n};\ntemplate <typename ...Ts> using void_t = typename make_void<Ts...>::type;\n} // namespace detail\n}  // namespace nlohmann\n"
  },
  {
    "path": "nlohmann_json/include/nlohmann/detail/output/binary_writer.hpp",
    "content": "#pragma once\n\n#include <algorithm> // reverse\n#include <array> // array\n#include <cstdint> // uint8_t, uint16_t, uint32_t, uint64_t\n#include <cstring> // memcpy\n#include <limits> // numeric_limits\n\n#include <nlohmann/detail/input/binary_reader.hpp>\n#include <nlohmann/detail/output/output_adapters.hpp>\n\nnamespace nlohmann\n{\nnamespace detail\n{\n///////////////////\n// binary writer //\n///////////////////\n\n/*!\n@brief serialization to CBOR and MessagePack values\n*/\ntemplate<typename BasicJsonType, typename CharType>\nclass binary_writer\n{\n    using string_t = typename BasicJsonType::string_t;\n\n  public:\n    /*!\n    @brief create a binary writer\n\n    @param[in] adapter  output adapter to write to\n    */\n    explicit binary_writer(output_adapter_t<CharType> adapter) : oa(adapter)\n    {\n        assert(oa);\n    }\n\n    /*!\n    @param[in] j  JSON value to serialize\n    @pre       j.type() == value_t::object\n    */\n    void write_bson(const BasicJsonType& j)\n    {\n        switch (j.type())\n        {\n            case value_t::object:\n            {\n                write_bson_object(*j.m_value.object);\n                break;\n            }\n\n            default:\n            {\n                JSON_THROW(type_error::create(317, \"to serialize to BSON, top-level type must be object, but is \" + std::string(j.type_name())));\n            }\n        }\n    }\n\n    /*!\n    @param[in] j  JSON value to serialize\n    */\n    void write_cbor(const BasicJsonType& j)\n    {\n        switch (j.type())\n        {\n            case value_t::null:\n            {\n                oa->write_character(to_char_type(0xF6));\n                break;\n            }\n\n            case value_t::boolean:\n            {\n                oa->write_character(j.m_value.boolean\n                                    ? to_char_type(0xF5)\n                                    : to_char_type(0xF4));\n                break;\n            }\n\n            case value_t::number_integer:\n            {\n                if (j.m_value.number_integer >= 0)\n                {\n                    // CBOR does not differentiate between positive signed\n                    // integers and unsigned integers. Therefore, we used the\n                    // code from the value_t::number_unsigned case here.\n                    if (j.m_value.number_integer <= 0x17)\n                    {\n                        write_number(static_cast<uint8_t>(j.m_value.number_integer));\n                    }\n                    else if (j.m_value.number_integer <= (std::numeric_limits<uint8_t>::max)())\n                    {\n                        oa->write_character(to_char_type(0x18));\n                        write_number(static_cast<uint8_t>(j.m_value.number_integer));\n                    }\n                    else if (j.m_value.number_integer <= (std::numeric_limits<uint16_t>::max)())\n                    {\n                        oa->write_character(to_char_type(0x19));\n                        write_number(static_cast<uint16_t>(j.m_value.number_integer));\n                    }\n                    else if (j.m_value.number_integer <= (std::numeric_limits<uint32_t>::max)())\n                    {\n                        oa->write_character(to_char_type(0x1A));\n                        write_number(static_cast<uint32_t>(j.m_value.number_integer));\n                    }\n                    else\n                    {\n                        oa->write_character(to_char_type(0x1B));\n                        write_number(static_cast<uint64_t>(j.m_value.number_integer));\n                    }\n                }\n                else\n                {\n                    // The conversions below encode the sign in the first\n                    // byte, and the value is converted to a positive number.\n                    const auto positive_number = -1 - j.m_value.number_integer;\n                    if (j.m_value.number_integer >= -24)\n                    {\n                        write_number(static_cast<uint8_t>(0x20 + positive_number));\n                    }\n                    else if (positive_number <= (std::numeric_limits<uint8_t>::max)())\n                    {\n                        oa->write_character(to_char_type(0x38));\n                        write_number(static_cast<uint8_t>(positive_number));\n                    }\n                    else if (positive_number <= (std::numeric_limits<uint16_t>::max)())\n                    {\n                        oa->write_character(to_char_type(0x39));\n                        write_number(static_cast<uint16_t>(positive_number));\n                    }\n                    else if (positive_number <= (std::numeric_limits<uint32_t>::max)())\n                    {\n                        oa->write_character(to_char_type(0x3A));\n                        write_number(static_cast<uint32_t>(positive_number));\n                    }\n                    else\n                    {\n                        oa->write_character(to_char_type(0x3B));\n                        write_number(static_cast<uint64_t>(positive_number));\n                    }\n                }\n                break;\n            }\n\n            case value_t::number_unsigned:\n            {\n                if (j.m_value.number_unsigned <= 0x17)\n                {\n                    write_number(static_cast<uint8_t>(j.m_value.number_unsigned));\n                }\n                else if (j.m_value.number_unsigned <= (std::numeric_limits<uint8_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x18));\n                    write_number(static_cast<uint8_t>(j.m_value.number_unsigned));\n                }\n                else if (j.m_value.number_unsigned <= (std::numeric_limits<uint16_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x19));\n                    write_number(static_cast<uint16_t>(j.m_value.number_unsigned));\n                }\n                else if (j.m_value.number_unsigned <= (std::numeric_limits<uint32_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x1A));\n                    write_number(static_cast<uint32_t>(j.m_value.number_unsigned));\n                }\n                else\n                {\n                    oa->write_character(to_char_type(0x1B));\n                    write_number(static_cast<uint64_t>(j.m_value.number_unsigned));\n                }\n                break;\n            }\n\n            case value_t::number_float:\n            {\n                oa->write_character(get_cbor_float_prefix(j.m_value.number_float));\n                write_number(j.m_value.number_float);\n                break;\n            }\n\n            case value_t::string:\n            {\n                // step 1: write control byte and the string length\n                const auto N = j.m_value.string->size();\n                if (N <= 0x17)\n                {\n                    write_number(static_cast<uint8_t>(0x60 + N));\n                }\n                else if (N <= (std::numeric_limits<uint8_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x78));\n                    write_number(static_cast<uint8_t>(N));\n                }\n                else if (N <= (std::numeric_limits<uint16_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x79));\n                    write_number(static_cast<uint16_t>(N));\n                }\n                else if (N <= (std::numeric_limits<uint32_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x7A));\n                    write_number(static_cast<uint32_t>(N));\n                }\n                // LCOV_EXCL_START\n                else if (N <= (std::numeric_limits<uint64_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x7B));\n                    write_number(static_cast<uint64_t>(N));\n                }\n                // LCOV_EXCL_STOP\n\n                // step 2: write the string\n                oa->write_characters(\n                    reinterpret_cast<const CharType*>(j.m_value.string->c_str()),\n                    j.m_value.string->size());\n                break;\n            }\n\n            case value_t::array:\n            {\n                // step 1: write control byte and the array size\n                const auto N = j.m_value.array->size();\n                if (N <= 0x17)\n                {\n                    write_number(static_cast<uint8_t>(0x80 + N));\n                }\n                else if (N <= (std::numeric_limits<uint8_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x98));\n                    write_number(static_cast<uint8_t>(N));\n                }\n                else if (N <= (std::numeric_limits<uint16_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x99));\n                    write_number(static_cast<uint16_t>(N));\n                }\n                else if (N <= (std::numeric_limits<uint32_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x9A));\n                    write_number(static_cast<uint32_t>(N));\n                }\n                // LCOV_EXCL_START\n                else if (N <= (std::numeric_limits<uint64_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x9B));\n                    write_number(static_cast<uint64_t>(N));\n                }\n                // LCOV_EXCL_STOP\n\n                // step 2: write each element\n                for (const auto& el : *j.m_value.array)\n                {\n                    write_cbor(el);\n                }\n                break;\n            }\n\n            case value_t::object:\n            {\n                // step 1: write control byte and the object size\n                const auto N = j.m_value.object->size();\n                if (N <= 0x17)\n                {\n                    write_number(static_cast<uint8_t>(0xA0 + N));\n                }\n                else if (N <= (std::numeric_limits<uint8_t>::max)())\n                {\n                    oa->write_character(to_char_type(0xB8));\n                    write_number(static_cast<uint8_t>(N));\n                }\n                else if (N <= (std::numeric_limits<uint16_t>::max)())\n                {\n                    oa->write_character(to_char_type(0xB9));\n                    write_number(static_cast<uint16_t>(N));\n                }\n                else if (N <= (std::numeric_limits<uint32_t>::max)())\n                {\n                    oa->write_character(to_char_type(0xBA));\n                    write_number(static_cast<uint32_t>(N));\n                }\n                // LCOV_EXCL_START\n                else if (N <= (std::numeric_limits<uint64_t>::max)())\n                {\n                    oa->write_character(to_char_type(0xBB));\n                    write_number(static_cast<uint64_t>(N));\n                }\n                // LCOV_EXCL_STOP\n\n                // step 2: write each element\n                for (const auto& el : *j.m_value.object)\n                {\n                    write_cbor(el.first);\n                    write_cbor(el.second);\n                }\n                break;\n            }\n\n            default:\n                break;\n        }\n    }\n\n    /*!\n    @param[in] j  JSON value to serialize\n    */\n    void write_msgpack(const BasicJsonType& j)\n    {\n        switch (j.type())\n        {\n            case value_t::null: // nil\n            {\n                oa->write_character(to_char_type(0xC0));\n                break;\n            }\n\n            case value_t::boolean: // true and false\n            {\n                oa->write_character(j.m_value.boolean\n                                    ? to_char_type(0xC3)\n                                    : to_char_type(0xC2));\n                break;\n            }\n\n            case value_t::number_integer:\n            {\n                if (j.m_value.number_integer >= 0)\n                {\n                    // MessagePack does not differentiate between positive\n                    // signed integers and unsigned integers. Therefore, we used\n                    // the code from the value_t::number_unsigned case here.\n                    if (j.m_value.number_unsigned < 128)\n                    {\n                        // positive fixnum\n                        write_number(static_cast<uint8_t>(j.m_value.number_integer));\n                    }\n                    else if (j.m_value.number_unsigned <= (std::numeric_limits<uint8_t>::max)())\n                    {\n                        // uint 8\n                        oa->write_character(to_char_type(0xCC));\n                        write_number(static_cast<uint8_t>(j.m_value.number_integer));\n                    }\n                    else if (j.m_value.number_unsigned <= (std::numeric_limits<uint16_t>::max)())\n                    {\n                        // uint 16\n                        oa->write_character(to_char_type(0xCD));\n                        write_number(static_cast<uint16_t>(j.m_value.number_integer));\n                    }\n                    else if (j.m_value.number_unsigned <= (std::numeric_limits<uint32_t>::max)())\n                    {\n                        // uint 32\n                        oa->write_character(to_char_type(0xCE));\n                        write_number(static_cast<uint32_t>(j.m_value.number_integer));\n                    }\n                    else if (j.m_value.number_unsigned <= (std::numeric_limits<uint64_t>::max)())\n                    {\n                        // uint 64\n                        oa->write_character(to_char_type(0xCF));\n                        write_number(static_cast<uint64_t>(j.m_value.number_integer));\n                    }\n                }\n                else\n                {\n                    if (j.m_value.number_integer >= -32)\n                    {\n                        // negative fixnum\n                        write_number(static_cast<int8_t>(j.m_value.number_integer));\n                    }\n                    else if (j.m_value.number_integer >= (std::numeric_limits<int8_t>::min)() and\n                             j.m_value.number_integer <= (std::numeric_limits<int8_t>::max)())\n                    {\n                        // int 8\n                        oa->write_character(to_char_type(0xD0));\n                        write_number(static_cast<int8_t>(j.m_value.number_integer));\n                    }\n                    else if (j.m_value.number_integer >= (std::numeric_limits<int16_t>::min)() and\n                             j.m_value.number_integer <= (std::numeric_limits<int16_t>::max)())\n                    {\n                        // int 16\n                        oa->write_character(to_char_type(0xD1));\n                        write_number(static_cast<int16_t>(j.m_value.number_integer));\n                    }\n                    else if (j.m_value.number_integer >= (std::numeric_limits<int32_t>::min)() and\n                             j.m_value.number_integer <= (std::numeric_limits<int32_t>::max)())\n                    {\n                        // int 32\n                        oa->write_character(to_char_type(0xD2));\n                        write_number(static_cast<int32_t>(j.m_value.number_integer));\n                    }\n                    else if (j.m_value.number_integer >= (std::numeric_limits<int64_t>::min)() and\n                             j.m_value.number_integer <= (std::numeric_limits<int64_t>::max)())\n                    {\n                        // int 64\n                        oa->write_character(to_char_type(0xD3));\n                        write_number(static_cast<int64_t>(j.m_value.number_integer));\n                    }\n                }\n                break;\n            }\n\n            case value_t::number_unsigned:\n            {\n                if (j.m_value.number_unsigned < 128)\n                {\n                    // positive fixnum\n                    write_number(static_cast<uint8_t>(j.m_value.number_integer));\n                }\n                else if (j.m_value.number_unsigned <= (std::numeric_limits<uint8_t>::max)())\n                {\n                    // uint 8\n                    oa->write_character(to_char_type(0xCC));\n                    write_number(static_cast<uint8_t>(j.m_value.number_integer));\n                }\n                else if (j.m_value.number_unsigned <= (std::numeric_limits<uint16_t>::max)())\n                {\n                    // uint 16\n                    oa->write_character(to_char_type(0xCD));\n                    write_number(static_cast<uint16_t>(j.m_value.number_integer));\n                }\n                else if (j.m_value.number_unsigned <= (std::numeric_limits<uint32_t>::max)())\n                {\n                    // uint 32\n                    oa->write_character(to_char_type(0xCE));\n                    write_number(static_cast<uint32_t>(j.m_value.number_integer));\n                }\n                else if (j.m_value.number_unsigned <= (std::numeric_limits<uint64_t>::max)())\n                {\n                    // uint 64\n                    oa->write_character(to_char_type(0xCF));\n                    write_number(static_cast<uint64_t>(j.m_value.number_integer));\n                }\n                break;\n            }\n\n            case value_t::number_float:\n            {\n                oa->write_character(get_msgpack_float_prefix(j.m_value.number_float));\n                write_number(j.m_value.number_float);\n                break;\n            }\n\n            case value_t::string:\n            {\n                // step 1: write control byte and the string length\n                const auto N = j.m_value.string->size();\n                if (N <= 31)\n                {\n                    // fixstr\n                    write_number(static_cast<uint8_t>(0xA0 | N));\n                }\n                else if (N <= (std::numeric_limits<uint8_t>::max)())\n                {\n                    // str 8\n                    oa->write_character(to_char_type(0xD9));\n                    write_number(static_cast<uint8_t>(N));\n                }\n                else if (N <= (std::numeric_limits<uint16_t>::max)())\n                {\n                    // str 16\n                    oa->write_character(to_char_type(0xDA));\n                    write_number(static_cast<uint16_t>(N));\n                }\n                else if (N <= (std::numeric_limits<uint32_t>::max)())\n                {\n                    // str 32\n                    oa->write_character(to_char_type(0xDB));\n                    write_number(static_cast<uint32_t>(N));\n                }\n\n                // step 2: write the string\n                oa->write_characters(\n                    reinterpret_cast<const CharType*>(j.m_value.string->c_str()),\n                    j.m_value.string->size());\n                break;\n            }\n\n            case value_t::array:\n            {\n                // step 1: write control byte and the array size\n                const auto N = j.m_value.array->size();\n                if (N <= 15)\n                {\n                    // fixarray\n                    write_number(static_cast<uint8_t>(0x90 | N));\n                }\n                else if (N <= (std::numeric_limits<uint16_t>::max)())\n                {\n                    // array 16\n                    oa->write_character(to_char_type(0xDC));\n                    write_number(static_cast<uint16_t>(N));\n                }\n                else if (N <= (std::numeric_limits<uint32_t>::max)())\n                {\n                    // array 32\n                    oa->write_character(to_char_type(0xDD));\n                    write_number(static_cast<uint32_t>(N));\n                }\n\n                // step 2: write each element\n                for (const auto& el : *j.m_value.array)\n                {\n                    write_msgpack(el);\n                }\n                break;\n            }\n\n            case value_t::object:\n            {\n                // step 1: write control byte and the object size\n                const auto N = j.m_value.object->size();\n                if (N <= 15)\n                {\n                    // fixmap\n                    write_number(static_cast<uint8_t>(0x80 | (N & 0xF)));\n                }\n                else if (N <= (std::numeric_limits<uint16_t>::max)())\n                {\n                    // map 16\n                    oa->write_character(to_char_type(0xDE));\n                    write_number(static_cast<uint16_t>(N));\n                }\n                else if (N <= (std::numeric_limits<uint32_t>::max)())\n                {\n                    // map 32\n                    oa->write_character(to_char_type(0xDF));\n                    write_number(static_cast<uint32_t>(N));\n                }\n\n                // step 2: write each element\n                for (const auto& el : *j.m_value.object)\n                {\n                    write_msgpack(el.first);\n                    write_msgpack(el.second);\n                }\n                break;\n            }\n\n            default:\n                break;\n        }\n    }\n\n    /*!\n    @param[in] j  JSON value to serialize\n    @param[in] use_count   whether to use '#' prefixes (optimized format)\n    @param[in] use_type    whether to use '$' prefixes (optimized format)\n    @param[in] add_prefix  whether prefixes need to be used for this value\n    */\n    void write_ubjson(const BasicJsonType& j, const bool use_count,\n                      const bool use_type, const bool add_prefix = true)\n    {\n        switch (j.type())\n        {\n            case value_t::null:\n            {\n                if (add_prefix)\n                {\n                    oa->write_character(to_char_type('Z'));\n                }\n                break;\n            }\n\n            case value_t::boolean:\n            {\n                if (add_prefix)\n                {\n                    oa->write_character(j.m_value.boolean\n                                        ? to_char_type('T')\n                                        : to_char_type('F'));\n                }\n                break;\n            }\n\n            case value_t::number_integer:\n            {\n                write_number_with_ubjson_prefix(j.m_value.number_integer, add_prefix);\n                break;\n            }\n\n            case value_t::number_unsigned:\n            {\n                write_number_with_ubjson_prefix(j.m_value.number_unsigned, add_prefix);\n                break;\n            }\n\n            case value_t::number_float:\n            {\n                write_number_with_ubjson_prefix(j.m_value.number_float, add_prefix);\n                break;\n            }\n\n            case value_t::string:\n            {\n                if (add_prefix)\n                {\n                    oa->write_character(to_char_type('S'));\n                }\n                write_number_with_ubjson_prefix(j.m_value.string->size(), true);\n                oa->write_characters(\n                    reinterpret_cast<const CharType*>(j.m_value.string->c_str()),\n                    j.m_value.string->size());\n                break;\n            }\n\n            case value_t::array:\n            {\n                if (add_prefix)\n                {\n                    oa->write_character(to_char_type('['));\n                }\n\n                bool prefix_required = true;\n                if (use_type and not j.m_value.array->empty())\n                {\n                    assert(use_count);\n                    const CharType first_prefix = ubjson_prefix(j.front());\n                    const bool same_prefix = std::all_of(j.begin() + 1, j.end(),\n                                                         [this, first_prefix](const BasicJsonType & v)\n                    {\n                        return ubjson_prefix(v) == first_prefix;\n                    });\n\n                    if (same_prefix)\n                    {\n                        prefix_required = false;\n                        oa->write_character(to_char_type('$'));\n                        oa->write_character(first_prefix);\n                    }\n                }\n\n                if (use_count)\n                {\n                    oa->write_character(to_char_type('#'));\n                    write_number_with_ubjson_prefix(j.m_value.array->size(), true);\n                }\n\n                for (const auto& el : *j.m_value.array)\n                {\n                    write_ubjson(el, use_count, use_type, prefix_required);\n                }\n\n                if (not use_count)\n                {\n                    oa->write_character(to_char_type(']'));\n                }\n\n                break;\n            }\n\n            case value_t::object:\n            {\n                if (add_prefix)\n                {\n                    oa->write_character(to_char_type('{'));\n                }\n\n                bool prefix_required = true;\n                if (use_type and not j.m_value.object->empty())\n                {\n                    assert(use_count);\n                    const CharType first_prefix = ubjson_prefix(j.front());\n                    const bool same_prefix = std::all_of(j.begin(), j.end(),\n                                                         [this, first_prefix](const BasicJsonType & v)\n                    {\n                        return ubjson_prefix(v) == first_prefix;\n                    });\n\n                    if (same_prefix)\n                    {\n                        prefix_required = false;\n                        oa->write_character(to_char_type('$'));\n                        oa->write_character(first_prefix);\n                    }\n                }\n\n                if (use_count)\n                {\n                    oa->write_character(to_char_type('#'));\n                    write_number_with_ubjson_prefix(j.m_value.object->size(), true);\n                }\n\n                for (const auto& el : *j.m_value.object)\n                {\n                    write_number_with_ubjson_prefix(el.first.size(), true);\n                    oa->write_characters(\n                        reinterpret_cast<const CharType*>(el.first.c_str()),\n                        el.first.size());\n                    write_ubjson(el.second, use_count, use_type, prefix_required);\n                }\n\n                if (not use_count)\n                {\n                    oa->write_character(to_char_type('}'));\n                }\n\n                break;\n            }\n\n            default:\n                break;\n        }\n    }\n\n  private:\n    //////////\n    // BSON //\n    //////////\n\n    /*!\n    @return The size of a BSON document entry header, including the id marker\n            and the entry name size (and its null-terminator).\n    */\n    static std::size_t calc_bson_entry_header_size(const string_t& name)\n    {\n        const auto it = name.find(static_cast<typename string_t::value_type>(0));\n        if (JSON_UNLIKELY(it != BasicJsonType::string_t::npos))\n        {\n            JSON_THROW(out_of_range::create(409,\n                                            \"BSON key cannot contain code point U+0000 (at byte \" + std::to_string(it) + \")\"));\n        }\n\n        return /*id*/ 1ul + name.size() + /*zero-terminator*/1u;\n    }\n\n    /*!\n    @brief Writes the given @a element_type and @a name to the output adapter\n    */\n    void write_bson_entry_header(const string_t& name,\n                                 const std::uint8_t element_type)\n    {\n        oa->write_character(to_char_type(element_type)); // boolean\n        oa->write_characters(\n            reinterpret_cast<const CharType*>(name.c_str()),\n            name.size() + 1u);\n    }\n\n    /*!\n    @brief Writes a BSON element with key @a name and boolean value @a value\n    */\n    void write_bson_boolean(const string_t& name,\n                            const bool value)\n    {\n        write_bson_entry_header(name, 0x08);\n        oa->write_character(value ? to_char_type(0x01) : to_char_type(0x00));\n    }\n\n    /*!\n    @brief Writes a BSON element with key @a name and double value @a value\n    */\n    void write_bson_double(const string_t& name,\n                           const double value)\n    {\n        write_bson_entry_header(name, 0x01);\n        write_number<double, true>(value);\n    }\n\n    /*!\n    @return The size of the BSON-encoded string in @a value\n    */\n    static std::size_t calc_bson_string_size(const string_t& value)\n    {\n        return sizeof(std::int32_t) + value.size() + 1ul;\n    }\n\n    /*!\n    @brief Writes a BSON element with key @a name and string value @a value\n    */\n    void write_bson_string(const string_t& name,\n                           const string_t& value)\n    {\n        write_bson_entry_header(name, 0x02);\n\n        write_number<std::int32_t, true>(static_cast<std::int32_t>(value.size() + 1ul));\n        oa->write_characters(\n            reinterpret_cast<const CharType*>(value.c_str()),\n            value.size() + 1);\n    }\n\n    /*!\n    @brief Writes a BSON element with key @a name and null value\n    */\n    void write_bson_null(const string_t& name)\n    {\n        write_bson_entry_header(name, 0x0A);\n    }\n\n    /*!\n    @return The size of the BSON-encoded integer @a value\n    */\n    static std::size_t calc_bson_integer_size(const std::int64_t value)\n    {\n        if ((std::numeric_limits<std::int32_t>::min)() <= value and value <= (std::numeric_limits<std::int32_t>::max)())\n        {\n            return sizeof(std::int32_t);\n        }\n        else\n        {\n            return sizeof(std::int64_t);\n        }\n    }\n\n    /*!\n    @brief Writes a BSON element with key @a name and integer @a value\n    */\n    void write_bson_integer(const string_t& name,\n                            const std::int64_t value)\n    {\n        if ((std::numeric_limits<std::int32_t>::min)() <= value and value <= (std::numeric_limits<std::int32_t>::max)())\n        {\n            write_bson_entry_header(name, 0x10); // int32\n            write_number<std::int32_t, true>(static_cast<std::int32_t>(value));\n        }\n        else\n        {\n            write_bson_entry_header(name, 0x12); // int64\n            write_number<std::int64_t, true>(static_cast<std::int64_t>(value));\n        }\n    }\n\n    /*!\n    @return The size of the BSON-encoded unsigned integer in @a j\n    */\n    static constexpr std::size_t calc_bson_unsigned_size(const std::uint64_t value) noexcept\n    {\n        return (value <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))\n               ? sizeof(std::int32_t)\n               : sizeof(std::int64_t);\n    }\n\n    /*!\n    @brief Writes a BSON element with key @a name and unsigned @a value\n    */\n    void write_bson_unsigned(const string_t& name,\n                             const std::uint64_t value)\n    {\n        if (value <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))\n        {\n            write_bson_entry_header(name, 0x10 /* int32 */);\n            write_number<std::int32_t, true>(static_cast<std::int32_t>(value));\n        }\n        else if (value <= static_cast<std::uint64_t>((std::numeric_limits<std::int64_t>::max)()))\n        {\n            write_bson_entry_header(name, 0x12 /* int64 */);\n            write_number<std::int64_t, true>(static_cast<std::int64_t>(value));\n        }\n        else\n        {\n            JSON_THROW(out_of_range::create(407, \"integer number \" + std::to_string(value) + \" cannot be represented by BSON as it does not fit int64\"));\n        }\n    }\n\n    /*!\n    @brief Writes a BSON element with key @a name and object @a value\n    */\n    void write_bson_object_entry(const string_t& name,\n                                 const typename BasicJsonType::object_t& value)\n    {\n        write_bson_entry_header(name, 0x03); // object\n        write_bson_object(value);\n    }\n\n    /*!\n    @return The size of the BSON-encoded array @a value\n    */\n    static std::size_t calc_bson_array_size(const typename BasicJsonType::array_t& value)\n    {\n        std::size_t embedded_document_size = 0ul;\n        std::size_t array_index = 0ul;\n\n        for (const auto& el : value)\n        {\n            embedded_document_size += calc_bson_element_size(std::to_string(array_index++), el);\n        }\n\n        return sizeof(std::int32_t) + embedded_document_size + 1ul;\n    }\n\n    /*!\n    @brief Writes a BSON element with key @a name and array @a value\n    */\n    void write_bson_array(const string_t& name,\n                          const typename BasicJsonType::array_t& value)\n    {\n        write_bson_entry_header(name, 0x04); // array\n        write_number<std::int32_t, true>(static_cast<std::int32_t>(calc_bson_array_size(value)));\n\n        std::size_t array_index = 0ul;\n\n        for (const auto& el : value)\n        {\n            write_bson_element(std::to_string(array_index++), el);\n        }\n\n        oa->write_character(to_char_type(0x00));\n    }\n\n    /*!\n    @brief Calculates the size necessary to serialize the JSON value @a j with its @a name\n    @return The calculated size for the BSON document entry for @a j with the given @a name.\n    */\n    static std::size_t calc_bson_element_size(const string_t& name,\n            const BasicJsonType& j)\n    {\n        const auto header_size = calc_bson_entry_header_size(name);\n        switch (j.type())\n        {\n            case value_t::object:\n                return header_size + calc_bson_object_size(*j.m_value.object);\n\n            case value_t::array:\n                return header_size + calc_bson_array_size(*j.m_value.array);\n\n            case value_t::boolean:\n                return header_size + 1ul;\n\n            case value_t::number_float:\n                return header_size + 8ul;\n\n            case value_t::number_integer:\n                return header_size + calc_bson_integer_size(j.m_value.number_integer);\n\n            case value_t::number_unsigned:\n                return header_size + calc_bson_unsigned_size(j.m_value.number_unsigned);\n\n            case value_t::string:\n                return header_size + calc_bson_string_size(*j.m_value.string);\n\n            case value_t::null:\n                return header_size + 0ul;\n\n            // LCOV_EXCL_START\n            default:\n                assert(false);\n                return 0ul;\n                // LCOV_EXCL_STOP\n        }\n    }\n\n    /*!\n    @brief Serializes the JSON value @a j to BSON and associates it with the\n           key @a name.\n    @param name The name to associate with the JSON entity @a j within the\n                current BSON document\n    @return The size of the BSON entry\n    */\n    void write_bson_element(const string_t& name,\n                            const BasicJsonType& j)\n    {\n        switch (j.type())\n        {\n            case value_t::object:\n                return write_bson_object_entry(name, *j.m_value.object);\n\n            case value_t::array:\n                return write_bson_array(name, *j.m_value.array);\n\n            case value_t::boolean:\n                return write_bson_boolean(name, j.m_value.boolean);\n\n            case value_t::number_float:\n                return write_bson_double(name, j.m_value.number_float);\n\n            case value_t::number_integer:\n                return write_bson_integer(name, j.m_value.number_integer);\n\n            case value_t::number_unsigned:\n                return write_bson_unsigned(name, j.m_value.number_unsigned);\n\n            case value_t::string:\n                return write_bson_string(name, *j.m_value.string);\n\n            case value_t::null:\n                return write_bson_null(name);\n\n            // LCOV_EXCL_START\n            default:\n                assert(false);\n                return;\n                // LCOV_EXCL_STOP\n        }\n    }\n\n    /*!\n    @brief Calculates the size of the BSON serialization of the given\n           JSON-object @a j.\n    @param[in] j  JSON value to serialize\n    @pre       j.type() == value_t::object\n    */\n    static std::size_t calc_bson_object_size(const typename BasicJsonType::object_t& value)\n    {\n        std::size_t document_size = std::accumulate(value.begin(), value.end(), 0ul,\n                                    [](size_t result, const typename BasicJsonType::object_t::value_type & el)\n        {\n            return result += calc_bson_element_size(el.first, el.second);\n        });\n\n        return sizeof(std::int32_t) + document_size + 1ul;\n    }\n\n    /*!\n    @param[in] j  JSON value to serialize\n    @pre       j.type() == value_t::object\n    */\n    void write_bson_object(const typename BasicJsonType::object_t& value)\n    {\n        write_number<std::int32_t, true>(static_cast<std::int32_t>(calc_bson_object_size(value)));\n\n        for (const auto& el : value)\n        {\n            write_bson_element(el.first, el.second);\n        }\n\n        oa->write_character(to_char_type(0x00));\n    }\n\n    //////////\n    // CBOR //\n    //////////\n\n    static constexpr CharType get_cbor_float_prefix(float /*unused*/)\n    {\n        return to_char_type(0xFA);  // Single-Precision Float\n    }\n\n    static constexpr CharType get_cbor_float_prefix(double /*unused*/)\n    {\n        return to_char_type(0xFB);  // Double-Precision Float\n    }\n\n    /////////////\n    // MsgPack //\n    /////////////\n\n    static constexpr CharType get_msgpack_float_prefix(float /*unused*/)\n    {\n        return to_char_type(0xCA);  // float 32\n    }\n\n    static constexpr CharType get_msgpack_float_prefix(double /*unused*/)\n    {\n        return to_char_type(0xCB);  // float 64\n    }\n\n    ////////////\n    // UBJSON //\n    ////////////\n\n    // UBJSON: write number (floating point)\n    template<typename NumberType, typename std::enable_if<\n                 std::is_floating_point<NumberType>::value, int>::type = 0>\n    void write_number_with_ubjson_prefix(const NumberType n,\n                                         const bool add_prefix)\n    {\n        if (add_prefix)\n        {\n            oa->write_character(get_ubjson_float_prefix(n));\n        }\n        write_number(n);\n    }\n\n    // UBJSON: write number (unsigned integer)\n    template<typename NumberType, typename std::enable_if<\n                 std::is_unsigned<NumberType>::value, int>::type = 0>\n    void write_number_with_ubjson_prefix(const NumberType n,\n                                         const bool add_prefix)\n    {\n        if (n <= static_cast<uint64_t>((std::numeric_limits<int8_t>::max)()))\n        {\n            if (add_prefix)\n            {\n                oa->write_character(to_char_type('i'));  // int8\n            }\n            write_number(static_cast<uint8_t>(n));\n        }\n        else if (n <= (std::numeric_limits<uint8_t>::max)())\n        {\n            if (add_prefix)\n            {\n                oa->write_character(to_char_type('U'));  // uint8\n            }\n            write_number(static_cast<uint8_t>(n));\n        }\n        else if (n <= static_cast<uint64_t>((std::numeric_limits<int16_t>::max)()))\n        {\n            if (add_prefix)\n            {\n                oa->write_character(to_char_type('I'));  // int16\n            }\n            write_number(static_cast<int16_t>(n));\n        }\n        else if (n <= static_cast<uint64_t>((std::numeric_limits<int32_t>::max)()))\n        {\n            if (add_prefix)\n            {\n                oa->write_character(to_char_type('l'));  // int32\n            }\n            write_number(static_cast<int32_t>(n));\n        }\n        else if (n <= static_cast<uint64_t>((std::numeric_limits<int64_t>::max)()))\n        {\n            if (add_prefix)\n            {\n                oa->write_character(to_char_type('L'));  // int64\n            }\n            write_number(static_cast<int64_t>(n));\n        }\n        else\n        {\n            JSON_THROW(out_of_range::create(407, \"integer number \" + std::to_string(n) + \" cannot be represented by UBJSON as it does not fit int64\"));\n        }\n    }\n\n    // UBJSON: write number (signed integer)\n    template<typename NumberType, typename std::enable_if<\n                 std::is_signed<NumberType>::value and\n                 not std::is_floating_point<NumberType>::value, int>::type = 0>\n    void write_number_with_ubjson_prefix(const NumberType n,\n                                         const bool add_prefix)\n    {\n        if ((std::numeric_limits<int8_t>::min)() <= n and n <= (std::numeric_limits<int8_t>::max)())\n        {\n            if (add_prefix)\n            {\n                oa->write_character(to_char_type('i'));  // int8\n            }\n            write_number(static_cast<int8_t>(n));\n        }\n        else if (static_cast<int64_t>((std::numeric_limits<uint8_t>::min)()) <= n and n <= static_cast<int64_t>((std::numeric_limits<uint8_t>::max)()))\n        {\n            if (add_prefix)\n            {\n                oa->write_character(to_char_type('U'));  // uint8\n            }\n            write_number(static_cast<uint8_t>(n));\n        }\n        else if ((std::numeric_limits<int16_t>::min)() <= n and n <= (std::numeric_limits<int16_t>::max)())\n        {\n            if (add_prefix)\n            {\n                oa->write_character(to_char_type('I'));  // int16\n            }\n            write_number(static_cast<int16_t>(n));\n        }\n        else if ((std::numeric_limits<int32_t>::min)() <= n and n <= (std::numeric_limits<int32_t>::max)())\n        {\n            if (add_prefix)\n            {\n                oa->write_character(to_char_type('l'));  // int32\n            }\n            write_number(static_cast<int32_t>(n));\n        }\n        else if ((std::numeric_limits<int64_t>::min)() <= n and n <= (std::numeric_limits<int64_t>::max)())\n        {\n            if (add_prefix)\n            {\n                oa->write_character(to_char_type('L'));  // int64\n            }\n            write_number(static_cast<int64_t>(n));\n        }\n        // LCOV_EXCL_START\n        else\n        {\n            JSON_THROW(out_of_range::create(407, \"integer number \" + std::to_string(n) + \" cannot be represented by UBJSON as it does not fit int64\"));\n        }\n        // LCOV_EXCL_STOP\n    }\n\n    /*!\n    @brief determine the type prefix of container values\n\n    @note This function does not need to be 100% accurate when it comes to\n          integer limits. In case a number exceeds the limits of int64_t,\n          this will be detected by a later call to function\n          write_number_with_ubjson_prefix. Therefore, we return 'L' for any\n          value that does not fit the previous limits.\n    */\n    CharType ubjson_prefix(const BasicJsonType& j) const noexcept\n    {\n        switch (j.type())\n        {\n            case value_t::null:\n                return 'Z';\n\n            case value_t::boolean:\n                return j.m_value.boolean ? 'T' : 'F';\n\n            case value_t::number_integer:\n            {\n                if ((std::numeric_limits<int8_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<int8_t>::max)())\n                {\n                    return 'i';\n                }\n                if ((std::numeric_limits<uint8_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<uint8_t>::max)())\n                {\n                    return 'U';\n                }\n                if ((std::numeric_limits<int16_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<int16_t>::max)())\n                {\n                    return 'I';\n                }\n                if ((std::numeric_limits<int32_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<int32_t>::max)())\n                {\n                    return 'l';\n                }\n                // no check and assume int64_t (see note above)\n                return 'L';\n            }\n\n            case value_t::number_unsigned:\n            {\n                if (j.m_value.number_unsigned <= (std::numeric_limits<int8_t>::max)())\n                {\n                    return 'i';\n                }\n                if (j.m_value.number_unsigned <= (std::numeric_limits<uint8_t>::max)())\n                {\n                    return 'U';\n                }\n                if (j.m_value.number_unsigned <= (std::numeric_limits<int16_t>::max)())\n                {\n                    return 'I';\n                }\n                if (j.m_value.number_unsigned <= (std::numeric_limits<int32_t>::max)())\n                {\n                    return 'l';\n                }\n                // no check and assume int64_t (see note above)\n                return 'L';\n            }\n\n            case value_t::number_float:\n                return get_ubjson_float_prefix(j.m_value.number_float);\n\n            case value_t::string:\n                return 'S';\n\n            case value_t::array:\n                return '[';\n\n            case value_t::object:\n                return '{';\n\n            default:  // discarded values\n                return 'N';\n        }\n    }\n\n    static constexpr CharType get_ubjson_float_prefix(float /*unused*/)\n    {\n        return 'd';  // float 32\n    }\n\n    static constexpr CharType get_ubjson_float_prefix(double /*unused*/)\n    {\n        return 'D';  // float 64\n    }\n\n    ///////////////////////\n    // Utility functions //\n    ///////////////////////\n\n    /*\n    @brief write a number to output input\n    @param[in] n number of type @a NumberType\n    @tparam NumberType the type of the number\n    @tparam OutputIsLittleEndian Set to true if output data is\n                                 required to be little endian\n\n    @note This function needs to respect the system's endianess, because bytes\n          in CBOR, MessagePack, and UBJSON are stored in network order (big\n          endian) and therefore need reordering on little endian systems.\n    */\n    template<typename NumberType, bool OutputIsLittleEndian = false>\n    void write_number(const NumberType n)\n    {\n        // step 1: write number to array of length NumberType\n        std::array<CharType, sizeof(NumberType)> vec;\n        std::memcpy(vec.data(), &n, sizeof(NumberType));\n\n        // step 2: write array to output (with possible reordering)\n        if (is_little_endian and not OutputIsLittleEndian)\n        {\n            // reverse byte order prior to conversion if necessary\n            std::reverse(vec.begin(), vec.end());\n        }\n\n        oa->write_characters(vec.data(), sizeof(NumberType));\n    }\n\n  public:\n    // The following to_char_type functions are implement the conversion\n    // between uint8_t and CharType. In case CharType is not unsigned,\n    // such a conversion is required to allow values greater than 128.\n    // See <https://github.com/nlohmann/json/issues/1286> for a discussion.\n    template < typename C = CharType,\n               enable_if_t < std::is_signed<C>::value and std::is_signed<char>::value > * = nullptr >\n    static constexpr CharType to_char_type(std::uint8_t x) noexcept\n    {\n        return *reinterpret_cast<char*>(&x);\n    }\n\n    template < typename C = CharType,\n               enable_if_t < std::is_signed<C>::value and std::is_unsigned<char>::value > * = nullptr >\n    static CharType to_char_type(std::uint8_t x) noexcept\n    {\n        static_assert(sizeof(std::uint8_t) == sizeof(CharType), \"size of CharType must be equal to std::uint8_t\");\n        static_assert(std::is_pod<CharType>::value, \"CharType must be POD\");\n        CharType result;\n        std::memcpy(&result, &x, sizeof(x));\n        return result;\n    }\n\n    template<typename C = CharType,\n             enable_if_t<std::is_unsigned<C>::value>* = nullptr>\n    static constexpr CharType to_char_type(std::uint8_t x) noexcept\n    {\n        return x;\n    }\n\n    template < typename InputCharType, typename C = CharType,\n               enable_if_t <\n                   std::is_signed<C>::value and\n                   std::is_signed<char>::value and\n                   std::is_same<char, typename std::remove_cv<InputCharType>::type>::value\n                   > * = nullptr >\n    static constexpr CharType to_char_type(InputCharType x) noexcept\n    {\n        return x;\n    }\n\n  private:\n    /// whether we can assume little endianess\n    const bool is_little_endian = binary_reader<BasicJsonType>::little_endianess();\n\n    /// the output\n    output_adapter_t<CharType> oa = nullptr;\n};\n}  // namespace detail\n}  // namespace nlohmann\n"
  },
  {
    "path": "nlohmann_json/include/nlohmann/detail/output/output_adapters.hpp",
    "content": "#pragma once\n\n#include <algorithm> // copy\n#include <cstddef> // size_t\n#include <ios> // streamsize\n#include <iterator> // back_inserter\n#include <memory> // shared_ptr, make_shared\n#include <ostream> // basic_ostream\n#include <string> // basic_string\n#include <vector> // vector\n\nnamespace nlohmann\n{\nnamespace detail\n{\n/// abstract output adapter interface\ntemplate<typename CharType> struct output_adapter_protocol\n{\n    virtual void write_character(CharType c) = 0;\n    virtual void write_characters(const CharType* s, std::size_t length) = 0;\n    virtual ~output_adapter_protocol() = default;\n};\n\n/// a type to simplify interfaces\ntemplate<typename CharType>\nusing output_adapter_t = std::shared_ptr<output_adapter_protocol<CharType>>;\n\n/// output adapter for byte vectors\ntemplate<typename CharType>\nclass output_vector_adapter : public output_adapter_protocol<CharType>\n{\n  public:\n    explicit output_vector_adapter(std::vector<CharType>& vec) noexcept\n        : v(vec)\n    {}\n\n    void write_character(CharType c) override\n    {\n        v.push_back(c);\n    }\n\n    void write_characters(const CharType* s, std::size_t length) override\n    {\n        std::copy(s, s + length, std::back_inserter(v));\n    }\n\n  private:\n    std::vector<CharType>& v;\n};\n\n/// output adapter for output streams\ntemplate<typename CharType>\nclass output_stream_adapter : public output_adapter_protocol<CharType>\n{\n  public:\n    explicit output_stream_adapter(std::basic_ostream<CharType>& s) noexcept\n        : stream(s)\n    {}\n\n    void write_character(CharType c) override\n    {\n        stream.put(c);\n    }\n\n    void write_characters(const CharType* s, std::size_t length) override\n    {\n        stream.write(s, static_cast<std::streamsize>(length));\n    }\n\n  private:\n    std::basic_ostream<CharType>& stream;\n};\n\n/// output adapter for basic_string\ntemplate<typename CharType, typename StringType = std::basic_string<CharType>>\nclass output_string_adapter : public output_adapter_protocol<CharType>\n{\n  public:\n    explicit output_string_adapter(StringType& s) noexcept\n        : str(s)\n    {}\n\n    void write_character(CharType c) override\n    {\n        str.push_back(c);\n    }\n\n    void write_characters(const CharType* s, std::size_t length) override\n    {\n        str.append(s, length);\n    }\n\n  private:\n    StringType& str;\n};\n\ntemplate<typename CharType, typename StringType = std::basic_string<CharType>>\nclass output_adapter\n{\n  public:\n    output_adapter(std::vector<CharType>& vec)\n        : oa(std::make_shared<output_vector_adapter<CharType>>(vec)) {}\n\n    output_adapter(std::basic_ostream<CharType>& s)\n        : oa(std::make_shared<output_stream_adapter<CharType>>(s)) {}\n\n    output_adapter(StringType& s)\n        : oa(std::make_shared<output_string_adapter<CharType, StringType>>(s)) {}\n\n    operator output_adapter_t<CharType>()\n    {\n        return oa;\n    }\n\n  private:\n    output_adapter_t<CharType> oa = nullptr;\n};\n}  // namespace detail\n}  // namespace nlohmann\n"
  },
  {
    "path": "nlohmann_json/include/nlohmann/detail/output/serializer.hpp",
    "content": "#pragma once\n\n#include <algorithm> // reverse, remove, fill, find, none_of\n#include <array> // array\n#include <cassert> // assert\n#include <ciso646> // and, or\n#include <clocale> // localeconv, lconv\n#include <cmath> // labs, isfinite, isnan, signbit\n#include <cstddef> // size_t, ptrdiff_t\n#include <cstdint> // uint8_t\n#include <cstdio> // snprintf\n#include <limits> // numeric_limits\n#include <string> // string\n#include <type_traits> // is_same\n\n#include <nlohmann/detail/exceptions.hpp>\n#include <nlohmann/detail/conversions/to_chars.hpp>\n#include <nlohmann/detail/macro_scope.hpp>\n#include <nlohmann/detail/meta/cpp_future.hpp>\n#include <nlohmann/detail/output/binary_writer.hpp>\n#include <nlohmann/detail/output/output_adapters.hpp>\n#include <nlohmann/detail/value_t.hpp>\n\nnamespace nlohmann\n{\nnamespace detail\n{\n///////////////////\n// serialization //\n///////////////////\n\n/// how to treat decoding errors\nenum class error_handler_t\n{\n    strict,  ///< throw a type_error exception in case of invalid UTF-8\n    replace, ///< replace invalid UTF-8 sequences with U+FFFD\n    ignore   ///< ignore invalid UTF-8 sequences\n};\n\ntemplate<typename BasicJsonType>\nclass serializer\n{\n    using string_t = typename BasicJsonType::string_t;\n    using number_float_t = typename BasicJsonType::number_float_t;\n    using number_integer_t = typename BasicJsonType::number_integer_t;\n    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n    static constexpr uint8_t UTF8_ACCEPT = 0;\n    static constexpr uint8_t UTF8_REJECT = 1;\n\n  public:\n    /*!\n    @param[in] s  output stream to serialize to\n    @param[in] ichar  indentation character to use\n    @param[in] error_handler_  how to react on decoding errors\n    */\n    serializer(output_adapter_t<char> s, const char ichar,\n               error_handler_t error_handler_ = error_handler_t::strict)\n        : o(std::move(s))\n        , loc(std::localeconv())\n        , thousands_sep(loc->thousands_sep == nullptr ? '\\0' : * (loc->thousands_sep))\n        , decimal_point(loc->decimal_point == nullptr ? '\\0' : * (loc->decimal_point))\n        , indent_char(ichar)\n        , indent_string(512, indent_char)\n        , error_handler(error_handler_)\n    {}\n\n    // delete because of pointer members\n    serializer(const serializer&) = delete;\n    serializer& operator=(const serializer&) = delete;\n    serializer(serializer&&) = delete;\n    serializer& operator=(serializer&&) = delete;\n    ~serializer() = default;\n\n    /*!\n    @brief internal implementation of the serialization function\n\n    This function is called by the public member function dump and organizes\n    the serialization internally. The indentation level is propagated as\n    additional parameter. In case of arrays and objects, the function is\n    called recursively.\n\n    - strings and object keys are escaped using `escape_string()`\n    - integer numbers are converted implicitly via `operator<<`\n    - floating-point numbers are converted to a string using `\"%g\"` format\n\n    @param[in] val             value to serialize\n    @param[in] pretty_print    whether the output shall be pretty-printed\n    @param[in] indent_step     the indent level\n    @param[in] current_indent  the current indent level (only used internally)\n    */\n    void dump(const BasicJsonType& val, const bool pretty_print,\n              const bool ensure_ascii,\n              const unsigned int indent_step,\n              const unsigned int current_indent = 0)\n    {\n        switch (val.m_type)\n        {\n            case value_t::object:\n            {\n                if (val.m_value.object->empty())\n                {\n                    o->write_characters(\"{}\", 2);\n                    return;\n                }\n\n                if (pretty_print)\n                {\n                    o->write_characters(\"{\\n\", 2);\n\n                    // variable to hold indentation for recursive calls\n                    const auto new_indent = current_indent + indent_step;\n                    if (JSON_UNLIKELY(indent_string.size() < new_indent))\n                    {\n                        indent_string.resize(indent_string.size() * 2, ' ');\n                    }\n\n                    // first n-1 elements\n                    auto i = val.m_value.object->cbegin();\n                    for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i)\n                    {\n                        o->write_characters(indent_string.c_str(), new_indent);\n                        o->write_character('\\\"');\n                        dump_escaped(i->first, ensure_ascii);\n                        o->write_characters(\"\\\": \", 3);\n                        dump(i->second, true, ensure_ascii, indent_step, new_indent);\n                        o->write_characters(\",\\n\", 2);\n                    }\n\n                    // last element\n                    assert(i != val.m_value.object->cend());\n                    assert(std::next(i) == val.m_value.object->cend());\n                    o->write_characters(indent_string.c_str(), new_indent);\n                    o->write_character('\\\"');\n                    dump_escaped(i->first, ensure_ascii);\n                    o->write_characters(\"\\\": \", 3);\n                    dump(i->second, true, ensure_ascii, indent_step, new_indent);\n\n                    o->write_character('\\n');\n                    o->write_characters(indent_string.c_str(), current_indent);\n                    o->write_character('}');\n                }\n                else\n                {\n                    o->write_character('{');\n\n                    // first n-1 elements\n                    auto i = val.m_value.object->cbegin();\n                    for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i)\n                    {\n                        o->write_character('\\\"');\n                        dump_escaped(i->first, ensure_ascii);\n                        o->write_characters(\"\\\":\", 2);\n                        dump(i->second, false, ensure_ascii, indent_step, current_indent);\n                        o->write_character(',');\n                    }\n\n                    // last element\n                    assert(i != val.m_value.object->cend());\n                    assert(std::next(i) == val.m_value.object->cend());\n                    o->write_character('\\\"');\n                    dump_escaped(i->first, ensure_ascii);\n                    o->write_characters(\"\\\":\", 2);\n                    dump(i->second, false, ensure_ascii, indent_step, current_indent);\n\n                    o->write_character('}');\n                }\n\n                return;\n            }\n\n            case value_t::array:\n            {\n                if (val.m_value.array->empty())\n                {\n                    o->write_characters(\"[]\", 2);\n                    return;\n                }\n\n                if (pretty_print)\n                {\n                    o->write_characters(\"[\\n\", 2);\n\n                    // variable to hold indentation for recursive calls\n                    const auto new_indent = current_indent + indent_step;\n                    if (JSON_UNLIKELY(indent_string.size() < new_indent))\n                    {\n                        indent_string.resize(indent_string.size() * 2, ' ');\n                    }\n\n                    // first n-1 elements\n                    for (auto i = val.m_value.array->cbegin();\n                            i != val.m_value.array->cend() - 1; ++i)\n                    {\n                        o->write_characters(indent_string.c_str(), new_indent);\n                        dump(*i, true, ensure_ascii, indent_step, new_indent);\n                        o->write_characters(\",\\n\", 2);\n                    }\n\n                    // last element\n                    assert(not val.m_value.array->empty());\n                    o->write_characters(indent_string.c_str(), new_indent);\n                    dump(val.m_value.array->back(), true, ensure_ascii, indent_step, new_indent);\n\n                    o->write_character('\\n');\n                    o->write_characters(indent_string.c_str(), current_indent);\n                    o->write_character(']');\n                }\n                else\n                {\n                    o->write_character('[');\n\n                    // first n-1 elements\n                    for (auto i = val.m_value.array->cbegin();\n                            i != val.m_value.array->cend() - 1; ++i)\n                    {\n                        dump(*i, false, ensure_ascii, indent_step, current_indent);\n                        o->write_character(',');\n                    }\n\n                    // last element\n                    assert(not val.m_value.array->empty());\n                    dump(val.m_value.array->back(), false, ensure_ascii, indent_step, current_indent);\n\n                    o->write_character(']');\n                }\n\n                return;\n            }\n\n            case value_t::string:\n            {\n                o->write_character('\\\"');\n                dump_escaped(*val.m_value.string, ensure_ascii);\n                o->write_character('\\\"');\n                return;\n            }\n\n            case value_t::boolean:\n            {\n                if (val.m_value.boolean)\n                {\n                    o->write_characters(\"true\", 4);\n                }\n                else\n                {\n                    o->write_characters(\"false\", 5);\n                }\n                return;\n            }\n\n            case value_t::number_integer:\n            {\n                dump_integer(val.m_value.number_integer);\n                return;\n            }\n\n            case value_t::number_unsigned:\n            {\n                dump_integer(val.m_value.number_unsigned);\n                return;\n            }\n\n            case value_t::number_float:\n            {\n                dump_float(val.m_value.number_float);\n                return;\n            }\n\n            case value_t::discarded:\n            {\n                o->write_characters(\"<discarded>\", 11);\n                return;\n            }\n\n            case value_t::null:\n            {\n                o->write_characters(\"null\", 4);\n                return;\n            }\n        }\n    }\n\n  private:\n    /*!\n    @brief dump escaped string\n\n    Escape a string by replacing certain special characters by a sequence of an\n    escape character (backslash) and another character and other control\n    characters by a sequence of \"\\u\" followed by a four-digit hex\n    representation. The escaped string is written to output stream @a o.\n\n    @param[in] s  the string to escape\n    @param[in] ensure_ascii  whether to escape non-ASCII characters with\n                             \\uXXXX sequences\n\n    @complexity Linear in the length of string @a s.\n    */\n    void dump_escaped(const string_t& s, const bool ensure_ascii)\n    {\n        uint32_t codepoint;\n        uint8_t state = UTF8_ACCEPT;\n        std::size_t bytes = 0;  // number of bytes written to string_buffer\n\n        // number of bytes written at the point of the last valid byte\n        std::size_t bytes_after_last_accept = 0;\n        std::size_t undumped_chars = 0;\n\n        for (std::size_t i = 0; i < s.size(); ++i)\n        {\n            const auto byte = static_cast<uint8_t>(s[i]);\n\n            switch (decode(state, codepoint, byte))\n            {\n                case UTF8_ACCEPT:  // decode found a new code point\n                {\n                    switch (codepoint)\n                    {\n                        case 0x08: // backspace\n                        {\n                            string_buffer[bytes++] = '\\\\';\n                            string_buffer[bytes++] = 'b';\n                            break;\n                        }\n\n                        case 0x09: // horizontal tab\n                        {\n                            string_buffer[bytes++] = '\\\\';\n                            string_buffer[bytes++] = 't';\n                            break;\n                        }\n\n                        case 0x0A: // newline\n                        {\n                            string_buffer[bytes++] = '\\\\';\n                            string_buffer[bytes++] = 'n';\n                            break;\n                        }\n\n                        case 0x0C: // formfeed\n                        {\n                            string_buffer[bytes++] = '\\\\';\n                            string_buffer[bytes++] = 'f';\n                            break;\n                        }\n\n                        case 0x0D: // carriage return\n                        {\n                            string_buffer[bytes++] = '\\\\';\n                            string_buffer[bytes++] = 'r';\n                            break;\n                        }\n\n                        case 0x22: // quotation mark\n                        {\n                            string_buffer[bytes++] = '\\\\';\n                            string_buffer[bytes++] = '\\\"';\n                            break;\n                        }\n\n                        case 0x5C: // reverse solidus\n                        {\n                            string_buffer[bytes++] = '\\\\';\n                            string_buffer[bytes++] = '\\\\';\n                            break;\n                        }\n\n                        default:\n                        {\n                            // escape control characters (0x00..0x1F) or, if\n                            // ensure_ascii parameter is used, non-ASCII characters\n                            if ((codepoint <= 0x1F) or (ensure_ascii and (codepoint >= 0x7F)))\n                            {\n                                if (codepoint <= 0xFFFF)\n                                {\n                                    (std::snprintf)(string_buffer.data() + bytes, 7, \"\\\\u%04x\",\n                                                    static_cast<uint16_t>(codepoint));\n                                    bytes += 6;\n                                }\n                                else\n                                {\n                                    (std::snprintf)(string_buffer.data() + bytes, 13, \"\\\\u%04x\\\\u%04x\",\n                                                    static_cast<uint16_t>(0xD7C0 + (codepoint >> 10)),\n                                                    static_cast<uint16_t>(0xDC00 + (codepoint & 0x3FF)));\n                                    bytes += 12;\n                                }\n                            }\n                            else\n                            {\n                                // copy byte to buffer (all previous bytes\n                                // been copied have in default case above)\n                                string_buffer[bytes++] = s[i];\n                            }\n                            break;\n                        }\n                    }\n\n                    // write buffer and reset index; there must be 13 bytes\n                    // left, as this is the maximal number of bytes to be\n                    // written (\"\\uxxxx\\uxxxx\\0\") for one code point\n                    if (string_buffer.size() - bytes < 13)\n                    {\n                        o->write_characters(string_buffer.data(), bytes);\n                        bytes = 0;\n                    }\n\n                    // remember the byte position of this accept\n                    bytes_after_last_accept = bytes;\n                    undumped_chars = 0;\n                    break;\n                }\n\n                case UTF8_REJECT:  // decode found invalid UTF-8 byte\n                {\n                    switch (error_handler)\n                    {\n                        case error_handler_t::strict:\n                        {\n                            std::string sn(3, '\\0');\n                            (std::snprintf)(&sn[0], sn.size(), \"%.2X\", byte);\n                            JSON_THROW(type_error::create(316, \"invalid UTF-8 byte at index \" + std::to_string(i) + \": 0x\" + sn));\n                        }\n\n                        case error_handler_t::ignore:\n                        case error_handler_t::replace:\n                        {\n                            // in case we saw this character the first time, we\n                            // would like to read it again, because the byte\n                            // may be OK for itself, but just not OK for the\n                            // previous sequence\n                            if (undumped_chars > 0)\n                            {\n                                --i;\n                            }\n\n                            // reset length buffer to the last accepted index;\n                            // thus removing/ignoring the invalid characters\n                            bytes = bytes_after_last_accept;\n\n                            if (error_handler == error_handler_t::replace)\n                            {\n                                // add a replacement character\n                                if (ensure_ascii)\n                                {\n                                    string_buffer[bytes++] = '\\\\';\n                                    string_buffer[bytes++] = 'u';\n                                    string_buffer[bytes++] = 'f';\n                                    string_buffer[bytes++] = 'f';\n                                    string_buffer[bytes++] = 'f';\n                                    string_buffer[bytes++] = 'd';\n                                }\n                                else\n                                {\n                                    string_buffer[bytes++] = detail::binary_writer<BasicJsonType, char>::to_char_type('\\xEF');\n                                    string_buffer[bytes++] = detail::binary_writer<BasicJsonType, char>::to_char_type('\\xBF');\n                                    string_buffer[bytes++] = detail::binary_writer<BasicJsonType, char>::to_char_type('\\xBD');\n                                }\n                                bytes_after_last_accept = bytes;\n                            }\n\n                            undumped_chars = 0;\n\n                            // continue processing the string\n                            state = UTF8_ACCEPT;\n                            break;\n                        }\n                    }\n                    break;\n                }\n\n                default:  // decode found yet incomplete multi-byte code point\n                {\n                    if (not ensure_ascii)\n                    {\n                        // code point will not be escaped - copy byte to buffer\n                        string_buffer[bytes++] = s[i];\n                    }\n                    ++undumped_chars;\n                    break;\n                }\n            }\n        }\n\n        // we finished processing the string\n        if (JSON_LIKELY(state == UTF8_ACCEPT))\n        {\n            // write buffer\n            if (bytes > 0)\n            {\n                o->write_characters(string_buffer.data(), bytes);\n            }\n        }\n        else\n        {\n            // we finish reading, but do not accept: string was incomplete\n            switch (error_handler)\n            {\n                case error_handler_t::strict:\n                {\n                    std::string sn(3, '\\0');\n                    (std::snprintf)(&sn[0], sn.size(), \"%.2X\", static_cast<uint8_t>(s.back()));\n                    JSON_THROW(type_error::create(316, \"incomplete UTF-8 string; last byte: 0x\" + sn));\n                }\n\n                case error_handler_t::ignore:\n                {\n                    // write all accepted bytes\n                    o->write_characters(string_buffer.data(), bytes_after_last_accept);\n                    break;\n                }\n\n                case error_handler_t::replace:\n                {\n                    // write all accepted bytes\n                    o->write_characters(string_buffer.data(), bytes_after_last_accept);\n                    // add a replacement character\n                    if (ensure_ascii)\n                    {\n                        o->write_characters(\"\\\\ufffd\", 6);\n                    }\n                    else\n                    {\n                        o->write_characters(\"\\xEF\\xBF\\xBD\", 3);\n                    }\n                    break;\n                }\n            }\n        }\n    }\n\n    /*!\n    @brief dump an integer\n\n    Dump a given integer to output stream @a o. Works internally with\n    @a number_buffer.\n\n    @param[in] x  integer number (signed or unsigned) to dump\n    @tparam NumberType either @a number_integer_t or @a number_unsigned_t\n    */\n    template<typename NumberType, detail::enable_if_t<\n                 std::is_same<NumberType, number_unsigned_t>::value or\n                 std::is_same<NumberType, number_integer_t>::value,\n                 int> = 0>\n    void dump_integer(NumberType x)\n    {\n        // special case for \"0\"\n        if (x == 0)\n        {\n            o->write_character('0');\n            return;\n        }\n\n        const bool is_negative = std::is_same<NumberType, number_integer_t>::value and not (x >= 0);  // see issue #755\n        std::size_t i = 0;\n\n        while (x != 0)\n        {\n            // spare 1 byte for '\\0'\n            assert(i < number_buffer.size() - 1);\n\n            const auto digit = std::labs(static_cast<long>(x % 10));\n            number_buffer[i++] = static_cast<char>('0' + digit);\n            x /= 10;\n        }\n\n        if (is_negative)\n        {\n            // make sure there is capacity for the '-'\n            assert(i < number_buffer.size() - 2);\n            number_buffer[i++] = '-';\n        }\n\n        std::reverse(number_buffer.begin(), number_buffer.begin() + i);\n        o->write_characters(number_buffer.data(), i);\n    }\n\n    /*!\n    @brief dump a floating-point number\n\n    Dump a given floating-point number to output stream @a o. Works internally\n    with @a number_buffer.\n\n    @param[in] x  floating-point number to dump\n    */\n    void dump_float(number_float_t x)\n    {\n        // NaN / inf\n        if (not std::isfinite(x))\n        {\n            o->write_characters(\"null\", 4);\n            return;\n        }\n\n        // If number_float_t is an IEEE-754 single or double precision number,\n        // use the Grisu2 algorithm to produce short numbers which are\n        // guaranteed to round-trip, using strtof and strtod, resp.\n        //\n        // NB: The test below works if <long double> == <double>.\n        static constexpr bool is_ieee_single_or_double\n            = (std::numeric_limits<number_float_t>::is_iec559 and std::numeric_limits<number_float_t>::digits == 24 and std::numeric_limits<number_float_t>::max_exponent == 128) or\n              (std::numeric_limits<number_float_t>::is_iec559 and std::numeric_limits<number_float_t>::digits == 53 and std::numeric_limits<number_float_t>::max_exponent == 1024);\n\n        dump_float(x, std::integral_constant<bool, is_ieee_single_or_double>());\n    }\n\n    void dump_float(number_float_t x, std::true_type /*is_ieee_single_or_double*/)\n    {\n        char* begin = number_buffer.data();\n        char* end = ::nlohmann::detail::to_chars(begin, begin + number_buffer.size(), x);\n\n        o->write_characters(begin, static_cast<size_t>(end - begin));\n    }\n\n    void dump_float(number_float_t x, std::false_type /*is_ieee_single_or_double*/)\n    {\n        // get number of digits for a float -> text -> float round-trip\n        static constexpr auto d = std::numeric_limits<number_float_t>::max_digits10;\n\n        // the actual conversion\n        std::ptrdiff_t len = (std::snprintf)(number_buffer.data(), number_buffer.size(), \"%.*g\", d, x);\n\n        // negative value indicates an error\n        assert(len > 0);\n        // check if buffer was large enough\n        assert(static_cast<std::size_t>(len) < number_buffer.size());\n\n        // erase thousands separator\n        if (thousands_sep != '\\0')\n        {\n            const auto end = std::remove(number_buffer.begin(),\n                                         number_buffer.begin() + len, thousands_sep);\n            std::fill(end, number_buffer.end(), '\\0');\n            assert((end - number_buffer.begin()) <= len);\n            len = (end - number_buffer.begin());\n        }\n\n        // convert decimal point to '.'\n        if (decimal_point != '\\0' and decimal_point != '.')\n        {\n            const auto dec_pos = std::find(number_buffer.begin(), number_buffer.end(), decimal_point);\n            if (dec_pos != number_buffer.end())\n            {\n                *dec_pos = '.';\n            }\n        }\n\n        o->write_characters(number_buffer.data(), static_cast<std::size_t>(len));\n\n        // determine if need to append \".0\"\n        const bool value_is_int_like =\n            std::none_of(number_buffer.begin(), number_buffer.begin() + len + 1,\n                         [](char c)\n        {\n            return (c == '.' or c == 'e');\n        });\n\n        if (value_is_int_like)\n        {\n            o->write_characters(\".0\", 2);\n        }\n    }\n\n    /*!\n    @brief check whether a string is UTF-8 encoded\n\n    The function checks each byte of a string whether it is UTF-8 encoded. The\n    result of the check is stored in the @a state parameter. The function must\n    be called initially with state 0 (accept). State 1 means the string must\n    be rejected, because the current byte is not allowed. If the string is\n    completely processed, but the state is non-zero, the string ended\n    prematurely; that is, the last byte indicated more bytes should have\n    followed.\n\n    @param[in,out] state  the state of the decoding\n    @param[in,out] codep  codepoint (valid only if resulting state is UTF8_ACCEPT)\n    @param[in] byte       next byte to decode\n    @return               new state\n\n    @note The function has been edited: a std::array is used.\n\n    @copyright Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>\n    @sa http://bjoern.hoehrmann.de/utf-8/decoder/dfa/\n    */\n    static uint8_t decode(uint8_t& state, uint32_t& codep, const uint8_t byte) noexcept\n    {\n        static const std::array<uint8_t, 400> utf8d =\n        {\n            {\n                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00..1F\n                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20..3F\n                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40..5F\n                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60..7F\n                1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 80..9F\n                7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // A0..BF\n                8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // C0..DF\n                0xA, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3, 0x3, // E0..EF\n                0xB, 0x6, 0x6, 0x6, 0x5, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, // F0..FF\n                0x0, 0x1, 0x2, 0x3, 0x5, 0x8, 0x7, 0x1, 0x1, 0x1, 0x4, 0x6, 0x1, 0x1, 0x1, 0x1, // s0..s0\n                1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, // s1..s2\n                1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, // s3..s4\n                1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, // s5..s6\n                1, 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // s7..s8\n            }\n        };\n\n        const uint8_t type = utf8d[byte];\n\n        codep = (state != UTF8_ACCEPT)\n                ? (byte & 0x3fu) | (codep << 6)\n                : static_cast<uint32_t>(0xff >> type) & (byte);\n\n        state = utf8d[256u + state * 16u + type];\n        return state;\n    }\n\n  private:\n    /// the output of the serializer\n    output_adapter_t<char> o = nullptr;\n\n    /// a (hopefully) large enough character buffer\n    std::array<char, 64> number_buffer{{}};\n\n    /// the locale\n    const std::lconv* loc = nullptr;\n    /// the locale's thousand separator character\n    const char thousands_sep = '\\0';\n    /// the locale's decimal point character\n    const char decimal_point = '\\0';\n\n    /// string buffer\n    std::array<char, 512> string_buffer{{}};\n\n    /// the indentation character\n    const char indent_char;\n    /// the indentation string\n    string_t indent_string;\n\n    /// error_handler how to react on decoding errors\n    const error_handler_t error_handler;\n};\n}  // namespace detail\n}  // namespace nlohmann\n"
  },
  {
    "path": "nlohmann_json/include/nlohmann/detail/value_t.hpp",
    "content": "#pragma once\n\n#include <array> // array\n#include <ciso646> // and\n#include <cstddef> // size_t\n#include <cstdint> // uint8_t\n\nnamespace nlohmann\n{\nnamespace detail\n{\n///////////////////////////\n// JSON type enumeration //\n///////////////////////////\n\n/*!\n@brief the JSON type enumeration\n\nThis enumeration collects the different JSON types. It is internally used to\ndistinguish the stored values, and the functions @ref basic_json::is_null(),\n@ref basic_json::is_object(), @ref basic_json::is_array(),\n@ref basic_json::is_string(), @ref basic_json::is_boolean(),\n@ref basic_json::is_number() (with @ref basic_json::is_number_integer(),\n@ref basic_json::is_number_unsigned(), and @ref basic_json::is_number_float()),\n@ref basic_json::is_discarded(), @ref basic_json::is_primitive(), and\n@ref basic_json::is_structured() rely on it.\n\n@note There are three enumeration entries (number_integer, number_unsigned, and\nnumber_float), because the library distinguishes these three types for numbers:\n@ref basic_json::number_unsigned_t is used for unsigned integers,\n@ref basic_json::number_integer_t is used for signed integers, and\n@ref basic_json::number_float_t is used for floating-point numbers or to\napproximate integers which do not fit in the limits of their respective type.\n\n@sa @ref basic_json::basic_json(const value_t value_type) -- create a JSON\nvalue with the default value for a given type\n\n@since version 1.0.0\n*/\nenum class value_t : std::uint8_t\n{\n    null,             ///< null value\n    object,           ///< object (unordered set of name/value pairs)\n    array,            ///< array (ordered collection of values)\n    string,           ///< string value\n    boolean,          ///< boolean value\n    number_integer,   ///< number value (signed integer)\n    number_unsigned,  ///< number value (unsigned integer)\n    number_float,     ///< number value (floating-point)\n    discarded         ///< discarded by the the parser callback function\n};\n\n/*!\n@brief comparison operator for JSON types\n\nReturns an ordering that is similar to Python:\n- order: null < boolean < number < object < array < string\n- furthermore, each type is not smaller than itself\n- discarded values are not comparable\n\n@since version 1.0.0\n*/\ninline bool operator<(const value_t lhs, const value_t rhs) noexcept\n{\n    static constexpr std::array<std::uint8_t, 8> order = {{\n            0 /* null */, 3 /* object */, 4 /* array */, 5 /* string */,\n            1 /* boolean */, 2 /* integer */, 2 /* unsigned */, 2 /* float */\n        }\n    };\n\n    const auto l_index = static_cast<std::size_t>(lhs);\n    const auto r_index = static_cast<std::size_t>(rhs);\n    return l_index < order.size() and r_index < order.size() and order[l_index] < order[r_index];\n}\n}  // namespace detail\n}  // namespace nlohmann\n"
  },
  {
    "path": "nlohmann_json/include/nlohmann/json.hpp",
    "content": "/*\n    __ _____ _____ _____\n __|  |   __|     |   | |  JSON for Modern C++\n|  |  |__   |  |  | | | |  version 3.5.0\n|_____|_____|_____|_|___|  https://github.com/nlohmann/json\n\nLicensed under the MIT License <http://opensource.org/licenses/MIT>.\nSPDX-License-Identifier: MIT\nCopyright (c) 2013-2018 Niels Lohmann <http://nlohmann.me>.\n\nPermission is hereby  granted, free of charge, to any  person obtaining a copy\nof this software and associated  documentation files (the \"Software\"), to deal\nin the Software  without restriction, including without  limitation the rights\nto  use, copy,  modify, merge,  publish, distribute,  sublicense, and/or  sell\ncopies  of  the Software,  and  to  permit persons  to  whom  the Software  is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE  IS PROVIDED \"AS  IS\", WITHOUT WARRANTY  OF ANY KIND,  EXPRESS OR\nIMPLIED,  INCLUDING BUT  NOT  LIMITED TO  THE  WARRANTIES OF  MERCHANTABILITY,\nFITNESS FOR  A PARTICULAR PURPOSE AND  NONINFRINGEMENT. IN NO EVENT  SHALL THE\nAUTHORS  OR COPYRIGHT  HOLDERS  BE  LIABLE FOR  ANY  CLAIM,  DAMAGES OR  OTHER\nLIABILITY, WHETHER IN AN ACTION OF  CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE  OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n*/\n\n#ifndef NLOHMANN_JSON_HPP\n#define NLOHMANN_JSON_HPP\n\n#define NLOHMANN_JSON_VERSION_MAJOR 3\n#define NLOHMANN_JSON_VERSION_MINOR 5\n#define NLOHMANN_JSON_VERSION_PATCH 0\n\n#include <algorithm> // all_of, find, for_each\n#include <cassert> // assert\n#include <ciso646> // and, not, or\n#include <cstddef> // nullptr_t, ptrdiff_t, size_t\n#include <functional> // hash, less\n#include <initializer_list> // initializer_list\n#include <iosfwd> // istream, ostream\n#include <iterator> // random_access_iterator_tag\n#include <numeric> // accumulate\n#include <string> // string, stoi, to_string\n#include <utility> // declval, forward, move, pair, swap\n\n#include <nlohmann/json_fwd.hpp>\n#include <nlohmann/detail/macro_scope.hpp>\n#include <nlohmann/detail/meta/cpp_future.hpp>\n#include <nlohmann/detail/meta/type_traits.hpp>\n#include <nlohmann/detail/exceptions.hpp>\n#include <nlohmann/detail/value_t.hpp>\n#include <nlohmann/detail/conversions/from_json.hpp>\n#include <nlohmann/detail/conversions/to_json.hpp>\n#include <nlohmann/detail/input/input_adapters.hpp>\n#include <nlohmann/detail/input/lexer.hpp>\n#include <nlohmann/detail/input/parser.hpp>\n#include <nlohmann/detail/iterators/primitive_iterator.hpp>\n#include <nlohmann/detail/iterators/internal_iterator.hpp>\n#include <nlohmann/detail/iterators/iter_impl.hpp>\n#include <nlohmann/detail/iterators/iteration_proxy.hpp>\n#include <nlohmann/detail/iterators/json_reverse_iterator.hpp>\n#include <nlohmann/detail/output/output_adapters.hpp>\n#include <nlohmann/detail/input/binary_reader.hpp>\n#include <nlohmann/detail/output/binary_writer.hpp>\n#include <nlohmann/detail/output/serializer.hpp>\n#include <nlohmann/detail/json_ref.hpp>\n#include <nlohmann/detail/json_pointer.hpp>\n#include <nlohmann/adl_serializer.hpp>\n\n/*!\n@brief namespace for Niels Lohmann\n@see https://github.com/nlohmann\n@since version 1.0.0\n*/\nnamespace nlohmann\n{\n\n/*!\n@brief a class to store JSON values\n\n@tparam ObjectType type for JSON objects (`std::map` by default; will be used\nin @ref object_t)\n@tparam ArrayType type for JSON arrays (`std::vector` by default; will be used\nin @ref array_t)\n@tparam StringType type for JSON strings and object keys (`std::string` by\ndefault; will be used in @ref string_t)\n@tparam BooleanType type for JSON booleans (`bool` by default; will be used\nin @ref boolean_t)\n@tparam NumberIntegerType type for JSON integer numbers (`int64_t` by\ndefault; will be used in @ref number_integer_t)\n@tparam NumberUnsignedType type for JSON unsigned integer numbers (@c\n`uint64_t` by default; will be used in @ref number_unsigned_t)\n@tparam NumberFloatType type for JSON floating-point numbers (`double` by\ndefault; will be used in @ref number_float_t)\n@tparam AllocatorType type of the allocator to use (`std::allocator` by\ndefault)\n@tparam JSONSerializer the serializer to resolve internal calls to `to_json()`\nand `from_json()` (@ref adl_serializer by default)\n\n@requirement The class satisfies the following concept requirements:\n- Basic\n - [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible):\n   JSON values can be default constructed. The result will be a JSON null\n   value.\n - [MoveConstructible](https://en.cppreference.com/w/cpp/named_req/MoveConstructible):\n   A JSON value can be constructed from an rvalue argument.\n - [CopyConstructible](https://en.cppreference.com/w/cpp/named_req/CopyConstructible):\n   A JSON value can be copy-constructed from an lvalue expression.\n - [MoveAssignable](https://en.cppreference.com/w/cpp/named_req/MoveAssignable):\n   A JSON value van be assigned from an rvalue argument.\n - [CopyAssignable](https://en.cppreference.com/w/cpp/named_req/CopyAssignable):\n   A JSON value can be copy-assigned from an lvalue expression.\n - [Destructible](https://en.cppreference.com/w/cpp/named_req/Destructible):\n   JSON values can be destructed.\n- Layout\n - [StandardLayoutType](https://en.cppreference.com/w/cpp/named_req/StandardLayoutType):\n   JSON values have\n   [standard layout](https://en.cppreference.com/w/cpp/language/data_members#Standard_layout):\n   All non-static data members are private and standard layout types, the\n   class has no virtual functions or (virtual) base classes.\n- Library-wide\n - [EqualityComparable](https://en.cppreference.com/w/cpp/named_req/EqualityComparable):\n   JSON values can be compared with `==`, see @ref\n   operator==(const_reference,const_reference).\n - [LessThanComparable](https://en.cppreference.com/w/cpp/named_req/LessThanComparable):\n   JSON values can be compared with `<`, see @ref\n   operator<(const_reference,const_reference).\n - [Swappable](https://en.cppreference.com/w/cpp/named_req/Swappable):\n   Any JSON lvalue or rvalue of can be swapped with any lvalue or rvalue of\n   other compatible types, using unqualified function call @ref swap().\n - [NullablePointer](https://en.cppreference.com/w/cpp/named_req/NullablePointer):\n   JSON values can be compared against `std::nullptr_t` objects which are used\n   to model the `null` value.\n- Container\n - [Container](https://en.cppreference.com/w/cpp/named_req/Container):\n   JSON values can be used like STL containers and provide iterator access.\n - [ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer);\n   JSON values can be used like STL containers and provide reverse iterator\n   access.\n\n@invariant The member variables @a m_value and @a m_type have the following\nrelationship:\n- If `m_type == value_t::object`, then `m_value.object != nullptr`.\n- If `m_type == value_t::array`, then `m_value.array != nullptr`.\n- If `m_type == value_t::string`, then `m_value.string != nullptr`.\nThe invariants are checked by member function assert_invariant().\n\n@internal\n@note ObjectType trick from http://stackoverflow.com/a/9860911\n@endinternal\n\n@see [RFC 7159: The JavaScript Object Notation (JSON) Data Interchange\nFormat](http://rfc7159.net/rfc7159)\n\n@since version 1.0.0\n\n@nosubgrouping\n*/\nNLOHMANN_BASIC_JSON_TPL_DECLARATION\nclass basic_json\n{\n  private:\n    template<detail::value_t> friend struct detail::external_constructor;\n    friend ::nlohmann::json_pointer<basic_json>;\n    friend ::nlohmann::detail::parser<basic_json>;\n    friend ::nlohmann::detail::serializer<basic_json>;\n    template<typename BasicJsonType>\n    friend class ::nlohmann::detail::iter_impl;\n    template<typename BasicJsonType, typename CharType>\n    friend class ::nlohmann::detail::binary_writer;\n    template<typename BasicJsonType, typename SAX>\n    friend class ::nlohmann::detail::binary_reader;\n    template<typename BasicJsonType>\n    friend class ::nlohmann::detail::json_sax_dom_parser;\n    template<typename BasicJsonType>\n    friend class ::nlohmann::detail::json_sax_dom_callback_parser;\n\n    /// workaround type for MSVC\n    using basic_json_t = NLOHMANN_BASIC_JSON_TPL;\n\n    // convenience aliases for types residing in namespace detail;\n    using lexer = ::nlohmann::detail::lexer<basic_json>;\n    using parser = ::nlohmann::detail::parser<basic_json>;\n\n    using primitive_iterator_t = ::nlohmann::detail::primitive_iterator_t;\n    template<typename BasicJsonType>\n    using internal_iterator = ::nlohmann::detail::internal_iterator<BasicJsonType>;\n    template<typename BasicJsonType>\n    using iter_impl = ::nlohmann::detail::iter_impl<BasicJsonType>;\n    template<typename Iterator>\n    using iteration_proxy = ::nlohmann::detail::iteration_proxy<Iterator>;\n    template<typename Base> using json_reverse_iterator = ::nlohmann::detail::json_reverse_iterator<Base>;\n\n    template<typename CharType>\n    using output_adapter_t = ::nlohmann::detail::output_adapter_t<CharType>;\n\n    using binary_reader = ::nlohmann::detail::binary_reader<basic_json>;\n    template<typename CharType> using binary_writer = ::nlohmann::detail::binary_writer<basic_json, CharType>;\n\n    using serializer = ::nlohmann::detail::serializer<basic_json>;\n\n  public:\n    using value_t = detail::value_t;\n    /// JSON Pointer, see @ref nlohmann::json_pointer\n    using json_pointer = ::nlohmann::json_pointer<basic_json>;\n    template<typename T, typename SFINAE>\n    using json_serializer = JSONSerializer<T, SFINAE>;\n    /// how to treat decoding errors\n    using error_handler_t = detail::error_handler_t;\n    /// helper type for initializer lists of basic_json values\n    using initializer_list_t = std::initializer_list<detail::json_ref<basic_json>>;\n\n    using input_format_t = detail::input_format_t;\n    /// SAX interface type, see @ref nlohmann::json_sax\n    using json_sax_t = json_sax<basic_json>;\n\n    ////////////////\n    // exceptions //\n    ////////////////\n\n    /// @name exceptions\n    /// Classes to implement user-defined exceptions.\n    /// @{\n\n    /// @copydoc detail::exception\n    using exception = detail::exception;\n    /// @copydoc detail::parse_error\n    using parse_error = detail::parse_error;\n    /// @copydoc detail::invalid_iterator\n    using invalid_iterator = detail::invalid_iterator;\n    /// @copydoc detail::type_error\n    using type_error = detail::type_error;\n    /// @copydoc detail::out_of_range\n    using out_of_range = detail::out_of_range;\n    /// @copydoc detail::other_error\n    using other_error = detail::other_error;\n\n    /// @}\n\n\n    /////////////////////\n    // container types //\n    /////////////////////\n\n    /// @name container types\n    /// The canonic container types to use @ref basic_json like any other STL\n    /// container.\n    /// @{\n\n    /// the type of elements in a basic_json container\n    using value_type = basic_json;\n\n    /// the type of an element reference\n    using reference = value_type&;\n    /// the type of an element const reference\n    using const_reference = const value_type&;\n\n    /// a type to represent differences between iterators\n    using difference_type = std::ptrdiff_t;\n    /// a type to represent container sizes\n    using size_type = std::size_t;\n\n    /// the allocator type\n    using allocator_type = AllocatorType<basic_json>;\n\n    /// the type of an element pointer\n    using pointer = typename std::allocator_traits<allocator_type>::pointer;\n    /// the type of an element const pointer\n    using const_pointer = typename std::allocator_traits<allocator_type>::const_pointer;\n\n    /// an iterator for a basic_json container\n    using iterator = iter_impl<basic_json>;\n    /// a const iterator for a basic_json container\n    using const_iterator = iter_impl<const basic_json>;\n    /// a reverse iterator for a basic_json container\n    using reverse_iterator = json_reverse_iterator<typename basic_json::iterator>;\n    /// a const reverse iterator for a basic_json container\n    using const_reverse_iterator = json_reverse_iterator<typename basic_json::const_iterator>;\n\n    /// @}\n\n\n    /*!\n    @brief returns the allocator associated with the container\n    */\n    static allocator_type get_allocator()\n    {\n        return allocator_type();\n    }\n\n    /*!\n    @brief returns version information on the library\n\n    This function returns a JSON object with information about the library,\n    including the version number and information on the platform and compiler.\n\n    @return JSON object holding version information\n    key         | description\n    ----------- | ---------------\n    `compiler`  | Information on the used compiler. It is an object with the following keys: `c++` (the used C++ standard), `family` (the compiler family; possible values are `clang`, `icc`, `gcc`, `ilecpp`, `msvc`, `pgcpp`, `sunpro`, and `unknown`), and `version` (the compiler version).\n    `copyright` | The copyright line for the library as string.\n    `name`      | The name of the library as string.\n    `platform`  | The used platform as string. Possible values are `win32`, `linux`, `apple`, `unix`, and `unknown`.\n    `url`       | The URL of the project as string.\n    `version`   | The version of the library. It is an object with the following keys: `major`, `minor`, and `patch` as defined by [Semantic Versioning](http://semver.org), and `string` (the version string).\n\n    @liveexample{The following code shows an example output of the `meta()`\n    function.,meta}\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes to any JSON value.\n\n    @complexity Constant.\n\n    @since 2.1.0\n    */\n    static basic_json meta()\n    {\n        basic_json result;\n\n        result[\"copyright\"] = \"(C) 2013-2017 Niels Lohmann\";\n        result[\"name\"] = \"JSON for Modern C++\";\n        result[\"url\"] = \"https://github.com/nlohmann/json\";\n        result[\"version\"][\"string\"] =\n            std::to_string(NLOHMANN_JSON_VERSION_MAJOR) + \".\" +\n            std::to_string(NLOHMANN_JSON_VERSION_MINOR) + \".\" +\n            std::to_string(NLOHMANN_JSON_VERSION_PATCH);\n        result[\"version\"][\"major\"] = NLOHMANN_JSON_VERSION_MAJOR;\n        result[\"version\"][\"minor\"] = NLOHMANN_JSON_VERSION_MINOR;\n        result[\"version\"][\"patch\"] = NLOHMANN_JSON_VERSION_PATCH;\n\n#ifdef _WIN32\n        result[\"platform\"] = \"win32\";\n#elif defined __linux__\n        result[\"platform\"] = \"linux\";\n#elif defined __APPLE__\n        result[\"platform\"] = \"apple\";\n#elif defined __unix__\n        result[\"platform\"] = \"unix\";\n#else\n        result[\"platform\"] = \"unknown\";\n#endif\n\n#if defined(__ICC) || defined(__INTEL_COMPILER)\n        result[\"compiler\"] = {{\"family\", \"icc\"}, {\"version\", __INTEL_COMPILER}};\n#elif defined(__clang__)\n        result[\"compiler\"] = {{\"family\", \"clang\"}, {\"version\", __clang_version__}};\n#elif defined(__GNUC__) || defined(__GNUG__)\n        result[\"compiler\"] = {{\"family\", \"gcc\"}, {\"version\", std::to_string(__GNUC__) + \".\" + std::to_string(__GNUC_MINOR__) + \".\" + std::to_string(__GNUC_PATCHLEVEL__)}};\n#elif defined(__HP_cc) || defined(__HP_aCC)\n        result[\"compiler\"] = \"hp\"\n#elif defined(__IBMCPP__)\n        result[\"compiler\"] = {{\"family\", \"ilecpp\"}, {\"version\", __IBMCPP__}};\n#elif defined(_MSC_VER)\n        result[\"compiler\"] = {{\"family\", \"msvc\"}, {\"version\", _MSC_VER}};\n#elif defined(__PGI)\n        result[\"compiler\"] = {{\"family\", \"pgcpp\"}, {\"version\", __PGI}};\n#elif defined(__SUNPRO_CC)\n        result[\"compiler\"] = {{\"family\", \"sunpro\"}, {\"version\", __SUNPRO_CC}};\n#else\n        result[\"compiler\"] = {{\"family\", \"unknown\"}, {\"version\", \"unknown\"}};\n#endif\n\n#ifdef __cplusplus\n        result[\"compiler\"][\"c++\"] = std::to_string(__cplusplus);\n#else\n        result[\"compiler\"][\"c++\"] = \"unknown\";\n#endif\n        return result;\n    }\n\n\n    ///////////////////////////\n    // JSON value data types //\n    ///////////////////////////\n\n    /// @name JSON value data types\n    /// The data types to store a JSON value. These types are derived from\n    /// the template arguments passed to class @ref basic_json.\n    /// @{\n\n#if defined(JSON_HAS_CPP_14)\n    // Use transparent comparator if possible, combined with perfect forwarding\n    // on find() and count() calls prevents unnecessary string construction.\n    using object_comparator_t = std::less<>;\n#else\n    using object_comparator_t = std::less<StringType>;\n#endif\n\n    /*!\n    @brief a type for an object\n\n    [RFC 7159](http://rfc7159.net/rfc7159) describes JSON objects as follows:\n    > An object is an unordered collection of zero or more name/value pairs,\n    > where a name is a string and a value is a string, number, boolean, null,\n    > object, or array.\n\n    To store objects in C++, a type is defined by the template parameters\n    described below.\n\n    @tparam ObjectType  the container to store objects (e.g., `std::map` or\n    `std::unordered_map`)\n    @tparam StringType the type of the keys or names (e.g., `std::string`).\n    The comparison function `std::less<StringType>` is used to order elements\n    inside the container.\n    @tparam AllocatorType the allocator to use for objects (e.g.,\n    `std::allocator`)\n\n    #### Default type\n\n    With the default values for @a ObjectType (`std::map`), @a StringType\n    (`std::string`), and @a AllocatorType (`std::allocator`), the default\n    value for @a object_t is:\n\n    @code {.cpp}\n    std::map<\n      std::string, // key_type\n      basic_json, // value_type\n      std::less<std::string>, // key_compare\n      std::allocator<std::pair<const std::string, basic_json>> // allocator_type\n    >\n    @endcode\n\n    #### Behavior\n\n    The choice of @a object_t influences the behavior of the JSON class. With\n    the default type, objects have the following behavior:\n\n    - When all names are unique, objects will be interoperable in the sense\n      that all software implementations receiving that object will agree on\n      the name-value mappings.\n    - When the names within an object are not unique, it is unspecified which\n      one of the values for a given key will be chosen. For instance,\n      `{\"key\": 2, \"key\": 1}` could be equal to either `{\"key\": 1}` or\n      `{\"key\": 2}`.\n    - Internally, name/value pairs are stored in lexicographical order of the\n      names. Objects will also be serialized (see @ref dump) in this order.\n      For instance, `{\"b\": 1, \"a\": 2}` and `{\"a\": 2, \"b\": 1}` will be stored\n      and serialized as `{\"a\": 2, \"b\": 1}`.\n    - When comparing objects, the order of the name/value pairs is irrelevant.\n      This makes objects interoperable in the sense that they will not be\n      affected by these differences. For instance, `{\"b\": 1, \"a\": 2}` and\n      `{\"a\": 2, \"b\": 1}` will be treated as equal.\n\n    #### Limits\n\n    [RFC 7159](http://rfc7159.net/rfc7159) specifies:\n    > An implementation may set limits on the maximum depth of nesting.\n\n    In this class, the object's limit of nesting is not explicitly constrained.\n    However, a maximum depth of nesting may be introduced by the compiler or\n    runtime environment. A theoretical limit can be queried by calling the\n    @ref max_size function of a JSON object.\n\n    #### Storage\n\n    Objects are stored as pointers in a @ref basic_json type. That is, for any\n    access to object values, a pointer of type `object_t*` must be\n    dereferenced.\n\n    @sa @ref array_t -- type for an array value\n\n    @since version 1.0.0\n\n    @note The order name/value pairs are added to the object is *not*\n    preserved by the library. Therefore, iterating an object may return\n    name/value pairs in a different order than they were originally stored. In\n    fact, keys will be traversed in alphabetical order as `std::map` with\n    `std::less` is used by default. Please note this behavior conforms to [RFC\n    7159](http://rfc7159.net/rfc7159), because any order implements the\n    specified \"unordered\" nature of JSON objects.\n    */\n    using object_t = ObjectType<StringType,\n          basic_json,\n          object_comparator_t,\n          AllocatorType<std::pair<const StringType,\n          basic_json>>>;\n\n    /*!\n    @brief a type for an array\n\n    [RFC 7159](http://rfc7159.net/rfc7159) describes JSON arrays as follows:\n    > An array is an ordered sequence of zero or more values.\n\n    To store objects in C++, a type is defined by the template parameters\n    explained below.\n\n    @tparam ArrayType  container type to store arrays (e.g., `std::vector` or\n    `std::list`)\n    @tparam AllocatorType allocator to use for arrays (e.g., `std::allocator`)\n\n    #### Default type\n\n    With the default values for @a ArrayType (`std::vector`) and @a\n    AllocatorType (`std::allocator`), the default value for @a array_t is:\n\n    @code {.cpp}\n    std::vector<\n      basic_json, // value_type\n      std::allocator<basic_json> // allocator_type\n    >\n    @endcode\n\n    #### Limits\n\n    [RFC 7159](http://rfc7159.net/rfc7159) specifies:\n    > An implementation may set limits on the maximum depth of nesting.\n\n    In this class, the array's limit of nesting is not explicitly constrained.\n    However, a maximum depth of nesting may be introduced by the compiler or\n    runtime environment. A theoretical limit can be queried by calling the\n    @ref max_size function of a JSON array.\n\n    #### Storage\n\n    Arrays are stored as pointers in a @ref basic_json type. That is, for any\n    access to array values, a pointer of type `array_t*` must be dereferenced.\n\n    @sa @ref object_t -- type for an object value\n\n    @since version 1.0.0\n    */\n    using array_t = ArrayType<basic_json, AllocatorType<basic_json>>;\n\n    /*!\n    @brief a type for a string\n\n    [RFC 7159](http://rfc7159.net/rfc7159) describes JSON strings as follows:\n    > A string is a sequence of zero or more Unicode characters.\n\n    To store objects in C++, a type is defined by the template parameter\n    described below. Unicode values are split by the JSON class into\n    byte-sized characters during deserialization.\n\n    @tparam StringType  the container to store strings (e.g., `std::string`).\n    Note this container is used for keys/names in objects, see @ref object_t.\n\n    #### Default type\n\n    With the default values for @a StringType (`std::string`), the default\n    value for @a string_t is:\n\n    @code {.cpp}\n    std::string\n    @endcode\n\n    #### Encoding\n\n    Strings are stored in UTF-8 encoding. Therefore, functions like\n    `std::string::size()` or `std::string::length()` return the number of\n    bytes in the string rather than the number of characters or glyphs.\n\n    #### String comparison\n\n    [RFC 7159](http://rfc7159.net/rfc7159) states:\n    > Software implementations are typically required to test names of object\n    > members for equality. Implementations that transform the textual\n    > representation into sequences of Unicode code units and then perform the\n    > comparison numerically, code unit by code unit, are interoperable in the\n    > sense that implementations will agree in all cases on equality or\n    > inequality of two strings. For example, implementations that compare\n    > strings with escaped characters unconverted may incorrectly find that\n    > `\"a\\\\b\"` and `\"a\\u005Cb\"` are not equal.\n\n    This implementation is interoperable as it does compare strings code unit\n    by code unit.\n\n    #### Storage\n\n    String values are stored as pointers in a @ref basic_json type. That is,\n    for any access to string values, a pointer of type `string_t*` must be\n    dereferenced.\n\n    @since version 1.0.0\n    */\n    using string_t = StringType;\n\n    /*!\n    @brief a type for a boolean\n\n    [RFC 7159](http://rfc7159.net/rfc7159) implicitly describes a boolean as a\n    type which differentiates the two literals `true` and `false`.\n\n    To store objects in C++, a type is defined by the template parameter @a\n    BooleanType which chooses the type to use.\n\n    #### Default type\n\n    With the default values for @a BooleanType (`bool`), the default value for\n    @a boolean_t is:\n\n    @code {.cpp}\n    bool\n    @endcode\n\n    #### Storage\n\n    Boolean values are stored directly inside a @ref basic_json type.\n\n    @since version 1.0.0\n    */\n    using boolean_t = BooleanType;\n\n    /*!\n    @brief a type for a number (integer)\n\n    [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows:\n    > The representation of numbers is similar to that used in most\n    > programming languages. A number is represented in base 10 using decimal\n    > digits. It contains an integer component that may be prefixed with an\n    > optional minus sign, which may be followed by a fraction part and/or an\n    > exponent part. Leading zeros are not allowed. (...) Numeric values that\n    > cannot be represented in the grammar below (such as Infinity and NaN)\n    > are not permitted.\n\n    This description includes both integer and floating-point numbers.\n    However, C++ allows more precise storage if it is known whether the number\n    is a signed integer, an unsigned integer or a floating-point number.\n    Therefore, three different types, @ref number_integer_t, @ref\n    number_unsigned_t and @ref number_float_t are used.\n\n    To store integer numbers in C++, a type is defined by the template\n    parameter @a NumberIntegerType which chooses the type to use.\n\n    #### Default type\n\n    With the default values for @a NumberIntegerType (`int64_t`), the default\n    value for @a number_integer_t is:\n\n    @code {.cpp}\n    int64_t\n    @endcode\n\n    #### Default behavior\n\n    - The restrictions about leading zeros is not enforced in C++. Instead,\n      leading zeros in integer literals lead to an interpretation as octal\n      number. Internally, the value will be stored as decimal number. For\n      instance, the C++ integer literal `010` will be serialized to `8`.\n      During deserialization, leading zeros yield an error.\n    - Not-a-number (NaN) values will be serialized to `null`.\n\n    #### Limits\n\n    [RFC 7159](http://rfc7159.net/rfc7159) specifies:\n    > An implementation may set limits on the range and precision of numbers.\n\n    When the default type is used, the maximal integer number that can be\n    stored is `9223372036854775807` (INT64_MAX) and the minimal integer number\n    that can be stored is `-9223372036854775808` (INT64_MIN). Integer numbers\n    that are out of range will yield over/underflow when used in a\n    constructor. During deserialization, too large or small integer numbers\n    will be automatically be stored as @ref number_unsigned_t or @ref\n    number_float_t.\n\n    [RFC 7159](http://rfc7159.net/rfc7159) further states:\n    > Note that when such software is used, numbers that are integers and are\n    > in the range \\f$[-2^{53}+1, 2^{53}-1]\\f$ are interoperable in the sense\n    > that implementations will agree exactly on their numeric values.\n\n    As this range is a subrange of the exactly supported range [INT64_MIN,\n    INT64_MAX], this class's integer type is interoperable.\n\n    #### Storage\n\n    Integer number values are stored directly inside a @ref basic_json type.\n\n    @sa @ref number_float_t -- type for number values (floating-point)\n\n    @sa @ref number_unsigned_t -- type for number values (unsigned integer)\n\n    @since version 1.0.0\n    */\n    using number_integer_t = NumberIntegerType;\n\n    /*!\n    @brief a type for a number (unsigned)\n\n    [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows:\n    > The representation of numbers is similar to that used in most\n    > programming languages. A number is represented in base 10 using decimal\n    > digits. It contains an integer component that may be prefixed with an\n    > optional minus sign, which may be followed by a fraction part and/or an\n    > exponent part. Leading zeros are not allowed. (...) Numeric values that\n    > cannot be represented in the grammar below (such as Infinity and NaN)\n    > are not permitted.\n\n    This description includes both integer and floating-point numbers.\n    However, C++ allows more precise storage if it is known whether the number\n    is a signed integer, an unsigned integer or a floating-point number.\n    Therefore, three different types, @ref number_integer_t, @ref\n    number_unsigned_t and @ref number_float_t are used.\n\n    To store unsigned integer numbers in C++, a type is defined by the\n    template parameter @a NumberUnsignedType which chooses the type to use.\n\n    #### Default type\n\n    With the default values for @a NumberUnsignedType (`uint64_t`), the\n    default value for @a number_unsigned_t is:\n\n    @code {.cpp}\n    uint64_t\n    @endcode\n\n    #### Default behavior\n\n    - The restrictions about leading zeros is not enforced in C++. Instead,\n      leading zeros in integer literals lead to an interpretation as octal\n      number. Internally, the value will be stored as decimal number. For\n      instance, the C++ integer literal `010` will be serialized to `8`.\n      During deserialization, leading zeros yield an error.\n    - Not-a-number (NaN) values will be serialized to `null`.\n\n    #### Limits\n\n    [RFC 7159](http://rfc7159.net/rfc7159) specifies:\n    > An implementation may set limits on the range and precision of numbers.\n\n    When the default type is used, the maximal integer number that can be\n    stored is `18446744073709551615` (UINT64_MAX) and the minimal integer\n    number that can be stored is `0`. Integer numbers that are out of range\n    will yield over/underflow when used in a constructor. During\n    deserialization, too large or small integer numbers will be automatically\n    be stored as @ref number_integer_t or @ref number_float_t.\n\n    [RFC 7159](http://rfc7159.net/rfc7159) further states:\n    > Note that when such software is used, numbers that are integers and are\n    > in the range \\f$[-2^{53}+1, 2^{53}-1]\\f$ are interoperable in the sense\n    > that implementations will agree exactly on their numeric values.\n\n    As this range is a subrange (when considered in conjunction with the\n    number_integer_t type) of the exactly supported range [0, UINT64_MAX],\n    this class's integer type is interoperable.\n\n    #### Storage\n\n    Integer number values are stored directly inside a @ref basic_json type.\n\n    @sa @ref number_float_t -- type for number values (floating-point)\n    @sa @ref number_integer_t -- type for number values (integer)\n\n    @since version 2.0.0\n    */\n    using number_unsigned_t = NumberUnsignedType;\n\n    /*!\n    @brief a type for a number (floating-point)\n\n    [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows:\n    > The representation of numbers is similar to that used in most\n    > programming languages. A number is represented in base 10 using decimal\n    > digits. It contains an integer component that may be prefixed with an\n    > optional minus sign, which may be followed by a fraction part and/or an\n    > exponent part. Leading zeros are not allowed. (...) Numeric values that\n    > cannot be represented in the grammar below (such as Infinity and NaN)\n    > are not permitted.\n\n    This description includes both integer and floating-point numbers.\n    However, C++ allows more precise storage if it is known whether the number\n    is a signed integer, an unsigned integer or a floating-point number.\n    Therefore, three different types, @ref number_integer_t, @ref\n    number_unsigned_t and @ref number_float_t are used.\n\n    To store floating-point numbers in C++, a type is defined by the template\n    parameter @a NumberFloatType which chooses the type to use.\n\n    #### Default type\n\n    With the default values for @a NumberFloatType (`double`), the default\n    value for @a number_float_t is:\n\n    @code {.cpp}\n    double\n    @endcode\n\n    #### Default behavior\n\n    - The restrictions about leading zeros is not enforced in C++. Instead,\n      leading zeros in floating-point literals will be ignored. Internally,\n      the value will be stored as decimal number. For instance, the C++\n      floating-point literal `01.2` will be serialized to `1.2`. During\n      deserialization, leading zeros yield an error.\n    - Not-a-number (NaN) values will be serialized to `null`.\n\n    #### Limits\n\n    [RFC 7159](http://rfc7159.net/rfc7159) states:\n    > This specification allows implementations to set limits on the range and\n    > precision of numbers accepted. Since software that implements IEEE\n    > 754-2008 binary64 (double precision) numbers is generally available and\n    > widely used, good interoperability can be achieved by implementations\n    > that expect no more precision or range than these provide, in the sense\n    > that implementations will approximate JSON numbers within the expected\n    > precision.\n\n    This implementation does exactly follow this approach, as it uses double\n    precision floating-point numbers. Note values smaller than\n    `-1.79769313486232e+308` and values greater than `1.79769313486232e+308`\n    will be stored as NaN internally and be serialized to `null`.\n\n    #### Storage\n\n    Floating-point number values are stored directly inside a @ref basic_json\n    type.\n\n    @sa @ref number_integer_t -- type for number values (integer)\n\n    @sa @ref number_unsigned_t -- type for number values (unsigned integer)\n\n    @since version 1.0.0\n    */\n    using number_float_t = NumberFloatType;\n\n    /// @}\n\n  private:\n\n    /// helper for exception-safe object creation\n    template<typename T, typename... Args>\n    static T* create(Args&& ... args)\n    {\n        AllocatorType<T> alloc;\n        using AllocatorTraits = std::allocator_traits<AllocatorType<T>>;\n\n        auto deleter = [&](T * object)\n        {\n            AllocatorTraits::deallocate(alloc, object, 1);\n        };\n        std::unique_ptr<T, decltype(deleter)> object(AllocatorTraits::allocate(alloc, 1), deleter);\n        AllocatorTraits::construct(alloc, object.get(), std::forward<Args>(args)...);\n        assert(object != nullptr);\n        return object.release();\n    }\n\n    ////////////////////////\n    // JSON value storage //\n    ////////////////////////\n\n    /*!\n    @brief a JSON value\n\n    The actual storage for a JSON value of the @ref basic_json class. This\n    union combines the different storage types for the JSON value types\n    defined in @ref value_t.\n\n    JSON type | value_t type    | used type\n    --------- | --------------- | ------------------------\n    object    | object          | pointer to @ref object_t\n    array     | array           | pointer to @ref array_t\n    string    | string          | pointer to @ref string_t\n    boolean   | boolean         | @ref boolean_t\n    number    | number_integer  | @ref number_integer_t\n    number    | number_unsigned | @ref number_unsigned_t\n    number    | number_float    | @ref number_float_t\n    null      | null            | *no value is stored*\n\n    @note Variable-length types (objects, arrays, and strings) are stored as\n    pointers. The size of the union should not exceed 64 bits if the default\n    value types are used.\n\n    @since version 1.0.0\n    */\n    union json_value\n    {\n        /// object (stored with pointer to save storage)\n        object_t* object;\n        /// array (stored with pointer to save storage)\n        array_t* array;\n        /// string (stored with pointer to save storage)\n        string_t* string;\n        /// boolean\n        boolean_t boolean;\n        /// number (integer)\n        number_integer_t number_integer;\n        /// number (unsigned integer)\n        number_unsigned_t number_unsigned;\n        /// number (floating-point)\n        number_float_t number_float;\n\n        /// default constructor (for null values)\n        json_value() = default;\n        /// constructor for booleans\n        json_value(boolean_t v) noexcept : boolean(v) {}\n        /// constructor for numbers (integer)\n        json_value(number_integer_t v) noexcept : number_integer(v) {}\n        /// constructor for numbers (unsigned)\n        json_value(number_unsigned_t v) noexcept : number_unsigned(v) {}\n        /// constructor for numbers (floating-point)\n        json_value(number_float_t v) noexcept : number_float(v) {}\n        /// constructor for empty values of a given type\n        json_value(value_t t)\n        {\n            switch (t)\n            {\n                case value_t::object:\n                {\n                    object = create<object_t>();\n                    break;\n                }\n\n                case value_t::array:\n                {\n                    array = create<array_t>();\n                    break;\n                }\n\n                case value_t::string:\n                {\n                    string = create<string_t>(\"\");\n                    break;\n                }\n\n                case value_t::boolean:\n                {\n                    boolean = boolean_t(false);\n                    break;\n                }\n\n                case value_t::number_integer:\n                {\n                    number_integer = number_integer_t(0);\n                    break;\n                }\n\n                case value_t::number_unsigned:\n                {\n                    number_unsigned = number_unsigned_t(0);\n                    break;\n                }\n\n                case value_t::number_float:\n                {\n                    number_float = number_float_t(0.0);\n                    break;\n                }\n\n                case value_t::null:\n                {\n                    object = nullptr;  // silence warning, see #821\n                    break;\n                }\n\n                default:\n                {\n                    object = nullptr;  // silence warning, see #821\n                    if (JSON_UNLIKELY(t == value_t::null))\n                    {\n                        JSON_THROW(other_error::create(500, \"961c151d2e87f2686a955a9be24d316f1362bf21 3.5.0\")); // LCOV_EXCL_LINE\n                    }\n                    break;\n                }\n            }\n        }\n\n        /// constructor for strings\n        json_value(const string_t& value)\n        {\n            string = create<string_t>(value);\n        }\n\n        /// constructor for rvalue strings\n        json_value(string_t&& value)\n        {\n            string = create<string_t>(std::move(value));\n        }\n\n        /// constructor for objects\n        json_value(const object_t& value)\n        {\n            object = create<object_t>(value);\n        }\n\n        /// constructor for rvalue objects\n        json_value(object_t&& value)\n        {\n            object = create<object_t>(std::move(value));\n        }\n\n        /// constructor for arrays\n        json_value(const array_t& value)\n        {\n            array = create<array_t>(value);\n        }\n\n        /// constructor for rvalue arrays\n        json_value(array_t&& value)\n        {\n            array = create<array_t>(std::move(value));\n        }\n\n        void destroy(value_t t) noexcept\n        {\n            switch (t)\n            {\n                case value_t::object:\n                {\n                    AllocatorType<object_t> alloc;\n                    std::allocator_traits<decltype(alloc)>::destroy(alloc, object);\n                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, object, 1);\n                    break;\n                }\n\n                case value_t::array:\n                {\n                    AllocatorType<array_t> alloc;\n                    std::allocator_traits<decltype(alloc)>::destroy(alloc, array);\n                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, array, 1);\n                    break;\n                }\n\n                case value_t::string:\n                {\n                    AllocatorType<string_t> alloc;\n                    std::allocator_traits<decltype(alloc)>::destroy(alloc, string);\n                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, string, 1);\n                    break;\n                }\n\n                default:\n                {\n                    break;\n                }\n            }\n        }\n    };\n\n    /*!\n    @brief checks the class invariants\n\n    This function asserts the class invariants. It needs to be called at the\n    end of every constructor to make sure that created objects respect the\n    invariant. Furthermore, it has to be called each time the type of a JSON\n    value is changed, because the invariant expresses a relationship between\n    @a m_type and @a m_value.\n    */\n    void assert_invariant() const noexcept\n    {\n        assert(m_type != value_t::object or m_value.object != nullptr);\n        assert(m_type != value_t::array or m_value.array != nullptr);\n        assert(m_type != value_t::string or m_value.string != nullptr);\n    }\n\n  public:\n    //////////////////////////\n    // JSON parser callback //\n    //////////////////////////\n\n    /*!\n    @brief parser event types\n\n    The parser callback distinguishes the following events:\n    - `object_start`: the parser read `{` and started to process a JSON object\n    - `key`: the parser read a key of a value in an object\n    - `object_end`: the parser read `}` and finished processing a JSON object\n    - `array_start`: the parser read `[` and started to process a JSON array\n    - `array_end`: the parser read `]` and finished processing a JSON array\n    - `value`: the parser finished reading a JSON value\n\n    @image html callback_events.png \"Example when certain parse events are triggered\"\n\n    @sa @ref parser_callback_t for more information and examples\n    */\n    using parse_event_t = typename parser::parse_event_t;\n\n    /*!\n    @brief per-element parser callback type\n\n    With a parser callback function, the result of parsing a JSON text can be\n    influenced. When passed to @ref parse, it is called on certain events\n    (passed as @ref parse_event_t via parameter @a event) with a set recursion\n    depth @a depth and context JSON value @a parsed. The return value of the\n    callback function is a boolean indicating whether the element that emitted\n    the callback shall be kept or not.\n\n    We distinguish six scenarios (determined by the event type) in which the\n    callback function can be called. The following table describes the values\n    of the parameters @a depth, @a event, and @a parsed.\n\n    parameter @a event | description | parameter @a depth | parameter @a parsed\n    ------------------ | ----------- | ------------------ | -------------------\n    parse_event_t::object_start | the parser read `{` and started to process a JSON object | depth of the parent of the JSON object | a JSON value with type discarded\n    parse_event_t::key | the parser read a key of a value in an object | depth of the currently parsed JSON object | a JSON string containing the key\n    parse_event_t::object_end | the parser read `}` and finished processing a JSON object | depth of the parent of the JSON object | the parsed JSON object\n    parse_event_t::array_start | the parser read `[` and started to process a JSON array | depth of the parent of the JSON array | a JSON value with type discarded\n    parse_event_t::array_end | the parser read `]` and finished processing a JSON array | depth of the parent of the JSON array | the parsed JSON array\n    parse_event_t::value | the parser finished reading a JSON value | depth of the value | the parsed JSON value\n\n    @image html callback_events.png \"Example when certain parse events are triggered\"\n\n    Discarding a value (i.e., returning `false`) has different effects\n    depending on the context in which function was called:\n\n    - Discarded values in structured types are skipped. That is, the parser\n      will behave as if the discarded value was never read.\n    - In case a value outside a structured type is skipped, it is replaced\n      with `null`. This case happens if the top-level element is skipped.\n\n    @param[in] depth  the depth of the recursion during parsing\n\n    @param[in] event  an event of type parse_event_t indicating the context in\n    the callback function has been called\n\n    @param[in,out] parsed  the current intermediate parse result; note that\n    writing to this value has no effect for parse_event_t::key events\n\n    @return Whether the JSON value which called the function during parsing\n    should be kept (`true`) or not (`false`). In the latter case, it is either\n    skipped completely or replaced by an empty discarded object.\n\n    @sa @ref parse for examples\n\n    @since version 1.0.0\n    */\n    using parser_callback_t = typename parser::parser_callback_t;\n\n    //////////////////\n    // constructors //\n    //////////////////\n\n    /// @name constructors and destructors\n    /// Constructors of class @ref basic_json, copy/move constructor, copy\n    /// assignment, static functions creating objects, and the destructor.\n    /// @{\n\n    /*!\n    @brief create an empty value with a given type\n\n    Create an empty JSON value with a given type. The value will be default\n    initialized with an empty value which depends on the type:\n\n    Value type  | initial value\n    ----------- | -------------\n    null        | `null`\n    boolean     | `false`\n    string      | `\"\"`\n    number      | `0`\n    object      | `{}`\n    array       | `[]`\n\n    @param[in] v  the type of the value to create\n\n    @complexity Constant.\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes to any JSON value.\n\n    @liveexample{The following code shows the constructor for different @ref\n    value_t values,basic_json__value_t}\n\n    @sa @ref clear() -- restores the postcondition of this constructor\n\n    @since version 1.0.0\n    */\n    basic_json(const value_t v)\n        : m_type(v), m_value(v)\n    {\n        assert_invariant();\n    }\n\n    /*!\n    @brief create a null object\n\n    Create a `null` JSON value. It either takes a null pointer as parameter\n    (explicitly creating `null`) or no parameter (implicitly creating `null`).\n    The passed null pointer itself is not read -- it is only used to choose\n    the right constructor.\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this constructor never throws\n    exceptions.\n\n    @liveexample{The following code shows the constructor with and without a\n    null pointer parameter.,basic_json__nullptr_t}\n\n    @since version 1.0.0\n    */\n    basic_json(std::nullptr_t = nullptr) noexcept\n        : basic_json(value_t::null)\n    {\n        assert_invariant();\n    }\n\n    /*!\n    @brief create a JSON value\n\n    This is a \"catch all\" constructor for all compatible JSON types; that is,\n    types for which a `to_json()` method exists. The constructor forwards the\n    parameter @a val to that method (to `json_serializer<U>::to_json` method\n    with `U = uncvref_t<CompatibleType>`, to be exact).\n\n    Template type @a CompatibleType includes, but is not limited to, the\n    following types:\n    - **arrays**: @ref array_t and all kinds of compatible containers such as\n      `std::vector`, `std::deque`, `std::list`, `std::forward_list`,\n      `std::array`, `std::valarray`, `std::set`, `std::unordered_set`,\n      `std::multiset`, and `std::unordered_multiset` with a `value_type` from\n      which a @ref basic_json value can be constructed.\n    - **objects**: @ref object_t and all kinds of compatible associative\n      containers such as `std::map`, `std::unordered_map`, `std::multimap`,\n      and `std::unordered_multimap` with a `key_type` compatible to\n      @ref string_t and a `value_type` from which a @ref basic_json value can\n      be constructed.\n    - **strings**: @ref string_t, string literals, and all compatible string\n      containers can be used.\n    - **numbers**: @ref number_integer_t, @ref number_unsigned_t,\n      @ref number_float_t, and all convertible number types such as `int`,\n      `size_t`, `int64_t`, `float` or `double` can be used.\n    - **boolean**: @ref boolean_t / `bool` can be used.\n\n    See the examples below.\n\n    @tparam CompatibleType a type such that:\n    - @a CompatibleType is not derived from `std::istream`,\n    - @a CompatibleType is not @ref basic_json (to avoid hijacking copy/move\n         constructors),\n    - @a CompatibleType is not a different @ref basic_json type (i.e. with different template arguments)\n    - @a CompatibleType is not a @ref basic_json nested type (e.g.,\n         @ref json_pointer, @ref iterator, etc ...)\n    - @ref @ref json_serializer<U> has a\n         `to_json(basic_json_t&, CompatibleType&&)` method\n\n    @tparam U = `uncvref_t<CompatibleType>`\n\n    @param[in] val the value to be forwarded to the respective constructor\n\n    @complexity Usually linear in the size of the passed @a val, also\n                depending on the implementation of the called `to_json()`\n                method.\n\n    @exceptionsafety Depends on the called constructor. For types directly\n    supported by the library (i.e., all types for which no `to_json()` function\n    was provided), strong guarantee holds: if an exception is thrown, there are\n    no changes to any JSON value.\n\n    @liveexample{The following code shows the constructor with several\n    compatible types.,basic_json__CompatibleType}\n\n    @since version 2.1.0\n    */\n    template <typename CompatibleType,\n              typename U = detail::uncvref_t<CompatibleType>,\n              detail::enable_if_t<\n                  not detail::is_basic_json<U>::value and detail::is_compatible_type<basic_json_t, U>::value, int> = 0>\n    basic_json(CompatibleType && val) noexcept(noexcept(\n                JSONSerializer<U>::to_json(std::declval<basic_json_t&>(),\n                                           std::forward<CompatibleType>(val))))\n    {\n        JSONSerializer<U>::to_json(*this, std::forward<CompatibleType>(val));\n        assert_invariant();\n    }\n\n    /*!\n    @brief create a JSON value from an existing one\n\n    This is a constructor for existing @ref basic_json types.\n    It does not hijack copy/move constructors, since the parameter has different\n    template arguments than the current ones.\n\n    The constructor tries to convert the internal @ref m_value of the parameter.\n\n    @tparam BasicJsonType a type such that:\n    - @a BasicJsonType is a @ref basic_json type.\n    - @a BasicJsonType has different template arguments than @ref basic_json_t.\n\n    @param[in] val the @ref basic_json value to be converted.\n\n    @complexity Usually linear in the size of the passed @a val, also\n                depending on the implementation of the called `to_json()`\n                method.\n\n    @exceptionsafety Depends on the called constructor. For types directly\n    supported by the library (i.e., all types for which no `to_json()` function\n    was provided), strong guarantee holds: if an exception is thrown, there are\n    no changes to any JSON value.\n\n    @since version 3.2.0\n    */\n    template <typename BasicJsonType,\n              detail::enable_if_t<\n                  detail::is_basic_json<BasicJsonType>::value and not std::is_same<basic_json, BasicJsonType>::value, int> = 0>\n    basic_json(const BasicJsonType& val)\n    {\n        using other_boolean_t = typename BasicJsonType::boolean_t;\n        using other_number_float_t = typename BasicJsonType::number_float_t;\n        using other_number_integer_t = typename BasicJsonType::number_integer_t;\n        using other_number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n        using other_string_t = typename BasicJsonType::string_t;\n        using other_object_t = typename BasicJsonType::object_t;\n        using other_array_t = typename BasicJsonType::array_t;\n\n        switch (val.type())\n        {\n            case value_t::boolean:\n                JSONSerializer<other_boolean_t>::to_json(*this, val.template get<other_boolean_t>());\n                break;\n            case value_t::number_float:\n                JSONSerializer<other_number_float_t>::to_json(*this, val.template get<other_number_float_t>());\n                break;\n            case value_t::number_integer:\n                JSONSerializer<other_number_integer_t>::to_json(*this, val.template get<other_number_integer_t>());\n                break;\n            case value_t::number_unsigned:\n                JSONSerializer<other_number_unsigned_t>::to_json(*this, val.template get<other_number_unsigned_t>());\n                break;\n            case value_t::string:\n                JSONSerializer<other_string_t>::to_json(*this, val.template get_ref<const other_string_t&>());\n                break;\n            case value_t::object:\n                JSONSerializer<other_object_t>::to_json(*this, val.template get_ref<const other_object_t&>());\n                break;\n            case value_t::array:\n                JSONSerializer<other_array_t>::to_json(*this, val.template get_ref<const other_array_t&>());\n                break;\n            case value_t::null:\n                *this = nullptr;\n                break;\n            case value_t::discarded:\n                m_type = value_t::discarded;\n                break;\n        }\n        assert_invariant();\n    }\n\n    /*!\n    @brief create a container (array or object) from an initializer list\n\n    Creates a JSON value of type array or object from the passed initializer\n    list @a init. In case @a type_deduction is `true` (default), the type of\n    the JSON value to be created is deducted from the initializer list @a init\n    according to the following rules:\n\n    1. If the list is empty, an empty JSON object value `{}` is created.\n    2. If the list consists of pairs whose first element is a string, a JSON\n       object value is created where the first elements of the pairs are\n       treated as keys and the second elements are as values.\n    3. In all other cases, an array is created.\n\n    The rules aim to create the best fit between a C++ initializer list and\n    JSON values. The rationale is as follows:\n\n    1. The empty initializer list is written as `{}` which is exactly an empty\n       JSON object.\n    2. C++ has no way of describing mapped types other than to list a list of\n       pairs. As JSON requires that keys must be of type string, rule 2 is the\n       weakest constraint one can pose on initializer lists to interpret them\n       as an object.\n    3. In all other cases, the initializer list could not be interpreted as\n       JSON object type, so interpreting it as JSON array type is safe.\n\n    With the rules described above, the following JSON values cannot be\n    expressed by an initializer list:\n\n    - the empty array (`[]`): use @ref array(initializer_list_t)\n      with an empty initializer list in this case\n    - arrays whose elements satisfy rule 2: use @ref\n      array(initializer_list_t) with the same initializer list\n      in this case\n\n    @note When used without parentheses around an empty initializer list, @ref\n    basic_json() is called instead of this function, yielding the JSON null\n    value.\n\n    @param[in] init  initializer list with JSON values\n\n    @param[in] type_deduction internal parameter; when set to `true`, the type\n    of the JSON value is deducted from the initializer list @a init; when set\n    to `false`, the type provided via @a manual_type is forced. This mode is\n    used by the functions @ref array(initializer_list_t) and\n    @ref object(initializer_list_t).\n\n    @param[in] manual_type internal parameter; when @a type_deduction is set\n    to `false`, the created JSON value will use the provided type (only @ref\n    value_t::array and @ref value_t::object are valid); when @a type_deduction\n    is set to `true`, this parameter has no effect\n\n    @throw type_error.301 if @a type_deduction is `false`, @a manual_type is\n    `value_t::object`, but @a init contains an element which is not a pair\n    whose first element is a string. In this case, the constructor could not\n    create an object. If @a type_deduction would have be `true`, an array\n    would have been created. See @ref object(initializer_list_t)\n    for an example.\n\n    @complexity Linear in the size of the initializer list @a init.\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes to any JSON value.\n\n    @liveexample{The example below shows how JSON values are created from\n    initializer lists.,basic_json__list_init_t}\n\n    @sa @ref array(initializer_list_t) -- create a JSON array\n    value from an initializer list\n    @sa @ref object(initializer_list_t) -- create a JSON object\n    value from an initializer list\n\n    @since version 1.0.0\n    */\n    basic_json(initializer_list_t init,\n               bool type_deduction = true,\n               value_t manual_type = value_t::array)\n    {\n        // check if each element is an array with two elements whose first\n        // element is a string\n        bool is_an_object = std::all_of(init.begin(), init.end(),\n                                        [](const detail::json_ref<basic_json>& element_ref)\n        {\n            return (element_ref->is_array() and element_ref->size() == 2 and (*element_ref)[0].is_string());\n        });\n\n        // adjust type if type deduction is not wanted\n        if (not type_deduction)\n        {\n            // if array is wanted, do not create an object though possible\n            if (manual_type == value_t::array)\n            {\n                is_an_object = false;\n            }\n\n            // if object is wanted but impossible, throw an exception\n            if (JSON_UNLIKELY(manual_type == value_t::object and not is_an_object))\n            {\n                JSON_THROW(type_error::create(301, \"cannot create object from initializer list\"));\n            }\n        }\n\n        if (is_an_object)\n        {\n            // the initializer list is a list of pairs -> create object\n            m_type = value_t::object;\n            m_value = value_t::object;\n\n            std::for_each(init.begin(), init.end(), [this](const detail::json_ref<basic_json>& element_ref)\n            {\n                auto element = element_ref.moved_or_copied();\n                m_value.object->emplace(\n                    std::move(*((*element.m_value.array)[0].m_value.string)),\n                    std::move((*element.m_value.array)[1]));\n            });\n        }\n        else\n        {\n            // the initializer list describes an array -> create array\n            m_type = value_t::array;\n            m_value.array = create<array_t>(init.begin(), init.end());\n        }\n\n        assert_invariant();\n    }\n\n    /*!\n    @brief explicitly create an array from an initializer list\n\n    Creates a JSON array value from a given initializer list. That is, given a\n    list of values `a, b, c`, creates the JSON value `[a, b, c]`. If the\n    initializer list is empty, the empty array `[]` is created.\n\n    @note This function is only needed to express two edge cases that cannot\n    be realized with the initializer list constructor (@ref\n    basic_json(initializer_list_t, bool, value_t)). These cases\n    are:\n    1. creating an array whose elements are all pairs whose first element is a\n    string -- in this case, the initializer list constructor would create an\n    object, taking the first elements as keys\n    2. creating an empty array -- passing the empty initializer list to the\n    initializer list constructor yields an empty object\n\n    @param[in] init  initializer list with JSON values to create an array from\n    (optional)\n\n    @return JSON array value\n\n    @complexity Linear in the size of @a init.\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes to any JSON value.\n\n    @liveexample{The following code shows an example for the `array`\n    function.,array}\n\n    @sa @ref basic_json(initializer_list_t, bool, value_t) --\n    create a JSON value from an initializer list\n    @sa @ref object(initializer_list_t) -- create a JSON object\n    value from an initializer list\n\n    @since version 1.0.0\n    */\n    static basic_json array(initializer_list_t init = {})\n    {\n        return basic_json(init, false, value_t::array);\n    }\n\n    /*!\n    @brief explicitly create an object from an initializer list\n\n    Creates a JSON object value from a given initializer list. The initializer\n    lists elements must be pairs, and their first elements must be strings. If\n    the initializer list is empty, the empty object `{}` is created.\n\n    @note This function is only added for symmetry reasons. In contrast to the\n    related function @ref array(initializer_list_t), there are\n    no cases which can only be expressed by this function. That is, any\n    initializer list @a init can also be passed to the initializer list\n    constructor @ref basic_json(initializer_list_t, bool, value_t).\n\n    @param[in] init  initializer list to create an object from (optional)\n\n    @return JSON object value\n\n    @throw type_error.301 if @a init is not a list of pairs whose first\n    elements are strings. In this case, no object can be created. When such a\n    value is passed to @ref basic_json(initializer_list_t, bool, value_t),\n    an array would have been created from the passed initializer list @a init.\n    See example below.\n\n    @complexity Linear in the size of @a init.\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes to any JSON value.\n\n    @liveexample{The following code shows an example for the `object`\n    function.,object}\n\n    @sa @ref basic_json(initializer_list_t, bool, value_t) --\n    create a JSON value from an initializer list\n    @sa @ref array(initializer_list_t) -- create a JSON array\n    value from an initializer list\n\n    @since version 1.0.0\n    */\n    static basic_json object(initializer_list_t init = {})\n    {\n        return basic_json(init, false, value_t::object);\n    }\n\n    /*!\n    @brief construct an array with count copies of given value\n\n    Constructs a JSON array value by creating @a cnt copies of a passed value.\n    In case @a cnt is `0`, an empty array is created.\n\n    @param[in] cnt  the number of JSON copies of @a val to create\n    @param[in] val  the JSON value to copy\n\n    @post `std::distance(begin(),end()) == cnt` holds.\n\n    @complexity Linear in @a cnt.\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes to any JSON value.\n\n    @liveexample{The following code shows examples for the @ref\n    basic_json(size_type\\, const basic_json&)\n    constructor.,basic_json__size_type_basic_json}\n\n    @since version 1.0.0\n    */\n    basic_json(size_type cnt, const basic_json& val)\n        : m_type(value_t::array)\n    {\n        m_value.array = create<array_t>(cnt, val);\n        assert_invariant();\n    }\n\n    /*!\n    @brief construct a JSON container given an iterator range\n\n    Constructs the JSON value with the contents of the range `[first, last)`.\n    The semantics depends on the different types a JSON value can have:\n    - In case of a null type, invalid_iterator.206 is thrown.\n    - In case of other primitive types (number, boolean, or string), @a first\n      must be `begin()` and @a last must be `end()`. In this case, the value is\n      copied. Otherwise, invalid_iterator.204 is thrown.\n    - In case of structured types (array, object), the constructor behaves as\n      similar versions for `std::vector` or `std::map`; that is, a JSON array\n      or object is constructed from the values in the range.\n\n    @tparam InputIT an input iterator type (@ref iterator or @ref\n    const_iterator)\n\n    @param[in] first begin of the range to copy from (included)\n    @param[in] last end of the range to copy from (excluded)\n\n    @pre Iterators @a first and @a last must be initialized. **This\n         precondition is enforced with an assertion (see warning).** If\n         assertions are switched off, a violation of this precondition yields\n         undefined behavior.\n\n    @pre Range `[first, last)` is valid. Usually, this precondition cannot be\n         checked efficiently. Only certain edge cases are detected; see the\n         description of the exceptions below. A violation of this precondition\n         yields undefined behavior.\n\n    @warning A precondition is enforced with a runtime assertion that will\n             result in calling `std::abort` if this precondition is not met.\n             Assertions can be disabled by defining `NDEBUG` at compile time.\n             See https://en.cppreference.com/w/cpp/error/assert for more\n             information.\n\n    @throw invalid_iterator.201 if iterators @a first and @a last are not\n    compatible (i.e., do not belong to the same JSON value). In this case,\n    the range `[first, last)` is undefined.\n    @throw invalid_iterator.204 if iterators @a first and @a last belong to a\n    primitive type (number, boolean, or string), but @a first does not point\n    to the first element any more. In this case, the range `[first, last)` is\n    undefined. See example code below.\n    @throw invalid_iterator.206 if iterators @a first and @a last belong to a\n    null value. In this case, the range `[first, last)` is undefined.\n\n    @complexity Linear in distance between @a first and @a last.\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes to any JSON value.\n\n    @liveexample{The example below shows several ways to create JSON values by\n    specifying a subrange with iterators.,basic_json__InputIt_InputIt}\n\n    @since version 1.0.0\n    */\n    template<class InputIT, typename std::enable_if<\n                 std::is_same<InputIT, typename basic_json_t::iterator>::value or\n                 std::is_same<InputIT, typename basic_json_t::const_iterator>::value, int>::type = 0>\n    basic_json(InputIT first, InputIT last)\n    {\n        assert(first.m_object != nullptr);\n        assert(last.m_object != nullptr);\n\n        // make sure iterator fits the current value\n        if (JSON_UNLIKELY(first.m_object != last.m_object))\n        {\n            JSON_THROW(invalid_iterator::create(201, \"iterators are not compatible\"));\n        }\n\n        // copy type from first iterator\n        m_type = first.m_object->m_type;\n\n        // check if iterator range is complete for primitive values\n        switch (m_type)\n        {\n            case value_t::boolean:\n            case value_t::number_float:\n            case value_t::number_integer:\n            case value_t::number_unsigned:\n            case value_t::string:\n            {\n                if (JSON_UNLIKELY(not first.m_it.primitive_iterator.is_begin()\n                                  or not last.m_it.primitive_iterator.is_end()))\n                {\n                    JSON_THROW(invalid_iterator::create(204, \"iterators out of range\"));\n                }\n                break;\n            }\n\n            default:\n                break;\n        }\n\n        switch (m_type)\n        {\n            case value_t::number_integer:\n            {\n                m_value.number_integer = first.m_object->m_value.number_integer;\n                break;\n            }\n\n            case value_t::number_unsigned:\n            {\n                m_value.number_unsigned = first.m_object->m_value.number_unsigned;\n                break;\n            }\n\n            case value_t::number_float:\n            {\n                m_value.number_float = first.m_object->m_value.number_float;\n                break;\n            }\n\n            case value_t::boolean:\n            {\n                m_value.boolean = first.m_object->m_value.boolean;\n                break;\n            }\n\n            case value_t::string:\n            {\n                m_value = *first.m_object->m_value.string;\n                break;\n            }\n\n            case value_t::object:\n            {\n                m_value.object = create<object_t>(first.m_it.object_iterator,\n                                                  last.m_it.object_iterator);\n                break;\n            }\n\n            case value_t::array:\n            {\n                m_value.array = create<array_t>(first.m_it.array_iterator,\n                                                last.m_it.array_iterator);\n                break;\n            }\n\n            default:\n                JSON_THROW(invalid_iterator::create(206, \"cannot construct with iterators from \" +\n                                                    std::string(first.m_object->type_name())));\n        }\n\n        assert_invariant();\n    }\n\n\n    ///////////////////////////////////////\n    // other constructors and destructor //\n    ///////////////////////////////////////\n\n    /// @private\n    basic_json(const detail::json_ref<basic_json>& ref)\n        : basic_json(ref.moved_or_copied())\n    {}\n\n    /*!\n    @brief copy constructor\n\n    Creates a copy of a given JSON value.\n\n    @param[in] other  the JSON value to copy\n\n    @post `*this == other`\n\n    @complexity Linear in the size of @a other.\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes to any JSON value.\n\n    @requirement This function helps `basic_json` satisfying the\n    [Container](https://en.cppreference.com/w/cpp/named_req/Container)\n    requirements:\n    - The complexity is linear.\n    - As postcondition, it holds: `other == basic_json(other)`.\n\n    @liveexample{The following code shows an example for the copy\n    constructor.,basic_json__basic_json}\n\n    @since version 1.0.0\n    */\n    basic_json(const basic_json& other)\n        : m_type(other.m_type)\n    {\n        // check of passed value is valid\n        other.assert_invariant();\n\n        switch (m_type)\n        {\n            case value_t::object:\n            {\n                m_value = *other.m_value.object;\n                break;\n            }\n\n            case value_t::array:\n            {\n                m_value = *other.m_value.array;\n                break;\n            }\n\n            case value_t::string:\n            {\n                m_value = *other.m_value.string;\n                break;\n            }\n\n            case value_t::boolean:\n            {\n                m_value = other.m_value.boolean;\n                break;\n            }\n\n            case value_t::number_integer:\n            {\n                m_value = other.m_value.number_integer;\n                break;\n            }\n\n            case value_t::number_unsigned:\n            {\n                m_value = other.m_value.number_unsigned;\n                break;\n            }\n\n            case value_t::number_float:\n            {\n                m_value = other.m_value.number_float;\n                break;\n            }\n\n            default:\n                break;\n        }\n\n        assert_invariant();\n    }\n\n    /*!\n    @brief move constructor\n\n    Move constructor. Constructs a JSON value with the contents of the given\n    value @a other using move semantics. It \"steals\" the resources from @a\n    other and leaves it as JSON null value.\n\n    @param[in,out] other  value to move to this object\n\n    @post `*this` has the same value as @a other before the call.\n    @post @a other is a JSON null value.\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this constructor never throws\n    exceptions.\n\n    @requirement This function helps `basic_json` satisfying the\n    [MoveConstructible](https://en.cppreference.com/w/cpp/named_req/MoveConstructible)\n    requirements.\n\n    @liveexample{The code below shows the move constructor explicitly called\n    via std::move.,basic_json__moveconstructor}\n\n    @since version 1.0.0\n    */\n    basic_json(basic_json&& other) noexcept\n        : m_type(std::move(other.m_type)),\n          m_value(std::move(other.m_value))\n    {\n        // check that passed value is valid\n        other.assert_invariant();\n\n        // invalidate payload\n        other.m_type = value_t::null;\n        other.m_value = {};\n\n        assert_invariant();\n    }\n\n    /*!\n    @brief copy assignment\n\n    Copy assignment operator. Copies a JSON value via the \"copy and swap\"\n    strategy: It is expressed in terms of the copy constructor, destructor,\n    and the `swap()` member function.\n\n    @param[in] other  value to copy from\n\n    @complexity Linear.\n\n    @requirement This function helps `basic_json` satisfying the\n    [Container](https://en.cppreference.com/w/cpp/named_req/Container)\n    requirements:\n    - The complexity is linear.\n\n    @liveexample{The code below shows and example for the copy assignment. It\n    creates a copy of value `a` which is then swapped with `b`. Finally\\, the\n    copy of `a` (which is the null value after the swap) is\n    destroyed.,basic_json__copyassignment}\n\n    @since version 1.0.0\n    */\n    basic_json& operator=(basic_json other) noexcept (\n        std::is_nothrow_move_constructible<value_t>::value and\n        std::is_nothrow_move_assignable<value_t>::value and\n        std::is_nothrow_move_constructible<json_value>::value and\n        std::is_nothrow_move_assignable<json_value>::value\n    )\n    {\n        // check that passed value is valid\n        other.assert_invariant();\n\n        using std::swap;\n        swap(m_type, other.m_type);\n        swap(m_value, other.m_value);\n\n        assert_invariant();\n        return *this;\n    }\n\n    /*!\n    @brief destructor\n\n    Destroys the JSON value and frees all allocated memory.\n\n    @complexity Linear.\n\n    @requirement This function helps `basic_json` satisfying the\n    [Container](https://en.cppreference.com/w/cpp/named_req/Container)\n    requirements:\n    - The complexity is linear.\n    - All stored elements are destroyed and all memory is freed.\n\n    @since version 1.0.0\n    */\n    ~basic_json() noexcept\n    {\n        assert_invariant();\n        m_value.destroy(m_type);\n    }\n\n    /// @}\n\n  public:\n    ///////////////////////\n    // object inspection //\n    ///////////////////////\n\n    /// @name object inspection\n    /// Functions to inspect the type of a JSON value.\n    /// @{\n\n    /*!\n    @brief serialization\n\n    Serialization function for JSON values. The function tries to mimic\n    Python's `json.dumps()` function, and currently supports its @a indent\n    and @a ensure_ascii parameters.\n\n    @param[in] indent If indent is nonnegative, then array elements and object\n    members will be pretty-printed with that indent level. An indent level of\n    `0` will only insert newlines. `-1` (the default) selects the most compact\n    representation.\n    @param[in] indent_char The character to use for indentation if @a indent is\n    greater than `0`. The default is ` ` (space).\n    @param[in] ensure_ascii If @a ensure_ascii is true, all non-ASCII characters\n    in the output are escaped with `\\uXXXX` sequences, and the result consists\n    of ASCII characters only.\n    @param[in] error_handler  how to react on decoding errors; there are three\n    possible values: `strict` (throws and exception in case a decoding error\n    occurs; default), `replace` (replace invalid UTF-8 sequences with U+FFFD),\n    and `ignore` (ignore invalid UTF-8 sequences during serialization).\n\n    @return string containing the serialization of the JSON value\n\n    @throw type_error.316 if a string stored inside the JSON value is not\n                          UTF-8 encoded\n\n    @complexity Linear.\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes in the JSON value.\n\n    @liveexample{The following example shows the effect of different @a indent\\,\n    @a indent_char\\, and @a ensure_ascii parameters to the result of the\n    serialization.,dump}\n\n    @see https://docs.python.org/2/library/json.html#json.dump\n\n    @since version 1.0.0; indentation character @a indent_char, option\n           @a ensure_ascii and exceptions added in version 3.0.0; error\n           handlers added in version 3.4.0.\n    */\n    string_t dump(const int indent = -1,\n                  const char indent_char = ' ',\n                  const bool ensure_ascii = false,\n                  const error_handler_t error_handler = error_handler_t::strict) const\n    {\n        string_t result;\n        serializer s(detail::output_adapter<char, string_t>(result), indent_char, error_handler);\n\n        if (indent >= 0)\n        {\n            s.dump(*this, true, ensure_ascii, static_cast<unsigned int>(indent));\n        }\n        else\n        {\n            s.dump(*this, false, ensure_ascii, 0);\n        }\n\n        return result;\n    }\n\n    /*!\n    @brief return the type of the JSON value (explicit)\n\n    Return the type of the JSON value as a value from the @ref value_t\n    enumeration.\n\n    @return the type of the JSON value\n            Value type                | return value\n            ------------------------- | -------------------------\n            null                      | value_t::null\n            boolean                   | value_t::boolean\n            string                    | value_t::string\n            number (integer)          | value_t::number_integer\n            number (unsigned integer) | value_t::number_unsigned\n            number (floating-point)   | value_t::number_float\n            object                    | value_t::object\n            array                     | value_t::array\n            discarded                 | value_t::discarded\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @liveexample{The following code exemplifies `type()` for all JSON\n    types.,type}\n\n    @sa @ref operator value_t() -- return the type of the JSON value (implicit)\n    @sa @ref type_name() -- return the type as string\n\n    @since version 1.0.0\n    */\n    constexpr value_t type() const noexcept\n    {\n        return m_type;\n    }\n\n    /*!\n    @brief return whether type is primitive\n\n    This function returns true if and only if the JSON type is primitive\n    (string, number, boolean, or null).\n\n    @return `true` if type is primitive (string, number, boolean, or null),\n    `false` otherwise.\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @liveexample{The following code exemplifies `is_primitive()` for all JSON\n    types.,is_primitive}\n\n    @sa @ref is_structured() -- returns whether JSON value is structured\n    @sa @ref is_null() -- returns whether JSON value is `null`\n    @sa @ref is_string() -- returns whether JSON value is a string\n    @sa @ref is_boolean() -- returns whether JSON value is a boolean\n    @sa @ref is_number() -- returns whether JSON value is a number\n\n    @since version 1.0.0\n    */\n    constexpr bool is_primitive() const noexcept\n    {\n        return is_null() or is_string() or is_boolean() or is_number();\n    }\n\n    /*!\n    @brief return whether type is structured\n\n    This function returns true if and only if the JSON type is structured\n    (array or object).\n\n    @return `true` if type is structured (array or object), `false` otherwise.\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @liveexample{The following code exemplifies `is_structured()` for all JSON\n    types.,is_structured}\n\n    @sa @ref is_primitive() -- returns whether value is primitive\n    @sa @ref is_array() -- returns whether value is an array\n    @sa @ref is_object() -- returns whether value is an object\n\n    @since version 1.0.0\n    */\n    constexpr bool is_structured() const noexcept\n    {\n        return is_array() or is_object();\n    }\n\n    /*!\n    @brief return whether value is null\n\n    This function returns true if and only if the JSON value is null.\n\n    @return `true` if type is null, `false` otherwise.\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @liveexample{The following code exemplifies `is_null()` for all JSON\n    types.,is_null}\n\n    @since version 1.0.0\n    */\n    constexpr bool is_null() const noexcept\n    {\n        return (m_type == value_t::null);\n    }\n\n    /*!\n    @brief return whether value is a boolean\n\n    This function returns true if and only if the JSON value is a boolean.\n\n    @return `true` if type is boolean, `false` otherwise.\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @liveexample{The following code exemplifies `is_boolean()` for all JSON\n    types.,is_boolean}\n\n    @since version 1.0.0\n    */\n    constexpr bool is_boolean() const noexcept\n    {\n        return (m_type == value_t::boolean);\n    }\n\n    /*!\n    @brief return whether value is a number\n\n    This function returns true if and only if the JSON value is a number. This\n    includes both integer (signed and unsigned) and floating-point values.\n\n    @return `true` if type is number (regardless whether integer, unsigned\n    integer or floating-type), `false` otherwise.\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @liveexample{The following code exemplifies `is_number()` for all JSON\n    types.,is_number}\n\n    @sa @ref is_number_integer() -- check if value is an integer or unsigned\n    integer number\n    @sa @ref is_number_unsigned() -- check if value is an unsigned integer\n    number\n    @sa @ref is_number_float() -- check if value is a floating-point number\n\n    @since version 1.0.0\n    */\n    constexpr bool is_number() const noexcept\n    {\n        return is_number_integer() or is_number_float();\n    }\n\n    /*!\n    @brief return whether value is an integer number\n\n    This function returns true if and only if the JSON value is a signed or\n    unsigned integer number. This excludes floating-point values.\n\n    @return `true` if type is an integer or unsigned integer number, `false`\n    otherwise.\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @liveexample{The following code exemplifies `is_number_integer()` for all\n    JSON types.,is_number_integer}\n\n    @sa @ref is_number() -- check if value is a number\n    @sa @ref is_number_unsigned() -- check if value is an unsigned integer\n    number\n    @sa @ref is_number_float() -- check if value is a floating-point number\n\n    @since version 1.0.0\n    */\n    constexpr bool is_number_integer() const noexcept\n    {\n        return (m_type == value_t::number_integer or m_type == value_t::number_unsigned);\n    }\n\n    /*!\n    @brief return whether value is an unsigned integer number\n\n    This function returns true if and only if the JSON value is an unsigned\n    integer number. This excludes floating-point and signed integer values.\n\n    @return `true` if type is an unsigned integer number, `false` otherwise.\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @liveexample{The following code exemplifies `is_number_unsigned()` for all\n    JSON types.,is_number_unsigned}\n\n    @sa @ref is_number() -- check if value is a number\n    @sa @ref is_number_integer() -- check if value is an integer or unsigned\n    integer number\n    @sa @ref is_number_float() -- check if value is a floating-point number\n\n    @since version 2.0.0\n    */\n    constexpr bool is_number_unsigned() const noexcept\n    {\n        return (m_type == value_t::number_unsigned);\n    }\n\n    /*!\n    @brief return whether value is a floating-point number\n\n    This function returns true if and only if the JSON value is a\n    floating-point number. This excludes signed and unsigned integer values.\n\n    @return `true` if type is a floating-point number, `false` otherwise.\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @liveexample{The following code exemplifies `is_number_float()` for all\n    JSON types.,is_number_float}\n\n    @sa @ref is_number() -- check if value is number\n    @sa @ref is_number_integer() -- check if value is an integer number\n    @sa @ref is_number_unsigned() -- check if value is an unsigned integer\n    number\n\n    @since version 1.0.0\n    */\n    constexpr bool is_number_float() const noexcept\n    {\n        return (m_type == value_t::number_float);\n    }\n\n    /*!\n    @brief return whether value is an object\n\n    This function returns true if and only if the JSON value is an object.\n\n    @return `true` if type is object, `false` otherwise.\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @liveexample{The following code exemplifies `is_object()` for all JSON\n    types.,is_object}\n\n    @since version 1.0.0\n    */\n    constexpr bool is_object() const noexcept\n    {\n        return (m_type == value_t::object);\n    }\n\n    /*!\n    @brief return whether value is an array\n\n    This function returns true if and only if the JSON value is an array.\n\n    @return `true` if type is array, `false` otherwise.\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @liveexample{The following code exemplifies `is_array()` for all JSON\n    types.,is_array}\n\n    @since version 1.0.0\n    */\n    constexpr bool is_array() const noexcept\n    {\n        return (m_type == value_t::array);\n    }\n\n    /*!\n    @brief return whether value is a string\n\n    This function returns true if and only if the JSON value is a string.\n\n    @return `true` if type is string, `false` otherwise.\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @liveexample{The following code exemplifies `is_string()` for all JSON\n    types.,is_string}\n\n    @since version 1.0.0\n    */\n    constexpr bool is_string() const noexcept\n    {\n        return (m_type == value_t::string);\n    }\n\n    /*!\n    @brief return whether value is discarded\n\n    This function returns true if and only if the JSON value was discarded\n    during parsing with a callback function (see @ref parser_callback_t).\n\n    @note This function will always be `false` for JSON values after parsing.\n    That is, discarded values can only occur during parsing, but will be\n    removed when inside a structured value or replaced by null in other cases.\n\n    @return `true` if type is discarded, `false` otherwise.\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @liveexample{The following code exemplifies `is_discarded()` for all JSON\n    types.,is_discarded}\n\n    @since version 1.0.0\n    */\n    constexpr bool is_discarded() const noexcept\n    {\n        return (m_type == value_t::discarded);\n    }\n\n    /*!\n    @brief return the type of the JSON value (implicit)\n\n    Implicitly return the type of the JSON value as a value from the @ref\n    value_t enumeration.\n\n    @return the type of the JSON value\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @liveexample{The following code exemplifies the @ref value_t operator for\n    all JSON types.,operator__value_t}\n\n    @sa @ref type() -- return the type of the JSON value (explicit)\n    @sa @ref type_name() -- return the type as string\n\n    @since version 1.0.0\n    */\n    constexpr operator value_t() const noexcept\n    {\n        return m_type;\n    }\n\n    /// @}\n\n  private:\n    //////////////////\n    // value access //\n    //////////////////\n\n    /// get a boolean (explicit)\n    boolean_t get_impl(boolean_t* /*unused*/) const\n    {\n        if (JSON_LIKELY(is_boolean()))\n        {\n            return m_value.boolean;\n        }\n\n        JSON_THROW(type_error::create(302, \"type must be boolean, but is \" + std::string(type_name())));\n    }\n\n    /// get a pointer to the value (object)\n    object_t* get_impl_ptr(object_t* /*unused*/) noexcept\n    {\n        return is_object() ? m_value.object : nullptr;\n    }\n\n    /// get a pointer to the value (object)\n    constexpr const object_t* get_impl_ptr(const object_t* /*unused*/) const noexcept\n    {\n        return is_object() ? m_value.object : nullptr;\n    }\n\n    /// get a pointer to the value (array)\n    array_t* get_impl_ptr(array_t* /*unused*/) noexcept\n    {\n        return is_array() ? m_value.array : nullptr;\n    }\n\n    /// get a pointer to the value (array)\n    constexpr const array_t* get_impl_ptr(const array_t* /*unused*/) const noexcept\n    {\n        return is_array() ? m_value.array : nullptr;\n    }\n\n    /// get a pointer to the value (string)\n    string_t* get_impl_ptr(string_t* /*unused*/) noexcept\n    {\n        return is_string() ? m_value.string : nullptr;\n    }\n\n    /// get a pointer to the value (string)\n    constexpr const string_t* get_impl_ptr(const string_t* /*unused*/) const noexcept\n    {\n        return is_string() ? m_value.string : nullptr;\n    }\n\n    /// get a pointer to the value (boolean)\n    boolean_t* get_impl_ptr(boolean_t* /*unused*/) noexcept\n    {\n        return is_boolean() ? &m_value.boolean : nullptr;\n    }\n\n    /// get a pointer to the value (boolean)\n    constexpr const boolean_t* get_impl_ptr(const boolean_t* /*unused*/) const noexcept\n    {\n        return is_boolean() ? &m_value.boolean : nullptr;\n    }\n\n    /// get a pointer to the value (integer number)\n    number_integer_t* get_impl_ptr(number_integer_t* /*unused*/) noexcept\n    {\n        return is_number_integer() ? &m_value.number_integer : nullptr;\n    }\n\n    /// get a pointer to the value (integer number)\n    constexpr const number_integer_t* get_impl_ptr(const number_integer_t* /*unused*/) const noexcept\n    {\n        return is_number_integer() ? &m_value.number_integer : nullptr;\n    }\n\n    /// get a pointer to the value (unsigned number)\n    number_unsigned_t* get_impl_ptr(number_unsigned_t* /*unused*/) noexcept\n    {\n        return is_number_unsigned() ? &m_value.number_unsigned : nullptr;\n    }\n\n    /// get a pointer to the value (unsigned number)\n    constexpr const number_unsigned_t* get_impl_ptr(const number_unsigned_t* /*unused*/) const noexcept\n    {\n        return is_number_unsigned() ? &m_value.number_unsigned : nullptr;\n    }\n\n    /// get a pointer to the value (floating-point number)\n    number_float_t* get_impl_ptr(number_float_t* /*unused*/) noexcept\n    {\n        return is_number_float() ? &m_value.number_float : nullptr;\n    }\n\n    /// get a pointer to the value (floating-point number)\n    constexpr const number_float_t* get_impl_ptr(const number_float_t* /*unused*/) const noexcept\n    {\n        return is_number_float() ? &m_value.number_float : nullptr;\n    }\n\n    /*!\n    @brief helper function to implement get_ref()\n\n    This function helps to implement get_ref() without code duplication for\n    const and non-const overloads\n\n    @tparam ThisType will be deduced as `basic_json` or `const basic_json`\n\n    @throw type_error.303 if ReferenceType does not match underlying value\n    type of the current JSON\n    */\n    template<typename ReferenceType, typename ThisType>\n    static ReferenceType get_ref_impl(ThisType& obj)\n    {\n        // delegate the call to get_ptr<>()\n        auto ptr = obj.template get_ptr<typename std::add_pointer<ReferenceType>::type>();\n\n        if (JSON_LIKELY(ptr != nullptr))\n        {\n            return *ptr;\n        }\n\n        JSON_THROW(type_error::create(303, \"incompatible ReferenceType for get_ref, actual type is \" + std::string(obj.type_name())));\n    }\n\n  public:\n    /// @name value access\n    /// Direct access to the stored value of a JSON value.\n    /// @{\n\n    /*!\n    @brief get special-case overload\n\n    This overloads avoids a lot of template boilerplate, it can be seen as the\n    identity method\n\n    @tparam BasicJsonType == @ref basic_json\n\n    @return a copy of *this\n\n    @complexity Constant.\n\n    @since version 2.1.0\n    */\n    template<typename BasicJsonType, detail::enable_if_t<\n                 std::is_same<typename std::remove_const<BasicJsonType>::type, basic_json_t>::value,\n                 int> = 0>\n    basic_json get() const\n    {\n        return *this;\n    }\n\n    /*!\n    @brief get special-case overload\n\n    This overloads converts the current @ref basic_json in a different\n    @ref basic_json type\n\n    @tparam BasicJsonType == @ref basic_json\n\n    @return a copy of *this, converted into @tparam BasicJsonType\n\n    @complexity Depending on the implementation of the called `from_json()`\n                method.\n\n    @since version 3.2.0\n    */\n    template<typename BasicJsonType, detail::enable_if_t<\n                 not std::is_same<BasicJsonType, basic_json>::value and\n                 detail::is_basic_json<BasicJsonType>::value, int> = 0>\n    BasicJsonType get() const\n    {\n        return *this;\n    }\n\n    /*!\n    @brief get a value (explicit)\n\n    Explicit type conversion between the JSON value and a compatible value\n    which is [CopyConstructible](https://en.cppreference.com/w/cpp/named_req/CopyConstructible)\n    and [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible).\n    The value is converted by calling the @ref json_serializer<ValueType>\n    `from_json()` method.\n\n    The function is equivalent to executing\n    @code {.cpp}\n    ValueType ret;\n    JSONSerializer<ValueType>::from_json(*this, ret);\n    return ret;\n    @endcode\n\n    This overloads is chosen if:\n    - @a ValueType is not @ref basic_json,\n    - @ref json_serializer<ValueType> has a `from_json()` method of the form\n      `void from_json(const basic_json&, ValueType&)`, and\n    - @ref json_serializer<ValueType> does not have a `from_json()` method of\n      the form `ValueType from_json(const basic_json&)`\n\n    @tparam ValueTypeCV the provided value type\n    @tparam ValueType the returned value type\n\n    @return copy of the JSON value, converted to @a ValueType\n\n    @throw what @ref json_serializer<ValueType> `from_json()` method throws\n\n    @liveexample{The example below shows several conversions from JSON values\n    to other types. There a few things to note: (1) Floating-point numbers can\n    be converted to integers\\, (2) A JSON array can be converted to a standard\n    `std::vector<short>`\\, (3) A JSON object can be converted to C++\n    associative containers such as `std::unordered_map<std::string\\,\n    json>`.,get__ValueType_const}\n\n    @since version 2.1.0\n    */\n    template<typename ValueTypeCV, typename ValueType = detail::uncvref_t<ValueTypeCV>,\n             detail::enable_if_t <\n                 not detail::is_basic_json<ValueType>::value and\n                 detail::has_from_json<basic_json_t, ValueType>::value and\n                 not detail::has_non_default_from_json<basic_json_t, ValueType>::value,\n                 int> = 0>\n    ValueType get() const noexcept(noexcept(\n                                       JSONSerializer<ValueType>::from_json(std::declval<const basic_json_t&>(), std::declval<ValueType&>())))\n    {\n        // we cannot static_assert on ValueTypeCV being non-const, because\n        // there is support for get<const basic_json_t>(), which is why we\n        // still need the uncvref\n        static_assert(not std::is_reference<ValueTypeCV>::value,\n                      \"get() cannot be used with reference types, you might want to use get_ref()\");\n        static_assert(std::is_default_constructible<ValueType>::value,\n                      \"types must be DefaultConstructible when used with get()\");\n\n        ValueType ret;\n        JSONSerializer<ValueType>::from_json(*this, ret);\n        return ret;\n    }\n\n    /*!\n    @brief get a value (explicit); special case\n\n    Explicit type conversion between the JSON value and a compatible value\n    which is **not** [CopyConstructible](https://en.cppreference.com/w/cpp/named_req/CopyConstructible)\n    and **not** [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible).\n    The value is converted by calling the @ref json_serializer<ValueType>\n    `from_json()` method.\n\n    The function is equivalent to executing\n    @code {.cpp}\n    return JSONSerializer<ValueTypeCV>::from_json(*this);\n    @endcode\n\n    This overloads is chosen if:\n    - @a ValueType is not @ref basic_json and\n    - @ref json_serializer<ValueType> has a `from_json()` method of the form\n      `ValueType from_json(const basic_json&)`\n\n    @note If @ref json_serializer<ValueType> has both overloads of\n    `from_json()`, this one is chosen.\n\n    @tparam ValueTypeCV the provided value type\n    @tparam ValueType the returned value type\n\n    @return copy of the JSON value, converted to @a ValueType\n\n    @throw what @ref json_serializer<ValueType> `from_json()` method throws\n\n    @since version 2.1.0\n    */\n    template<typename ValueTypeCV, typename ValueType = detail::uncvref_t<ValueTypeCV>,\n             detail::enable_if_t<not std::is_same<basic_json_t, ValueType>::value and\n                                 detail::has_non_default_from_json<basic_json_t, ValueType>::value,\n                                 int> = 0>\n    ValueType get() const noexcept(noexcept(\n                                       JSONSerializer<ValueTypeCV>::from_json(std::declval<const basic_json_t&>())))\n    {\n        static_assert(not std::is_reference<ValueTypeCV>::value,\n                      \"get() cannot be used with reference types, you might want to use get_ref()\");\n        return JSONSerializer<ValueTypeCV>::from_json(*this);\n    }\n\n    /*!\n    @brief get a value (explicit)\n\n    Explicit type conversion between the JSON value and a compatible value.\n    The value is filled into the input parameter by calling the @ref json_serializer<ValueType>\n    `from_json()` method.\n\n    The function is equivalent to executing\n    @code {.cpp}\n    ValueType v;\n    JSONSerializer<ValueType>::from_json(*this, v);\n    @endcode\n\n    This overloads is chosen if:\n    - @a ValueType is not @ref basic_json,\n    - @ref json_serializer<ValueType> has a `from_json()` method of the form\n      `void from_json(const basic_json&, ValueType&)`, and\n\n    @tparam ValueType the input parameter type.\n\n    @return the input parameter, allowing chaining calls.\n\n    @throw what @ref json_serializer<ValueType> `from_json()` method throws\n\n    @liveexample{The example below shows several conversions from JSON values\n    to other types. There a few things to note: (1) Floating-point numbers can\n    be converted to integers\\, (2) A JSON array can be converted to a standard\n    `std::vector<short>`\\, (3) A JSON object can be converted to C++\n    associative containers such as `std::unordered_map<std::string\\,\n    json>`.,get_to}\n\n    @since version 3.3.0\n    */\n    template<typename ValueType,\n             detail::enable_if_t <\n                 not detail::is_basic_json<ValueType>::value and\n                 detail::has_from_json<basic_json_t, ValueType>::value,\n                 int> = 0>\n    ValueType & get_to(ValueType& v) const noexcept(noexcept(\n                JSONSerializer<ValueType>::from_json(std::declval<const basic_json_t&>(), v)))\n    {\n        JSONSerializer<ValueType>::from_json(*this, v);\n        return v;\n    }\n\n\n    /*!\n    @brief get a pointer value (implicit)\n\n    Implicit pointer access to the internally stored JSON value. No copies are\n    made.\n\n    @warning Writing data to the pointee of the result yields an undefined\n    state.\n\n    @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref\n    object_t, @ref string_t, @ref boolean_t, @ref number_integer_t,\n    @ref number_unsigned_t, or @ref number_float_t. Enforced by a static\n    assertion.\n\n    @return pointer to the internally stored JSON value if the requested\n    pointer type @a PointerType fits to the JSON value; `nullptr` otherwise\n\n    @complexity Constant.\n\n    @liveexample{The example below shows how pointers to internal values of a\n    JSON value can be requested. Note that no type conversions are made and a\n    `nullptr` is returned if the value and the requested pointer type does not\n    match.,get_ptr}\n\n    @since version 1.0.0\n    */\n    template<typename PointerType, typename std::enable_if<\n                 std::is_pointer<PointerType>::value, int>::type = 0>\n    auto get_ptr() noexcept -> decltype(std::declval<basic_json_t&>().get_impl_ptr(std::declval<PointerType>()))\n    {\n        // delegate the call to get_impl_ptr<>()\n        return get_impl_ptr(static_cast<PointerType>(nullptr));\n    }\n\n    /*!\n    @brief get a pointer value (implicit)\n    @copydoc get_ptr()\n    */\n    template<typename PointerType, typename std::enable_if<\n                 std::is_pointer<PointerType>::value and\n                 std::is_const<typename std::remove_pointer<PointerType>::type>::value, int>::type = 0>\n    constexpr auto get_ptr() const noexcept -> decltype(std::declval<const basic_json_t&>().get_impl_ptr(std::declval<PointerType>()))\n    {\n        // delegate the call to get_impl_ptr<>() const\n        return get_impl_ptr(static_cast<PointerType>(nullptr));\n    }\n\n    /*!\n    @brief get a pointer value (explicit)\n\n    Explicit pointer access to the internally stored JSON value. No copies are\n    made.\n\n    @warning The pointer becomes invalid if the underlying JSON object\n    changes.\n\n    @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref\n    object_t, @ref string_t, @ref boolean_t, @ref number_integer_t,\n    @ref number_unsigned_t, or @ref number_float_t.\n\n    @return pointer to the internally stored JSON value if the requested\n    pointer type @a PointerType fits to the JSON value; `nullptr` otherwise\n\n    @complexity Constant.\n\n    @liveexample{The example below shows how pointers to internal values of a\n    JSON value can be requested. Note that no type conversions are made and a\n    `nullptr` is returned if the value and the requested pointer type does not\n    match.,get__PointerType}\n\n    @sa @ref get_ptr() for explicit pointer-member access\n\n    @since version 1.0.0\n    */\n    template<typename PointerType, typename std::enable_if<\n                 std::is_pointer<PointerType>::value, int>::type = 0>\n    auto get() noexcept -> decltype(std::declval<basic_json_t&>().template get_ptr<PointerType>())\n    {\n        // delegate the call to get_ptr\n        return get_ptr<PointerType>();\n    }\n\n    /*!\n    @brief get a pointer value (explicit)\n    @copydoc get()\n    */\n    template<typename PointerType, typename std::enable_if<\n                 std::is_pointer<PointerType>::value, int>::type = 0>\n    constexpr auto get() const noexcept -> decltype(std::declval<const basic_json_t&>().template get_ptr<PointerType>())\n    {\n        // delegate the call to get_ptr\n        return get_ptr<PointerType>();\n    }\n\n    /*!\n    @brief get a reference value (implicit)\n\n    Implicit reference access to the internally stored JSON value. No copies\n    are made.\n\n    @warning Writing data to the referee of the result yields an undefined\n    state.\n\n    @tparam ReferenceType reference type; must be a reference to @ref array_t,\n    @ref object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, or\n    @ref number_float_t. Enforced by static assertion.\n\n    @return reference to the internally stored JSON value if the requested\n    reference type @a ReferenceType fits to the JSON value; throws\n    type_error.303 otherwise\n\n    @throw type_error.303 in case passed type @a ReferenceType is incompatible\n    with the stored JSON value; see example below\n\n    @complexity Constant.\n\n    @liveexample{The example shows several calls to `get_ref()`.,get_ref}\n\n    @since version 1.1.0\n    */\n    template<typename ReferenceType, typename std::enable_if<\n                 std::is_reference<ReferenceType>::value, int>::type = 0>\n    ReferenceType get_ref()\n    {\n        // delegate call to get_ref_impl\n        return get_ref_impl<ReferenceType>(*this);\n    }\n\n    /*!\n    @brief get a reference value (implicit)\n    @copydoc get_ref()\n    */\n    template<typename ReferenceType, typename std::enable_if<\n                 std::is_reference<ReferenceType>::value and\n                 std::is_const<typename std::remove_reference<ReferenceType>::type>::value, int>::type = 0>\n    ReferenceType get_ref() const\n    {\n        // delegate call to get_ref_impl\n        return get_ref_impl<ReferenceType>(*this);\n    }\n\n    /*!\n    @brief get a value (implicit)\n\n    Implicit type conversion between the JSON value and a compatible value.\n    The call is realized by calling @ref get() const.\n\n    @tparam ValueType non-pointer type compatible to the JSON value, for\n    instance `int` for JSON integer numbers, `bool` for JSON booleans, or\n    `std::vector` types for JSON arrays. The character type of @ref string_t\n    as well as an initializer list of this type is excluded to avoid\n    ambiguities as these types implicitly convert to `std::string`.\n\n    @return copy of the JSON value, converted to type @a ValueType\n\n    @throw type_error.302 in case passed type @a ValueType is incompatible\n    to the JSON value type (e.g., the JSON value is of type boolean, but a\n    string is requested); see example below\n\n    @complexity Linear in the size of the JSON value.\n\n    @liveexample{The example below shows several conversions from JSON values\n    to other types. There a few things to note: (1) Floating-point numbers can\n    be converted to integers\\, (2) A JSON array can be converted to a standard\n    `std::vector<short>`\\, (3) A JSON object can be converted to C++\n    associative containers such as `std::unordered_map<std::string\\,\n    json>`.,operator__ValueType}\n\n    @since version 1.0.0\n    */\n    template < typename ValueType, typename std::enable_if <\n                   not std::is_pointer<ValueType>::value and\n                   not std::is_same<ValueType, detail::json_ref<basic_json>>::value and\n                   not std::is_same<ValueType, typename string_t::value_type>::value and\n                   not detail::is_basic_json<ValueType>::value\n\n#ifndef _MSC_VER  // fix for issue #167 operator<< ambiguity under VS2015\n                   and not std::is_same<ValueType, std::initializer_list<typename string_t::value_type>>::value\n#if defined(JSON_HAS_CPP_17) && defined(_MSC_VER) and _MSC_VER <= 1914\n                   and not std::is_same<ValueType, typename std::string_view>::value\n#endif\n#endif\n                   and detail::is_detected<detail::get_template_function, const basic_json_t&, ValueType>::value\n                   , int >::type = 0 >\n    operator ValueType() const\n    {\n        // delegate the call to get<>() const\n        return get<ValueType>();\n    }\n\n    /// @}\n\n\n    ////////////////////\n    // element access //\n    ////////////////////\n\n    /// @name element access\n    /// Access to the JSON value.\n    /// @{\n\n    /*!\n    @brief access specified array element with bounds checking\n\n    Returns a reference to the element at specified location @a idx, with\n    bounds checking.\n\n    @param[in] idx  index of the element to access\n\n    @return reference to the element at index @a idx\n\n    @throw type_error.304 if the JSON value is not an array; in this case,\n    calling `at` with an index makes no sense. See example below.\n    @throw out_of_range.401 if the index @a idx is out of range of the array;\n    that is, `idx >= size()`. See example below.\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes in the JSON value.\n\n    @complexity Constant.\n\n    @since version 1.0.0\n\n    @liveexample{The example below shows how array elements can be read and\n    written using `at()`. It also demonstrates the different exceptions that\n    can be thrown.,at__size_type}\n    */\n    reference at(size_type idx)\n    {\n        // at only works for arrays\n        if (JSON_LIKELY(is_array()))\n        {\n            JSON_TRY\n            {\n                return m_value.array->at(idx);\n            }\n            JSON_CATCH (std::out_of_range&)\n            {\n                // create better exception explanation\n                JSON_THROW(out_of_range::create(401, \"array index \" + std::to_string(idx) + \" is out of range\"));\n            }\n        }\n        else\n        {\n            JSON_THROW(type_error::create(304, \"cannot use at() with \" + std::string(type_name())));\n        }\n    }\n\n    /*!\n    @brief access specified array element with bounds checking\n\n    Returns a const reference to the element at specified location @a idx,\n    with bounds checking.\n\n    @param[in] idx  index of the element to access\n\n    @return const reference to the element at index @a idx\n\n    @throw type_error.304 if the JSON value is not an array; in this case,\n    calling `at` with an index makes no sense. See example below.\n    @throw out_of_range.401 if the index @a idx is out of range of the array;\n    that is, `idx >= size()`. See example below.\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes in the JSON value.\n\n    @complexity Constant.\n\n    @since version 1.0.0\n\n    @liveexample{The example below shows how array elements can be read using\n    `at()`. It also demonstrates the different exceptions that can be thrown.,\n    at__size_type_const}\n    */\n    const_reference at(size_type idx) const\n    {\n        // at only works for arrays\n        if (JSON_LIKELY(is_array()))\n        {\n            JSON_TRY\n            {\n                return m_value.array->at(idx);\n            }\n            JSON_CATCH (std::out_of_range&)\n            {\n                // create better exception explanation\n                JSON_THROW(out_of_range::create(401, \"array index \" + std::to_string(idx) + \" is out of range\"));\n            }\n        }\n        else\n        {\n            JSON_THROW(type_error::create(304, \"cannot use at() with \" + std::string(type_name())));\n        }\n    }\n\n    /*!\n    @brief access specified object element with bounds checking\n\n    Returns a reference to the element at with specified key @a key, with\n    bounds checking.\n\n    @param[in] key  key of the element to access\n\n    @return reference to the element at key @a key\n\n    @throw type_error.304 if the JSON value is not an object; in this case,\n    calling `at` with a key makes no sense. See example below.\n    @throw out_of_range.403 if the key @a key is is not stored in the object;\n    that is, `find(key) == end()`. See example below.\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes in the JSON value.\n\n    @complexity Logarithmic in the size of the container.\n\n    @sa @ref operator[](const typename object_t::key_type&) for unchecked\n    access by reference\n    @sa @ref value() for access by value with a default value\n\n    @since version 1.0.0\n\n    @liveexample{The example below shows how object elements can be read and\n    written using `at()`. It also demonstrates the different exceptions that\n    can be thrown.,at__object_t_key_type}\n    */\n    reference at(const typename object_t::key_type& key)\n    {\n        // at only works for objects\n        if (JSON_LIKELY(is_object()))\n        {\n            JSON_TRY\n            {\n                return m_value.object->at(key);\n            }\n            JSON_CATCH (std::out_of_range&)\n            {\n                // create better exception explanation\n                JSON_THROW(out_of_range::create(403, \"key '\" + key + \"' not found\"));\n            }\n        }\n        else\n        {\n            JSON_THROW(type_error::create(304, \"cannot use at() with \" + std::string(type_name())));\n        }\n    }\n\n    /*!\n    @brief access specified object element with bounds checking\n\n    Returns a const reference to the element at with specified key @a key,\n    with bounds checking.\n\n    @param[in] key  key of the element to access\n\n    @return const reference to the element at key @a key\n\n    @throw type_error.304 if the JSON value is not an object; in this case,\n    calling `at` with a key makes no sense. See example below.\n    @throw out_of_range.403 if the key @a key is is not stored in the object;\n    that is, `find(key) == end()`. See example below.\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes in the JSON value.\n\n    @complexity Logarithmic in the size of the container.\n\n    @sa @ref operator[](const typename object_t::key_type&) for unchecked\n    access by reference\n    @sa @ref value() for access by value with a default value\n\n    @since version 1.0.0\n\n    @liveexample{The example below shows how object elements can be read using\n    `at()`. It also demonstrates the different exceptions that can be thrown.,\n    at__object_t_key_type_const}\n    */\n    const_reference at(const typename object_t::key_type& key) const\n    {\n        // at only works for objects\n        if (JSON_LIKELY(is_object()))\n        {\n            JSON_TRY\n            {\n                return m_value.object->at(key);\n            }\n            JSON_CATCH (std::out_of_range&)\n            {\n                // create better exception explanation\n                JSON_THROW(out_of_range::create(403, \"key '\" + key + \"' not found\"));\n            }\n        }\n        else\n        {\n            JSON_THROW(type_error::create(304, \"cannot use at() with \" + std::string(type_name())));\n        }\n    }\n\n    /*!\n    @brief access specified array element\n\n    Returns a reference to the element at specified location @a idx.\n\n    @note If @a idx is beyond the range of the array (i.e., `idx >= size()`),\n    then the array is silently filled up with `null` values to make `idx` a\n    valid reference to the last stored element.\n\n    @param[in] idx  index of the element to access\n\n    @return reference to the element at index @a idx\n\n    @throw type_error.305 if the JSON value is not an array or null; in that\n    cases, using the [] operator with an index makes no sense.\n\n    @complexity Constant if @a idx is in the range of the array. Otherwise\n    linear in `idx - size()`.\n\n    @liveexample{The example below shows how array elements can be read and\n    written using `[]` operator. Note the addition of `null`\n    values.,operatorarray__size_type}\n\n    @since version 1.0.0\n    */\n    reference operator[](size_type idx)\n    {\n        // implicitly convert null value to an empty array\n        if (is_null())\n        {\n            m_type = value_t::array;\n            m_value.array = create<array_t>();\n            assert_invariant();\n        }\n\n        // operator[] only works for arrays\n        if (JSON_LIKELY(is_array()))\n        {\n            // fill up array with null values if given idx is outside range\n            if (idx >= m_value.array->size())\n            {\n                m_value.array->insert(m_value.array->end(),\n                                      idx - m_value.array->size() + 1,\n                                      basic_json());\n            }\n\n            return m_value.array->operator[](idx);\n        }\n\n        JSON_THROW(type_error::create(305, \"cannot use operator[] with a numeric argument with \" + std::string(type_name())));\n    }\n\n    /*!\n    @brief access specified array element\n\n    Returns a const reference to the element at specified location @a idx.\n\n    @param[in] idx  index of the element to access\n\n    @return const reference to the element at index @a idx\n\n    @throw type_error.305 if the JSON value is not an array; in that case,\n    using the [] operator with an index makes no sense.\n\n    @complexity Constant.\n\n    @liveexample{The example below shows how array elements can be read using\n    the `[]` operator.,operatorarray__size_type_const}\n\n    @since version 1.0.0\n    */\n    const_reference operator[](size_type idx) const\n    {\n        // const operator[] only works for arrays\n        if (JSON_LIKELY(is_array()))\n        {\n            return m_value.array->operator[](idx);\n        }\n\n        JSON_THROW(type_error::create(305, \"cannot use operator[] with a numeric argument with \" + std::string(type_name())));\n    }\n\n    /*!\n    @brief access specified object element\n\n    Returns a reference to the element at with specified key @a key.\n\n    @note If @a key is not found in the object, then it is silently added to\n    the object and filled with a `null` value to make `key` a valid reference.\n    In case the value was `null` before, it is converted to an object.\n\n    @param[in] key  key of the element to access\n\n    @return reference to the element at key @a key\n\n    @throw type_error.305 if the JSON value is not an object or null; in that\n    cases, using the [] operator with a key makes no sense.\n\n    @complexity Logarithmic in the size of the container.\n\n    @liveexample{The example below shows how object elements can be read and\n    written using the `[]` operator.,operatorarray__key_type}\n\n    @sa @ref at(const typename object_t::key_type&) for access by reference\n    with range checking\n    @sa @ref value() for access by value with a default value\n\n    @since version 1.0.0\n    */\n    reference operator[](const typename object_t::key_type& key)\n    {\n        // implicitly convert null value to an empty object\n        if (is_null())\n        {\n            m_type = value_t::object;\n            m_value.object = create<object_t>();\n            assert_invariant();\n        }\n\n        // operator[] only works for objects\n        if (JSON_LIKELY(is_object()))\n        {\n            return m_value.object->operator[](key);\n        }\n\n        JSON_THROW(type_error::create(305, \"cannot use operator[] with a string argument with \" + std::string(type_name())));\n    }\n\n    /*!\n    @brief read-only access specified object element\n\n    Returns a const reference to the element at with specified key @a key. No\n    bounds checking is performed.\n\n    @warning If the element with key @a key does not exist, the behavior is\n    undefined.\n\n    @param[in] key  key of the element to access\n\n    @return const reference to the element at key @a key\n\n    @pre The element with key @a key must exist. **This precondition is\n         enforced with an assertion.**\n\n    @throw type_error.305 if the JSON value is not an object; in that case,\n    using the [] operator with a key makes no sense.\n\n    @complexity Logarithmic in the size of the container.\n\n    @liveexample{The example below shows how object elements can be read using\n    the `[]` operator.,operatorarray__key_type_const}\n\n    @sa @ref at(const typename object_t::key_type&) for access by reference\n    with range checking\n    @sa @ref value() for access by value with a default value\n\n    @since version 1.0.0\n    */\n    const_reference operator[](const typename object_t::key_type& key) const\n    {\n        // const operator[] only works for objects\n        if (JSON_LIKELY(is_object()))\n        {\n            assert(m_value.object->find(key) != m_value.object->end());\n            return m_value.object->find(key)->second;\n        }\n\n        JSON_THROW(type_error::create(305, \"cannot use operator[] with a string argument with \" + std::string(type_name())));\n    }\n\n    /*!\n    @brief access specified object element\n\n    Returns a reference to the element at with specified key @a key.\n\n    @note If @a key is not found in the object, then it is silently added to\n    the object and filled with a `null` value to make `key` a valid reference.\n    In case the value was `null` before, it is converted to an object.\n\n    @param[in] key  key of the element to access\n\n    @return reference to the element at key @a key\n\n    @throw type_error.305 if the JSON value is not an object or null; in that\n    cases, using the [] operator with a key makes no sense.\n\n    @complexity Logarithmic in the size of the container.\n\n    @liveexample{The example below shows how object elements can be read and\n    written using the `[]` operator.,operatorarray__key_type}\n\n    @sa @ref at(const typename object_t::key_type&) for access by reference\n    with range checking\n    @sa @ref value() for access by value with a default value\n\n    @since version 1.1.0\n    */\n    template<typename T>\n    reference operator[](T* key)\n    {\n        // implicitly convert null to object\n        if (is_null())\n        {\n            m_type = value_t::object;\n            m_value = value_t::object;\n            assert_invariant();\n        }\n\n        // at only works for objects\n        if (JSON_LIKELY(is_object()))\n        {\n            return m_value.object->operator[](key);\n        }\n\n        JSON_THROW(type_error::create(305, \"cannot use operator[] with a string argument with \" + std::string(type_name())));\n    }\n\n    /*!\n    @brief read-only access specified object element\n\n    Returns a const reference to the element at with specified key @a key. No\n    bounds checking is performed.\n\n    @warning If the element with key @a key does not exist, the behavior is\n    undefined.\n\n    @param[in] key  key of the element to access\n\n    @return const reference to the element at key @a key\n\n    @pre The element with key @a key must exist. **This precondition is\n         enforced with an assertion.**\n\n    @throw type_error.305 if the JSON value is not an object; in that case,\n    using the [] operator with a key makes no sense.\n\n    @complexity Logarithmic in the size of the container.\n\n    @liveexample{The example below shows how object elements can be read using\n    the `[]` operator.,operatorarray__key_type_const}\n\n    @sa @ref at(const typename object_t::key_type&) for access by reference\n    with range checking\n    @sa @ref value() for access by value with a default value\n\n    @since version 1.1.0\n    */\n    template<typename T>\n    const_reference operator[](T* key) const\n    {\n        // at only works for objects\n        if (JSON_LIKELY(is_object()))\n        {\n            assert(m_value.object->find(key) != m_value.object->end());\n            return m_value.object->find(key)->second;\n        }\n\n        JSON_THROW(type_error::create(305, \"cannot use operator[] with a string argument with \" + std::string(type_name())));\n    }\n\n    /*!\n    @brief access specified object element with default value\n\n    Returns either a copy of an object's element at the specified key @a key\n    or a given default value if no element with key @a key exists.\n\n    The function is basically equivalent to executing\n    @code {.cpp}\n    try {\n        return at(key);\n    } catch(out_of_range) {\n        return default_value;\n    }\n    @endcode\n\n    @note Unlike @ref at(const typename object_t::key_type&), this function\n    does not throw if the given key @a key was not found.\n\n    @note Unlike @ref operator[](const typename object_t::key_type& key), this\n    function does not implicitly add an element to the position defined by @a\n    key. This function is furthermore also applicable to const objects.\n\n    @param[in] key  key of the element to access\n    @param[in] default_value  the value to return if @a key is not found\n\n    @tparam ValueType type compatible to JSON values, for instance `int` for\n    JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for\n    JSON arrays. Note the type of the expected value at @a key and the default\n    value @a default_value must be compatible.\n\n    @return copy of the element at key @a key or @a default_value if @a key\n    is not found\n\n    @throw type_error.306 if the JSON value is not an object; in that case,\n    using `value()` with a key makes no sense.\n\n    @complexity Logarithmic in the size of the container.\n\n    @liveexample{The example below shows how object elements can be queried\n    with a default value.,basic_json__value}\n\n    @sa @ref at(const typename object_t::key_type&) for access by reference\n    with range checking\n    @sa @ref operator[](const typename object_t::key_type&) for unchecked\n    access by reference\n\n    @since version 1.0.0\n    */\n    template<class ValueType, typename std::enable_if<\n                 std::is_convertible<basic_json_t, ValueType>::value, int>::type = 0>\n    ValueType value(const typename object_t::key_type& key, const ValueType& default_value) const\n    {\n        // at only works for objects\n        if (JSON_LIKELY(is_object()))\n        {\n            // if key is found, return value and given default value otherwise\n            const auto it = find(key);\n            if (it != end())\n            {\n                return *it;\n            }\n\n            return default_value;\n        }\n\n        JSON_THROW(type_error::create(306, \"cannot use value() with \" + std::string(type_name())));\n    }\n\n    /*!\n    @brief overload for a default value of type const char*\n    @copydoc basic_json::value(const typename object_t::key_type&, const ValueType&) const\n    */\n    string_t value(const typename object_t::key_type& key, const char* default_value) const\n    {\n        return value(key, string_t(default_value));\n    }\n\n    /*!\n    @brief access specified object element via JSON Pointer with default value\n\n    Returns either a copy of an object's element at the specified key @a key\n    or a given default value if no element with key @a key exists.\n\n    The function is basically equivalent to executing\n    @code {.cpp}\n    try {\n        return at(ptr);\n    } catch(out_of_range) {\n        return default_value;\n    }\n    @endcode\n\n    @note Unlike @ref at(const json_pointer&), this function does not throw\n    if the given key @a key was not found.\n\n    @param[in] ptr  a JSON pointer to the element to access\n    @param[in] default_value  the value to return if @a ptr found no value\n\n    @tparam ValueType type compatible to JSON values, for instance `int` for\n    JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for\n    JSON arrays. Note the type of the expected value at @a key and the default\n    value @a default_value must be compatible.\n\n    @return copy of the element at key @a key or @a default_value if @a key\n    is not found\n\n    @throw type_error.306 if the JSON value is not an object; in that case,\n    using `value()` with a key makes no sense.\n\n    @complexity Logarithmic in the size of the container.\n\n    @liveexample{The example below shows how object elements can be queried\n    with a default value.,basic_json__value_ptr}\n\n    @sa @ref operator[](const json_pointer&) for unchecked access by reference\n\n    @since version 2.0.2\n    */\n    template<class ValueType, typename std::enable_if<\n                 std::is_convertible<basic_json_t, ValueType>::value, int>::type = 0>\n    ValueType value(const json_pointer& ptr, const ValueType& default_value) const\n    {\n        // at only works for objects\n        if (JSON_LIKELY(is_object()))\n        {\n            // if pointer resolves a value, return it or use default value\n            JSON_TRY\n            {\n                return ptr.get_checked(this);\n            }\n            JSON_INTERNAL_CATCH (out_of_range&)\n            {\n                return default_value;\n            }\n        }\n\n        JSON_THROW(type_error::create(306, \"cannot use value() with \" + std::string(type_name())));\n    }\n\n    /*!\n    @brief overload for a default value of type const char*\n    @copydoc basic_json::value(const json_pointer&, ValueType) const\n    */\n    string_t value(const json_pointer& ptr, const char* default_value) const\n    {\n        return value(ptr, string_t(default_value));\n    }\n\n    /*!\n    @brief access the first element\n\n    Returns a reference to the first element in the container. For a JSON\n    container `c`, the expression `c.front()` is equivalent to `*c.begin()`.\n\n    @return In case of a structured type (array or object), a reference to the\n    first element is returned. In case of number, string, or boolean values, a\n    reference to the value is returned.\n\n    @complexity Constant.\n\n    @pre The JSON value must not be `null` (would throw `std::out_of_range`)\n    or an empty array or object (undefined behavior, **guarded by\n    assertions**).\n    @post The JSON value remains unchanged.\n\n    @throw invalid_iterator.214 when called on `null` value\n\n    @liveexample{The following code shows an example for `front()`.,front}\n\n    @sa @ref back() -- access the last element\n\n    @since version 1.0.0\n    */\n    reference front()\n    {\n        return *begin();\n    }\n\n    /*!\n    @copydoc basic_json::front()\n    */\n    const_reference front() const\n    {\n        return *cbegin();\n    }\n\n    /*!\n    @brief access the last element\n\n    Returns a reference to the last element in the container. For a JSON\n    container `c`, the expression `c.back()` is equivalent to\n    @code {.cpp}\n    auto tmp = c.end();\n    --tmp;\n    return *tmp;\n    @endcode\n\n    @return In case of a structured type (array or object), a reference to the\n    last element is returned. In case of number, string, or boolean values, a\n    reference to the value is returned.\n\n    @complexity Constant.\n\n    @pre The JSON value must not be `null` (would throw `std::out_of_range`)\n    or an empty array or object (undefined behavior, **guarded by\n    assertions**).\n    @post The JSON value remains unchanged.\n\n    @throw invalid_iterator.214 when called on a `null` value. See example\n    below.\n\n    @liveexample{The following code shows an example for `back()`.,back}\n\n    @sa @ref front() -- access the first element\n\n    @since version 1.0.0\n    */\n    reference back()\n    {\n        auto tmp = end();\n        --tmp;\n        return *tmp;\n    }\n\n    /*!\n    @copydoc basic_json::back()\n    */\n    const_reference back() const\n    {\n        auto tmp = cend();\n        --tmp;\n        return *tmp;\n    }\n\n    /*!\n    @brief remove element given an iterator\n\n    Removes the element specified by iterator @a pos. The iterator @a pos must\n    be valid and dereferenceable. Thus the `end()` iterator (which is valid,\n    but is not dereferenceable) cannot be used as a value for @a pos.\n\n    If called on a primitive type other than `null`, the resulting JSON value\n    will be `null`.\n\n    @param[in] pos iterator to the element to remove\n    @return Iterator following the last removed element. If the iterator @a\n    pos refers to the last element, the `end()` iterator is returned.\n\n    @tparam IteratorType an @ref iterator or @ref const_iterator\n\n    @post Invalidates iterators and references at or after the point of the\n    erase, including the `end()` iterator.\n\n    @throw type_error.307 if called on a `null` value; example: `\"cannot use\n    erase() with null\"`\n    @throw invalid_iterator.202 if called on an iterator which does not belong\n    to the current JSON value; example: `\"iterator does not fit current\n    value\"`\n    @throw invalid_iterator.205 if called on a primitive type with invalid\n    iterator (i.e., any iterator which is not `begin()`); example: `\"iterator\n    out of range\"`\n\n    @complexity The complexity depends on the type:\n    - objects: amortized constant\n    - arrays: linear in distance between @a pos and the end of the container\n    - strings: linear in the length of the string\n    - other types: constant\n\n    @liveexample{The example shows the result of `erase()` for different JSON\n    types.,erase__IteratorType}\n\n    @sa @ref erase(IteratorType, IteratorType) -- removes the elements in\n    the given range\n    @sa @ref erase(const typename object_t::key_type&) -- removes the element\n    from an object at the given key\n    @sa @ref erase(const size_type) -- removes the element from an array at\n    the given index\n\n    @since version 1.0.0\n    */\n    template<class IteratorType, typename std::enable_if<\n                 std::is_same<IteratorType, typename basic_json_t::iterator>::value or\n                 std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int>::type\n             = 0>\n    IteratorType erase(IteratorType pos)\n    {\n        // make sure iterator fits the current value\n        if (JSON_UNLIKELY(this != pos.m_object))\n        {\n            JSON_THROW(invalid_iterator::create(202, \"iterator does not fit current value\"));\n        }\n\n        IteratorType result = end();\n\n        switch (m_type)\n        {\n            case value_t::boolean:\n            case value_t::number_float:\n            case value_t::number_integer:\n            case value_t::number_unsigned:\n            case value_t::string:\n            {\n                if (JSON_UNLIKELY(not pos.m_it.primitive_iterator.is_begin()))\n                {\n                    JSON_THROW(invalid_iterator::create(205, \"iterator out of range\"));\n                }\n\n                if (is_string())\n                {\n                    AllocatorType<string_t> alloc;\n                    std::allocator_traits<decltype(alloc)>::destroy(alloc, m_value.string);\n                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_value.string, 1);\n                    m_value.string = nullptr;\n                }\n\n                m_type = value_t::null;\n                assert_invariant();\n                break;\n            }\n\n            case value_t::object:\n            {\n                result.m_it.object_iterator = m_value.object->erase(pos.m_it.object_iterator);\n                break;\n            }\n\n            case value_t::array:\n            {\n                result.m_it.array_iterator = m_value.array->erase(pos.m_it.array_iterator);\n                break;\n            }\n\n            default:\n                JSON_THROW(type_error::create(307, \"cannot use erase() with \" + std::string(type_name())));\n        }\n\n        return result;\n    }\n\n    /*!\n    @brief remove elements given an iterator range\n\n    Removes the element specified by the range `[first; last)`. The iterator\n    @a first does not need to be dereferenceable if `first == last`: erasing\n    an empty range is a no-op.\n\n    If called on a primitive type other than `null`, the resulting JSON value\n    will be `null`.\n\n    @param[in] first iterator to the beginning of the range to remove\n    @param[in] last iterator past the end of the range to remove\n    @return Iterator following the last removed element. If the iterator @a\n    second refers to the last element, the `end()` iterator is returned.\n\n    @tparam IteratorType an @ref iterator or @ref const_iterator\n\n    @post Invalidates iterators and references at or after the point of the\n    erase, including the `end()` iterator.\n\n    @throw type_error.307 if called on a `null` value; example: `\"cannot use\n    erase() with null\"`\n    @throw invalid_iterator.203 if called on iterators which does not belong\n    to the current JSON value; example: `\"iterators do not fit current value\"`\n    @throw invalid_iterator.204 if called on a primitive type with invalid\n    iterators (i.e., if `first != begin()` and `last != end()`); example:\n    `\"iterators out of range\"`\n\n    @complexity The complexity depends on the type:\n    - objects: `log(size()) + std::distance(first, last)`\n    - arrays: linear in the distance between @a first and @a last, plus linear\n      in the distance between @a last and end of the container\n    - strings: linear in the length of the string\n    - other types: constant\n\n    @liveexample{The example shows the result of `erase()` for different JSON\n    types.,erase__IteratorType_IteratorType}\n\n    @sa @ref erase(IteratorType) -- removes the element at a given position\n    @sa @ref erase(const typename object_t::key_type&) -- removes the element\n    from an object at the given key\n    @sa @ref erase(const size_type) -- removes the element from an array at\n    the given index\n\n    @since version 1.0.0\n    */\n    template<class IteratorType, typename std::enable_if<\n                 std::is_same<IteratorType, typename basic_json_t::iterator>::value or\n                 std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int>::type\n             = 0>\n    IteratorType erase(IteratorType first, IteratorType last)\n    {\n        // make sure iterator fits the current value\n        if (JSON_UNLIKELY(this != first.m_object or this != last.m_object))\n        {\n            JSON_THROW(invalid_iterator::create(203, \"iterators do not fit current value\"));\n        }\n\n        IteratorType result = end();\n\n        switch (m_type)\n        {\n            case value_t::boolean:\n            case value_t::number_float:\n            case value_t::number_integer:\n            case value_t::number_unsigned:\n            case value_t::string:\n            {\n                if (JSON_LIKELY(not first.m_it.primitive_iterator.is_begin()\n                                or not last.m_it.primitive_iterator.is_end()))\n                {\n                    JSON_THROW(invalid_iterator::create(204, \"iterators out of range\"));\n                }\n\n                if (is_string())\n                {\n                    AllocatorType<string_t> alloc;\n                    std::allocator_traits<decltype(alloc)>::destroy(alloc, m_value.string);\n                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_value.string, 1);\n                    m_value.string = nullptr;\n                }\n\n                m_type = value_t::null;\n                assert_invariant();\n                break;\n            }\n\n            case value_t::object:\n            {\n                result.m_it.object_iterator = m_value.object->erase(first.m_it.object_iterator,\n                                              last.m_it.object_iterator);\n                break;\n            }\n\n            case value_t::array:\n            {\n                result.m_it.array_iterator = m_value.array->erase(first.m_it.array_iterator,\n                                             last.m_it.array_iterator);\n                break;\n            }\n\n            default:\n                JSON_THROW(type_error::create(307, \"cannot use erase() with \" + std::string(type_name())));\n        }\n\n        return result;\n    }\n\n    /*!\n    @brief remove element from a JSON object given a key\n\n    Removes elements from a JSON object with the key value @a key.\n\n    @param[in] key value of the elements to remove\n\n    @return Number of elements removed. If @a ObjectType is the default\n    `std::map` type, the return value will always be `0` (@a key was not\n    found) or `1` (@a key was found).\n\n    @post References and iterators to the erased elements are invalidated.\n    Other references and iterators are not affected.\n\n    @throw type_error.307 when called on a type other than JSON object;\n    example: `\"cannot use erase() with null\"`\n\n    @complexity `log(size()) + count(key)`\n\n    @liveexample{The example shows the effect of `erase()`.,erase__key_type}\n\n    @sa @ref erase(IteratorType) -- removes the element at a given position\n    @sa @ref erase(IteratorType, IteratorType) -- removes the elements in\n    the given range\n    @sa @ref erase(const size_type) -- removes the element from an array at\n    the given index\n\n    @since version 1.0.0\n    */\n    size_type erase(const typename object_t::key_type& key)\n    {\n        // this erase only works for objects\n        if (JSON_LIKELY(is_object()))\n        {\n            return m_value.object->erase(key);\n        }\n\n        JSON_THROW(type_error::create(307, \"cannot use erase() with \" + std::string(type_name())));\n    }\n\n    /*!\n    @brief remove element from a JSON array given an index\n\n    Removes element from a JSON array at the index @a idx.\n\n    @param[in] idx index of the element to remove\n\n    @throw type_error.307 when called on a type other than JSON object;\n    example: `\"cannot use erase() with null\"`\n    @throw out_of_range.401 when `idx >= size()`; example: `\"array index 17\n    is out of range\"`\n\n    @complexity Linear in distance between @a idx and the end of the container.\n\n    @liveexample{The example shows the effect of `erase()`.,erase__size_type}\n\n    @sa @ref erase(IteratorType) -- removes the element at a given position\n    @sa @ref erase(IteratorType, IteratorType) -- removes the elements in\n    the given range\n    @sa @ref erase(const typename object_t::key_type&) -- removes the element\n    from an object at the given key\n\n    @since version 1.0.0\n    */\n    void erase(const size_type idx)\n    {\n        // this erase only works for arrays\n        if (JSON_LIKELY(is_array()))\n        {\n            if (JSON_UNLIKELY(idx >= size()))\n            {\n                JSON_THROW(out_of_range::create(401, \"array index \" + std::to_string(idx) + \" is out of range\"));\n            }\n\n            m_value.array->erase(m_value.array->begin() + static_cast<difference_type>(idx));\n        }\n        else\n        {\n            JSON_THROW(type_error::create(307, \"cannot use erase() with \" + std::string(type_name())));\n        }\n    }\n\n    /// @}\n\n\n    ////////////\n    // lookup //\n    ////////////\n\n    /// @name lookup\n    /// @{\n\n    /*!\n    @brief find an element in a JSON object\n\n    Finds an element in a JSON object with key equivalent to @a key. If the\n    element is not found or the JSON value is not an object, end() is\n    returned.\n\n    @note This method always returns @ref end() when executed on a JSON type\n          that is not an object.\n\n    @param[in] key key value of the element to search for.\n\n    @return Iterator to an element with key equivalent to @a key. If no such\n    element is found or the JSON value is not an object, past-the-end (see\n    @ref end()) iterator is returned.\n\n    @complexity Logarithmic in the size of the JSON object.\n\n    @liveexample{The example shows how `find()` is used.,find__key_type}\n\n    @since version 1.0.0\n    */\n    template<typename KeyT>\n    iterator find(KeyT&& key)\n    {\n        auto result = end();\n\n        if (is_object())\n        {\n            result.m_it.object_iterator = m_value.object->find(std::forward<KeyT>(key));\n        }\n\n        return result;\n    }\n\n    /*!\n    @brief find an element in a JSON object\n    @copydoc find(KeyT&&)\n    */\n    template<typename KeyT>\n    const_iterator find(KeyT&& key) const\n    {\n        auto result = cend();\n\n        if (is_object())\n        {\n            result.m_it.object_iterator = m_value.object->find(std::forward<KeyT>(key));\n        }\n\n        return result;\n    }\n\n    /*!\n    @brief returns the number of occurrences of a key in a JSON object\n\n    Returns the number of elements with key @a key. If ObjectType is the\n    default `std::map` type, the return value will always be `0` (@a key was\n    not found) or `1` (@a key was found).\n\n    @note This method always returns `0` when executed on a JSON type that is\n          not an object.\n\n    @param[in] key key value of the element to count\n\n    @return Number of elements with key @a key. If the JSON value is not an\n    object, the return value will be `0`.\n\n    @complexity Logarithmic in the size of the JSON object.\n\n    @liveexample{The example shows how `count()` is used.,count}\n\n    @since version 1.0.0\n    */\n    template<typename KeyT>\n    size_type count(KeyT&& key) const\n    {\n        // return 0 for all nonobject types\n        return is_object() ? m_value.object->count(std::forward<KeyT>(key)) : 0;\n    }\n\n    /// @}\n\n\n    ///////////////\n    // iterators //\n    ///////////////\n\n    /// @name iterators\n    /// @{\n\n    /*!\n    @brief returns an iterator to the first element\n\n    Returns an iterator to the first element.\n\n    @image html range-begin-end.svg \"Illustration from cppreference.com\"\n\n    @return iterator to the first element\n\n    @complexity Constant.\n\n    @requirement This function helps `basic_json` satisfying the\n    [Container](https://en.cppreference.com/w/cpp/named_req/Container)\n    requirements:\n    - The complexity is constant.\n\n    @liveexample{The following code shows an example for `begin()`.,begin}\n\n    @sa @ref cbegin() -- returns a const iterator to the beginning\n    @sa @ref end() -- returns an iterator to the end\n    @sa @ref cend() -- returns a const iterator to the end\n\n    @since version 1.0.0\n    */\n    iterator begin() noexcept\n    {\n        iterator result(this);\n        result.set_begin();\n        return result;\n    }\n\n    /*!\n    @copydoc basic_json::cbegin()\n    */\n    const_iterator begin() const noexcept\n    {\n        return cbegin();\n    }\n\n    /*!\n    @brief returns a const iterator to the first element\n\n    Returns a const iterator to the first element.\n\n    @image html range-begin-end.svg \"Illustration from cppreference.com\"\n\n    @return const iterator to the first element\n\n    @complexity Constant.\n\n    @requirement This function helps `basic_json` satisfying the\n    [Container](https://en.cppreference.com/w/cpp/named_req/Container)\n    requirements:\n    - The complexity is constant.\n    - Has the semantics of `const_cast<const basic_json&>(*this).begin()`.\n\n    @liveexample{The following code shows an example for `cbegin()`.,cbegin}\n\n    @sa @ref begin() -- returns an iterator to the beginning\n    @sa @ref end() -- returns an iterator to the end\n    @sa @ref cend() -- returns a const iterator to the end\n\n    @since version 1.0.0\n    */\n    const_iterator cbegin() const noexcept\n    {\n        const_iterator result(this);\n        result.set_begin();\n        return result;\n    }\n\n    /*!\n    @brief returns an iterator to one past the last element\n\n    Returns an iterator to one past the last element.\n\n    @image html range-begin-end.svg \"Illustration from cppreference.com\"\n\n    @return iterator one past the last element\n\n    @complexity Constant.\n\n    @requirement This function helps `basic_json` satisfying the\n    [Container](https://en.cppreference.com/w/cpp/named_req/Container)\n    requirements:\n    - The complexity is constant.\n\n    @liveexample{The following code shows an example for `end()`.,end}\n\n    @sa @ref cend() -- returns a const iterator to the end\n    @sa @ref begin() -- returns an iterator to the beginning\n    @sa @ref cbegin() -- returns a const iterator to the beginning\n\n    @since version 1.0.0\n    */\n    iterator end() noexcept\n    {\n        iterator result(this);\n        result.set_end();\n        return result;\n    }\n\n    /*!\n    @copydoc basic_json::cend()\n    */\n    const_iterator end() const noexcept\n    {\n        return cend();\n    }\n\n    /*!\n    @brief returns a const iterator to one past the last element\n\n    Returns a const iterator to one past the last element.\n\n    @image html range-begin-end.svg \"Illustration from cppreference.com\"\n\n    @return const iterator one past the last element\n\n    @complexity Constant.\n\n    @requirement This function helps `basic_json` satisfying the\n    [Container](https://en.cppreference.com/w/cpp/named_req/Container)\n    requirements:\n    - The complexity is constant.\n    - Has the semantics of `const_cast<const basic_json&>(*this).end()`.\n\n    @liveexample{The following code shows an example for `cend()`.,cend}\n\n    @sa @ref end() -- returns an iterator to the end\n    @sa @ref begin() -- returns an iterator to the beginning\n    @sa @ref cbegin() -- returns a const iterator to the beginning\n\n    @since version 1.0.0\n    */\n    const_iterator cend() const noexcept\n    {\n        const_iterator result(this);\n        result.set_end();\n        return result;\n    }\n\n    /*!\n    @brief returns an iterator to the reverse-beginning\n\n    Returns an iterator to the reverse-beginning; that is, the last element.\n\n    @image html range-rbegin-rend.svg \"Illustration from cppreference.com\"\n\n    @complexity Constant.\n\n    @requirement This function helps `basic_json` satisfying the\n    [ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer)\n    requirements:\n    - The complexity is constant.\n    - Has the semantics of `reverse_iterator(end())`.\n\n    @liveexample{The following code shows an example for `rbegin()`.,rbegin}\n\n    @sa @ref crbegin() -- returns a const reverse iterator to the beginning\n    @sa @ref rend() -- returns a reverse iterator to the end\n    @sa @ref crend() -- returns a const reverse iterator to the end\n\n    @since version 1.0.0\n    */\n    reverse_iterator rbegin() noexcept\n    {\n        return reverse_iterator(end());\n    }\n\n    /*!\n    @copydoc basic_json::crbegin()\n    */\n    const_reverse_iterator rbegin() const noexcept\n    {\n        return crbegin();\n    }\n\n    /*!\n    @brief returns an iterator to the reverse-end\n\n    Returns an iterator to the reverse-end; that is, one before the first\n    element.\n\n    @image html range-rbegin-rend.svg \"Illustration from cppreference.com\"\n\n    @complexity Constant.\n\n    @requirement This function helps `basic_json` satisfying the\n    [ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer)\n    requirements:\n    - The complexity is constant.\n    - Has the semantics of `reverse_iterator(begin())`.\n\n    @liveexample{The following code shows an example for `rend()`.,rend}\n\n    @sa @ref crend() -- returns a const reverse iterator to the end\n    @sa @ref rbegin() -- returns a reverse iterator to the beginning\n    @sa @ref crbegin() -- returns a const reverse iterator to the beginning\n\n    @since version 1.0.0\n    */\n    reverse_iterator rend() noexcept\n    {\n        return reverse_iterator(begin());\n    }\n\n    /*!\n    @copydoc basic_json::crend()\n    */\n    const_reverse_iterator rend() const noexcept\n    {\n        return crend();\n    }\n\n    /*!\n    @brief returns a const reverse iterator to the last element\n\n    Returns a const iterator to the reverse-beginning; that is, the last\n    element.\n\n    @image html range-rbegin-rend.svg \"Illustration from cppreference.com\"\n\n    @complexity Constant.\n\n    @requirement This function helps `basic_json` satisfying the\n    [ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer)\n    requirements:\n    - The complexity is constant.\n    - Has the semantics of `const_cast<const basic_json&>(*this).rbegin()`.\n\n    @liveexample{The following code shows an example for `crbegin()`.,crbegin}\n\n    @sa @ref rbegin() -- returns a reverse iterator to the beginning\n    @sa @ref rend() -- returns a reverse iterator to the end\n    @sa @ref crend() -- returns a const reverse iterator to the end\n\n    @since version 1.0.0\n    */\n    const_reverse_iterator crbegin() const noexcept\n    {\n        return const_reverse_iterator(cend());\n    }\n\n    /*!\n    @brief returns a const reverse iterator to one before the first\n\n    Returns a const reverse iterator to the reverse-end; that is, one before\n    the first element.\n\n    @image html range-rbegin-rend.svg \"Illustration from cppreference.com\"\n\n    @complexity Constant.\n\n    @requirement This function helps `basic_json` satisfying the\n    [ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer)\n    requirements:\n    - The complexity is constant.\n    - Has the semantics of `const_cast<const basic_json&>(*this).rend()`.\n\n    @liveexample{The following code shows an example for `crend()`.,crend}\n\n    @sa @ref rend() -- returns a reverse iterator to the end\n    @sa @ref rbegin() -- returns a reverse iterator to the beginning\n    @sa @ref crbegin() -- returns a const reverse iterator to the beginning\n\n    @since version 1.0.0\n    */\n    const_reverse_iterator crend() const noexcept\n    {\n        return const_reverse_iterator(cbegin());\n    }\n\n  public:\n    /*!\n    @brief wrapper to access iterator member functions in range-based for\n\n    This function allows to access @ref iterator::key() and @ref\n    iterator::value() during range-based for loops. In these loops, a\n    reference to the JSON values is returned, so there is no access to the\n    underlying iterator.\n\n    For loop without iterator_wrapper:\n\n    @code{cpp}\n    for (auto it = j_object.begin(); it != j_object.end(); ++it)\n    {\n        std::cout << \"key: \" << it.key() << \", value:\" << it.value() << '\\n';\n    }\n    @endcode\n\n    Range-based for loop without iterator proxy:\n\n    @code{cpp}\n    for (auto it : j_object)\n    {\n        // \"it\" is of type json::reference and has no key() member\n        std::cout << \"value: \" << it << '\\n';\n    }\n    @endcode\n\n    Range-based for loop with iterator proxy:\n\n    @code{cpp}\n    for (auto it : json::iterator_wrapper(j_object))\n    {\n        std::cout << \"key: \" << it.key() << \", value:\" << it.value() << '\\n';\n    }\n    @endcode\n\n    @note When iterating over an array, `key()` will return the index of the\n          element as string (see example).\n\n    @param[in] ref  reference to a JSON value\n    @return iteration proxy object wrapping @a ref with an interface to use in\n            range-based for loops\n\n    @liveexample{The following code shows how the wrapper is used,iterator_wrapper}\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes in the JSON value.\n\n    @complexity Constant.\n\n    @note The name of this function is not yet final and may change in the\n    future.\n\n    @deprecated This stream operator is deprecated and will be removed in\n                future 4.0.0 of the library. Please use @ref items() instead;\n                that is, replace `json::iterator_wrapper(j)` with `j.items()`.\n    */\n    JSON_DEPRECATED\n    static iteration_proxy<iterator> iterator_wrapper(reference ref) noexcept\n    {\n        return ref.items();\n    }\n\n    /*!\n    @copydoc iterator_wrapper(reference)\n    */\n    JSON_DEPRECATED\n    static iteration_proxy<const_iterator> iterator_wrapper(const_reference ref) noexcept\n    {\n        return ref.items();\n    }\n\n    /*!\n    @brief helper to access iterator member functions in range-based for\n\n    This function allows to access @ref iterator::key() and @ref\n    iterator::value() during range-based for loops. In these loops, a\n    reference to the JSON values is returned, so there is no access to the\n    underlying iterator.\n\n    For loop without `items()` function:\n\n    @code{cpp}\n    for (auto it = j_object.begin(); it != j_object.end(); ++it)\n    {\n        std::cout << \"key: \" << it.key() << \", value:\" << it.value() << '\\n';\n    }\n    @endcode\n\n    Range-based for loop without `items()` function:\n\n    @code{cpp}\n    for (auto it : j_object)\n    {\n        // \"it\" is of type json::reference and has no key() member\n        std::cout << \"value: \" << it << '\\n';\n    }\n    @endcode\n\n    Range-based for loop with `items()` function:\n\n    @code{cpp}\n    for (auto& el : j_object.items())\n    {\n        std::cout << \"key: \" << el.key() << \", value:\" << el.value() << '\\n';\n    }\n    @endcode\n\n    The `items()` function also allows to use\n    [structured bindings](https://en.cppreference.com/w/cpp/language/structured_binding)\n    (C++17):\n\n    @code{cpp}\n    for (auto& [key, val] : j_object.items())\n    {\n        std::cout << \"key: \" << key << \", value:\" << val << '\\n';\n    }\n    @endcode\n\n    @note When iterating over an array, `key()` will return the index of the\n          element as string (see example). For primitive types (e.g., numbers),\n          `key()` returns an empty string.\n\n    @return iteration proxy object wrapping @a ref with an interface to use in\n            range-based for loops\n\n    @liveexample{The following code shows how the function is used.,items}\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes in the JSON value.\n\n    @complexity Constant.\n\n    @since version 3.1.0, structured bindings support since 3.5.0.\n    */\n    iteration_proxy<iterator> items() noexcept\n    {\n        return iteration_proxy<iterator>(*this);\n    }\n\n    /*!\n    @copydoc items()\n    */\n    iteration_proxy<const_iterator> items() const noexcept\n    {\n        return iteration_proxy<const_iterator>(*this);\n    }\n\n    /// @}\n\n\n    //////////////\n    // capacity //\n    //////////////\n\n    /// @name capacity\n    /// @{\n\n    /*!\n    @brief checks whether the container is empty.\n\n    Checks if a JSON value has no elements (i.e. whether its @ref size is `0`).\n\n    @return The return value depends on the different types and is\n            defined as follows:\n            Value type  | return value\n            ----------- | -------------\n            null        | `true`\n            boolean     | `false`\n            string      | `false`\n            number      | `false`\n            object      | result of function `object_t::empty()`\n            array       | result of function `array_t::empty()`\n\n    @liveexample{The following code uses `empty()` to check if a JSON\n    object contains any elements.,empty}\n\n    @complexity Constant, as long as @ref array_t and @ref object_t satisfy\n    the Container concept; that is, their `empty()` functions have constant\n    complexity.\n\n    @iterators No changes.\n\n    @exceptionsafety No-throw guarantee: this function never throws exceptions.\n\n    @note This function does not return whether a string stored as JSON value\n    is empty - it returns whether the JSON container itself is empty which is\n    false in the case of a string.\n\n    @requirement This function helps `basic_json` satisfying the\n    [Container](https://en.cppreference.com/w/cpp/named_req/Container)\n    requirements:\n    - The complexity is constant.\n    - Has the semantics of `begin() == end()`.\n\n    @sa @ref size() -- returns the number of elements\n\n    @since version 1.0.0\n    */\n    bool empty() const noexcept\n    {\n        switch (m_type)\n        {\n            case value_t::null:\n            {\n                // null values are empty\n                return true;\n            }\n\n            case value_t::array:\n            {\n                // delegate call to array_t::empty()\n                return m_value.array->empty();\n            }\n\n            case value_t::object:\n            {\n                // delegate call to object_t::empty()\n                return m_value.object->empty();\n            }\n\n            default:\n            {\n                // all other types are nonempty\n                return false;\n            }\n        }\n    }\n\n    /*!\n    @brief returns the number of elements\n\n    Returns the number of elements in a JSON value.\n\n    @return The return value depends on the different types and is\n            defined as follows:\n            Value type  | return value\n            ----------- | -------------\n            null        | `0`\n            boolean     | `1`\n            string      | `1`\n            number      | `1`\n            object      | result of function object_t::size()\n            array       | result of function array_t::size()\n\n    @liveexample{The following code calls `size()` on the different value\n    types.,size}\n\n    @complexity Constant, as long as @ref array_t and @ref object_t satisfy\n    the Container concept; that is, their size() functions have constant\n    complexity.\n\n    @iterators No changes.\n\n    @exceptionsafety No-throw guarantee: this function never throws exceptions.\n\n    @note This function does not return the length of a string stored as JSON\n    value - it returns the number of elements in the JSON value which is 1 in\n    the case of a string.\n\n    @requirement This function helps `basic_json` satisfying the\n    [Container](https://en.cppreference.com/w/cpp/named_req/Container)\n    requirements:\n    - The complexity is constant.\n    - Has the semantics of `std::distance(begin(), end())`.\n\n    @sa @ref empty() -- checks whether the container is empty\n    @sa @ref max_size() -- returns the maximal number of elements\n\n    @since version 1.0.0\n    */\n    size_type size() const noexcept\n    {\n        switch (m_type)\n        {\n            case value_t::null:\n            {\n                // null values are empty\n                return 0;\n            }\n\n            case value_t::array:\n            {\n                // delegate call to array_t::size()\n                return m_value.array->size();\n            }\n\n            case value_t::object:\n            {\n                // delegate call to object_t::size()\n                return m_value.object->size();\n            }\n\n            default:\n            {\n                // all other types have size 1\n                return 1;\n            }\n        }\n    }\n\n    /*!\n    @brief returns the maximum possible number of elements\n\n    Returns the maximum number of elements a JSON value is able to hold due to\n    system or library implementation limitations, i.e. `std::distance(begin(),\n    end())` for the JSON value.\n\n    @return The return value depends on the different types and is\n            defined as follows:\n            Value type  | return value\n            ----------- | -------------\n            null        | `0` (same as `size()`)\n            boolean     | `1` (same as `size()`)\n            string      | `1` (same as `size()`)\n            number      | `1` (same as `size()`)\n            object      | result of function `object_t::max_size()`\n            array       | result of function `array_t::max_size()`\n\n    @liveexample{The following code calls `max_size()` on the different value\n    types. Note the output is implementation specific.,max_size}\n\n    @complexity Constant, as long as @ref array_t and @ref object_t satisfy\n    the Container concept; that is, their `max_size()` functions have constant\n    complexity.\n\n    @iterators No changes.\n\n    @exceptionsafety No-throw guarantee: this function never throws exceptions.\n\n    @requirement This function helps `basic_json` satisfying the\n    [Container](https://en.cppreference.com/w/cpp/named_req/Container)\n    requirements:\n    - The complexity is constant.\n    - Has the semantics of returning `b.size()` where `b` is the largest\n      possible JSON value.\n\n    @sa @ref size() -- returns the number of elements\n\n    @since version 1.0.0\n    */\n    size_type max_size() const noexcept\n    {\n        switch (m_type)\n        {\n            case value_t::array:\n            {\n                // delegate call to array_t::max_size()\n                return m_value.array->max_size();\n            }\n\n            case value_t::object:\n            {\n                // delegate call to object_t::max_size()\n                return m_value.object->max_size();\n            }\n\n            default:\n            {\n                // all other types have max_size() == size()\n                return size();\n            }\n        }\n    }\n\n    /// @}\n\n\n    ///////////////\n    // modifiers //\n    ///////////////\n\n    /// @name modifiers\n    /// @{\n\n    /*!\n    @brief clears the contents\n\n    Clears the content of a JSON value and resets it to the default value as\n    if @ref basic_json(value_t) would have been called with the current value\n    type from @ref type():\n\n    Value type  | initial value\n    ----------- | -------------\n    null        | `null`\n    boolean     | `false`\n    string      | `\"\"`\n    number      | `0`\n    object      | `{}`\n    array       | `[]`\n\n    @post Has the same effect as calling\n    @code {.cpp}\n    *this = basic_json(type());\n    @endcode\n\n    @liveexample{The example below shows the effect of `clear()` to different\n    JSON types.,clear}\n\n    @complexity Linear in the size of the JSON value.\n\n    @iterators All iterators, pointers and references related to this container\n               are invalidated.\n\n    @exceptionsafety No-throw guarantee: this function never throws exceptions.\n\n    @sa @ref basic_json(value_t) -- constructor that creates an object with the\n        same value than calling `clear()`\n\n    @since version 1.0.0\n    */\n    void clear() noexcept\n    {\n        switch (m_type)\n        {\n            case value_t::number_integer:\n            {\n                m_value.number_integer = 0;\n                break;\n            }\n\n            case value_t::number_unsigned:\n            {\n                m_value.number_unsigned = 0;\n                break;\n            }\n\n            case value_t::number_float:\n            {\n                m_value.number_float = 0.0;\n                break;\n            }\n\n            case value_t::boolean:\n            {\n                m_value.boolean = false;\n                break;\n            }\n\n            case value_t::string:\n            {\n                m_value.string->clear();\n                break;\n            }\n\n            case value_t::array:\n            {\n                m_value.array->clear();\n                break;\n            }\n\n            case value_t::object:\n            {\n                m_value.object->clear();\n                break;\n            }\n\n            default:\n                break;\n        }\n    }\n\n    /*!\n    @brief add an object to an array\n\n    Appends the given element @a val to the end of the JSON value. If the\n    function is called on a JSON null value, an empty array is created before\n    appending @a val.\n\n    @param[in] val the value to add to the JSON array\n\n    @throw type_error.308 when called on a type other than JSON array or\n    null; example: `\"cannot use push_back() with number\"`\n\n    @complexity Amortized constant.\n\n    @liveexample{The example shows how `push_back()` and `+=` can be used to\n    add elements to a JSON array. Note how the `null` value was silently\n    converted to a JSON array.,push_back}\n\n    @since version 1.0.0\n    */\n    void push_back(basic_json&& val)\n    {\n        // push_back only works for null objects or arrays\n        if (JSON_UNLIKELY(not(is_null() or is_array())))\n        {\n            JSON_THROW(type_error::create(308, \"cannot use push_back() with \" + std::string(type_name())));\n        }\n\n        // transform null object into an array\n        if (is_null())\n        {\n            m_type = value_t::array;\n            m_value = value_t::array;\n            assert_invariant();\n        }\n\n        // add element to array (move semantics)\n        m_value.array->push_back(std::move(val));\n        // invalidate object\n        val.m_type = value_t::null;\n    }\n\n    /*!\n    @brief add an object to an array\n    @copydoc push_back(basic_json&&)\n    */\n    reference operator+=(basic_json&& val)\n    {\n        push_back(std::move(val));\n        return *this;\n    }\n\n    /*!\n    @brief add an object to an array\n    @copydoc push_back(basic_json&&)\n    */\n    void push_back(const basic_json& val)\n    {\n        // push_back only works for null objects or arrays\n        if (JSON_UNLIKELY(not(is_null() or is_array())))\n        {\n            JSON_THROW(type_error::create(308, \"cannot use push_back() with \" + std::string(type_name())));\n        }\n\n        // transform null object into an array\n        if (is_null())\n        {\n            m_type = value_t::array;\n            m_value = value_t::array;\n            assert_invariant();\n        }\n\n        // add element to array\n        m_value.array->push_back(val);\n    }\n\n    /*!\n    @brief add an object to an array\n    @copydoc push_back(basic_json&&)\n    */\n    reference operator+=(const basic_json& val)\n    {\n        push_back(val);\n        return *this;\n    }\n\n    /*!\n    @brief add an object to an object\n\n    Inserts the given element @a val to the JSON object. If the function is\n    called on a JSON null value, an empty object is created before inserting\n    @a val.\n\n    @param[in] val the value to add to the JSON object\n\n    @throw type_error.308 when called on a type other than JSON object or\n    null; example: `\"cannot use push_back() with number\"`\n\n    @complexity Logarithmic in the size of the container, O(log(`size()`)).\n\n    @liveexample{The example shows how `push_back()` and `+=` can be used to\n    add elements to a JSON object. Note how the `null` value was silently\n    converted to a JSON object.,push_back__object_t__value}\n\n    @since version 1.0.0\n    */\n    void push_back(const typename object_t::value_type& val)\n    {\n        // push_back only works for null objects or objects\n        if (JSON_UNLIKELY(not(is_null() or is_object())))\n        {\n            JSON_THROW(type_error::create(308, \"cannot use push_back() with \" + std::string(type_name())));\n        }\n\n        // transform null object into an object\n        if (is_null())\n        {\n            m_type = value_t::object;\n            m_value = value_t::object;\n            assert_invariant();\n        }\n\n        // add element to array\n        m_value.object->insert(val);\n    }\n\n    /*!\n    @brief add an object to an object\n    @copydoc push_back(const typename object_t::value_type&)\n    */\n    reference operator+=(const typename object_t::value_type& val)\n    {\n        push_back(val);\n        return *this;\n    }\n\n    /*!\n    @brief add an object to an object\n\n    This function allows to use `push_back` with an initializer list. In case\n\n    1. the current value is an object,\n    2. the initializer list @a init contains only two elements, and\n    3. the first element of @a init is a string,\n\n    @a init is converted into an object element and added using\n    @ref push_back(const typename object_t::value_type&). Otherwise, @a init\n    is converted to a JSON value and added using @ref push_back(basic_json&&).\n\n    @param[in] init  an initializer list\n\n    @complexity Linear in the size of the initializer list @a init.\n\n    @note This function is required to resolve an ambiguous overload error,\n          because pairs like `{\"key\", \"value\"}` can be both interpreted as\n          `object_t::value_type` or `std::initializer_list<basic_json>`, see\n          https://github.com/nlohmann/json/issues/235 for more information.\n\n    @liveexample{The example shows how initializer lists are treated as\n    objects when possible.,push_back__initializer_list}\n    */\n    void push_back(initializer_list_t init)\n    {\n        if (is_object() and init.size() == 2 and (*init.begin())->is_string())\n        {\n            basic_json&& key = init.begin()->moved_or_copied();\n            push_back(typename object_t::value_type(\n                          std::move(key.get_ref<string_t&>()), (init.begin() + 1)->moved_or_copied()));\n        }\n        else\n        {\n            push_back(basic_json(init));\n        }\n    }\n\n    /*!\n    @brief add an object to an object\n    @copydoc push_back(initializer_list_t)\n    */\n    reference operator+=(initializer_list_t init)\n    {\n        push_back(init);\n        return *this;\n    }\n\n    /*!\n    @brief add an object to an array\n\n    Creates a JSON value from the passed parameters @a args to the end of the\n    JSON value. If the function is called on a JSON null value, an empty array\n    is created before appending the value created from @a args.\n\n    @param[in] args arguments to forward to a constructor of @ref basic_json\n    @tparam Args compatible types to create a @ref basic_json object\n\n    @throw type_error.311 when called on a type other than JSON array or\n    null; example: `\"cannot use emplace_back() with number\"`\n\n    @complexity Amortized constant.\n\n    @liveexample{The example shows how `push_back()` can be used to add\n    elements to a JSON array. Note how the `null` value was silently converted\n    to a JSON array.,emplace_back}\n\n    @since version 2.0.8\n    */\n    template<class... Args>\n    void emplace_back(Args&& ... args)\n    {\n        // emplace_back only works for null objects or arrays\n        if (JSON_UNLIKELY(not(is_null() or is_array())))\n        {\n            JSON_THROW(type_error::create(311, \"cannot use emplace_back() with \" + std::string(type_name())));\n        }\n\n        // transform null object into an array\n        if (is_null())\n        {\n            m_type = value_t::array;\n            m_value = value_t::array;\n            assert_invariant();\n        }\n\n        // add element to array (perfect forwarding)\n        m_value.array->emplace_back(std::forward<Args>(args)...);\n    }\n\n    /*!\n    @brief add an object to an object if key does not exist\n\n    Inserts a new element into a JSON object constructed in-place with the\n    given @a args if there is no element with the key in the container. If the\n    function is called on a JSON null value, an empty object is created before\n    appending the value created from @a args.\n\n    @param[in] args arguments to forward to a constructor of @ref basic_json\n    @tparam Args compatible types to create a @ref basic_json object\n\n    @return a pair consisting of an iterator to the inserted element, or the\n            already-existing element if no insertion happened, and a bool\n            denoting whether the insertion took place.\n\n    @throw type_error.311 when called on a type other than JSON object or\n    null; example: `\"cannot use emplace() with number\"`\n\n    @complexity Logarithmic in the size of the container, O(log(`size()`)).\n\n    @liveexample{The example shows how `emplace()` can be used to add elements\n    to a JSON object. Note how the `null` value was silently converted to a\n    JSON object. Further note how no value is added if there was already one\n    value stored with the same key.,emplace}\n\n    @since version 2.0.8\n    */\n    template<class... Args>\n    std::pair<iterator, bool> emplace(Args&& ... args)\n    {\n        // emplace only works for null objects or arrays\n        if (JSON_UNLIKELY(not(is_null() or is_object())))\n        {\n            JSON_THROW(type_error::create(311, \"cannot use emplace() with \" + std::string(type_name())));\n        }\n\n        // transform null object into an object\n        if (is_null())\n        {\n            m_type = value_t::object;\n            m_value = value_t::object;\n            assert_invariant();\n        }\n\n        // add element to array (perfect forwarding)\n        auto res = m_value.object->emplace(std::forward<Args>(args)...);\n        // create result iterator and set iterator to the result of emplace\n        auto it = begin();\n        it.m_it.object_iterator = res.first;\n\n        // return pair of iterator and boolean\n        return {it, res.second};\n    }\n\n    /// Helper for insertion of an iterator\n    /// @note: This uses std::distance to support GCC 4.8,\n    ///        see https://github.com/nlohmann/json/pull/1257\n    template<typename... Args>\n    iterator insert_iterator(const_iterator pos, Args&& ... args)\n    {\n        iterator result(this);\n        assert(m_value.array != nullptr);\n\n        auto insert_pos = std::distance(m_value.array->begin(), pos.m_it.array_iterator);\n        m_value.array->insert(pos.m_it.array_iterator, std::forward<Args>(args)...);\n        result.m_it.array_iterator = m_value.array->begin() + insert_pos;\n\n        // This could have been written as:\n        // result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val);\n        // but the return value of insert is missing in GCC 4.8, so it is written this way instead.\n\n        return result;\n    }\n\n    /*!\n    @brief inserts element\n\n    Inserts element @a val before iterator @a pos.\n\n    @param[in] pos iterator before which the content will be inserted; may be\n    the end() iterator\n    @param[in] val element to insert\n    @return iterator pointing to the inserted @a val.\n\n    @throw type_error.309 if called on JSON values other than arrays;\n    example: `\"cannot use insert() with string\"`\n    @throw invalid_iterator.202 if @a pos is not an iterator of *this;\n    example: `\"iterator does not fit current value\"`\n\n    @complexity Constant plus linear in the distance between @a pos and end of\n    the container.\n\n    @liveexample{The example shows how `insert()` is used.,insert}\n\n    @since version 1.0.0\n    */\n    iterator insert(const_iterator pos, const basic_json& val)\n    {\n        // insert only works for arrays\n        if (JSON_LIKELY(is_array()))\n        {\n            // check if iterator pos fits to this JSON value\n            if (JSON_UNLIKELY(pos.m_object != this))\n            {\n                JSON_THROW(invalid_iterator::create(202, \"iterator does not fit current value\"));\n            }\n\n            // insert to array and return iterator\n            return insert_iterator(pos, val);\n        }\n\n        JSON_THROW(type_error::create(309, \"cannot use insert() with \" + std::string(type_name())));\n    }\n\n    /*!\n    @brief inserts element\n    @copydoc insert(const_iterator, const basic_json&)\n    */\n    iterator insert(const_iterator pos, basic_json&& val)\n    {\n        return insert(pos, val);\n    }\n\n    /*!\n    @brief inserts elements\n\n    Inserts @a cnt copies of @a val before iterator @a pos.\n\n    @param[in] pos iterator before which the content will be inserted; may be\n    the end() iterator\n    @param[in] cnt number of copies of @a val to insert\n    @param[in] val element to insert\n    @return iterator pointing to the first element inserted, or @a pos if\n    `cnt==0`\n\n    @throw type_error.309 if called on JSON values other than arrays; example:\n    `\"cannot use insert() with string\"`\n    @throw invalid_iterator.202 if @a pos is not an iterator of *this;\n    example: `\"iterator does not fit current value\"`\n\n    @complexity Linear in @a cnt plus linear in the distance between @a pos\n    and end of the container.\n\n    @liveexample{The example shows how `insert()` is used.,insert__count}\n\n    @since version 1.0.0\n    */\n    iterator insert(const_iterator pos, size_type cnt, const basic_json& val)\n    {\n        // insert only works for arrays\n        if (JSON_LIKELY(is_array()))\n        {\n            // check if iterator pos fits to this JSON value\n            if (JSON_UNLIKELY(pos.m_object != this))\n            {\n                JSON_THROW(invalid_iterator::create(202, \"iterator does not fit current value\"));\n            }\n\n            // insert to array and return iterator\n            return insert_iterator(pos, cnt, val);\n        }\n\n        JSON_THROW(type_error::create(309, \"cannot use insert() with \" + std::string(type_name())));\n    }\n\n    /*!\n    @brief inserts elements\n\n    Inserts elements from range `[first, last)` before iterator @a pos.\n\n    @param[in] pos iterator before which the content will be inserted; may be\n    the end() iterator\n    @param[in] first begin of the range of elements to insert\n    @param[in] last end of the range of elements to insert\n\n    @throw type_error.309 if called on JSON values other than arrays; example:\n    `\"cannot use insert() with string\"`\n    @throw invalid_iterator.202 if @a pos is not an iterator of *this;\n    example: `\"iterator does not fit current value\"`\n    @throw invalid_iterator.210 if @a first and @a last do not belong to the\n    same JSON value; example: `\"iterators do not fit\"`\n    @throw invalid_iterator.211 if @a first or @a last are iterators into\n    container for which insert is called; example: `\"passed iterators may not\n    belong to container\"`\n\n    @return iterator pointing to the first element inserted, or @a pos if\n    `first==last`\n\n    @complexity Linear in `std::distance(first, last)` plus linear in the\n    distance between @a pos and end of the container.\n\n    @liveexample{The example shows how `insert()` is used.,insert__range}\n\n    @since version 1.0.0\n    */\n    iterator insert(const_iterator pos, const_iterator first, const_iterator last)\n    {\n        // insert only works for arrays\n        if (JSON_UNLIKELY(not is_array()))\n        {\n            JSON_THROW(type_error::create(309, \"cannot use insert() with \" + std::string(type_name())));\n        }\n\n        // check if iterator pos fits to this JSON value\n        if (JSON_UNLIKELY(pos.m_object != this))\n        {\n            JSON_THROW(invalid_iterator::create(202, \"iterator does not fit current value\"));\n        }\n\n        // check if range iterators belong to the same JSON object\n        if (JSON_UNLIKELY(first.m_object != last.m_object))\n        {\n            JSON_THROW(invalid_iterator::create(210, \"iterators do not fit\"));\n        }\n\n        if (JSON_UNLIKELY(first.m_object == this))\n        {\n            JSON_THROW(invalid_iterator::create(211, \"passed iterators may not belong to container\"));\n        }\n\n        // insert to array and return iterator\n        return insert_iterator(pos, first.m_it.array_iterator, last.m_it.array_iterator);\n    }\n\n    /*!\n    @brief inserts elements\n\n    Inserts elements from initializer list @a ilist before iterator @a pos.\n\n    @param[in] pos iterator before which the content will be inserted; may be\n    the end() iterator\n    @param[in] ilist initializer list to insert the values from\n\n    @throw type_error.309 if called on JSON values other than arrays; example:\n    `\"cannot use insert() with string\"`\n    @throw invalid_iterator.202 if @a pos is not an iterator of *this;\n    example: `\"iterator does not fit current value\"`\n\n    @return iterator pointing to the first element inserted, or @a pos if\n    `ilist` is empty\n\n    @complexity Linear in `ilist.size()` plus linear in the distance between\n    @a pos and end of the container.\n\n    @liveexample{The example shows how `insert()` is used.,insert__ilist}\n\n    @since version 1.0.0\n    */\n    iterator insert(const_iterator pos, initializer_list_t ilist)\n    {\n        // insert only works for arrays\n        if (JSON_UNLIKELY(not is_array()))\n        {\n            JSON_THROW(type_error::create(309, \"cannot use insert() with \" + std::string(type_name())));\n        }\n\n        // check if iterator pos fits to this JSON value\n        if (JSON_UNLIKELY(pos.m_object != this))\n        {\n            JSON_THROW(invalid_iterator::create(202, \"iterator does not fit current value\"));\n        }\n\n        // insert to array and return iterator\n        return insert_iterator(pos, ilist.begin(), ilist.end());\n    }\n\n    /*!\n    @brief inserts elements\n\n    Inserts elements from range `[first, last)`.\n\n    @param[in] first begin of the range of elements to insert\n    @param[in] last end of the range of elements to insert\n\n    @throw type_error.309 if called on JSON values other than objects; example:\n    `\"cannot use insert() with string\"`\n    @throw invalid_iterator.202 if iterator @a first or @a last does does not\n    point to an object; example: `\"iterators first and last must point to\n    objects\"`\n    @throw invalid_iterator.210 if @a first and @a last do not belong to the\n    same JSON value; example: `\"iterators do not fit\"`\n\n    @complexity Logarithmic: `O(N*log(size() + N))`, where `N` is the number\n    of elements to insert.\n\n    @liveexample{The example shows how `insert()` is used.,insert__range_object}\n\n    @since version 3.0.0\n    */\n    void insert(const_iterator first, const_iterator last)\n    {\n        // insert only works for objects\n        if (JSON_UNLIKELY(not is_object()))\n        {\n            JSON_THROW(type_error::create(309, \"cannot use insert() with \" + std::string(type_name())));\n        }\n\n        // check if range iterators belong to the same JSON object\n        if (JSON_UNLIKELY(first.m_object != last.m_object))\n        {\n            JSON_THROW(invalid_iterator::create(210, \"iterators do not fit\"));\n        }\n\n        // passed iterators must belong to objects\n        if (JSON_UNLIKELY(not first.m_object->is_object()))\n        {\n            JSON_THROW(invalid_iterator::create(202, \"iterators first and last must point to objects\"));\n        }\n\n        m_value.object->insert(first.m_it.object_iterator, last.m_it.object_iterator);\n    }\n\n    /*!\n    @brief updates a JSON object from another object, overwriting existing keys\n\n    Inserts all values from JSON object @a j and overwrites existing keys.\n\n    @param[in] j  JSON object to read values from\n\n    @throw type_error.312 if called on JSON values other than objects; example:\n    `\"cannot use update() with string\"`\n\n    @complexity O(N*log(size() + N)), where N is the number of elements to\n                insert.\n\n    @liveexample{The example shows how `update()` is used.,update}\n\n    @sa https://docs.python.org/3.6/library/stdtypes.html#dict.update\n\n    @since version 3.0.0\n    */\n    void update(const_reference j)\n    {\n        // implicitly convert null value to an empty object\n        if (is_null())\n        {\n            m_type = value_t::object;\n            m_value.object = create<object_t>();\n            assert_invariant();\n        }\n\n        if (JSON_UNLIKELY(not is_object()))\n        {\n            JSON_THROW(type_error::create(312, \"cannot use update() with \" + std::string(type_name())));\n        }\n        if (JSON_UNLIKELY(not j.is_object()))\n        {\n            JSON_THROW(type_error::create(312, \"cannot use update() with \" + std::string(j.type_name())));\n        }\n\n        for (auto it = j.cbegin(); it != j.cend(); ++it)\n        {\n            m_value.object->operator[](it.key()) = it.value();\n        }\n    }\n\n    /*!\n    @brief updates a JSON object from another object, overwriting existing keys\n\n    Inserts all values from from range `[first, last)` and overwrites existing\n    keys.\n\n    @param[in] first begin of the range of elements to insert\n    @param[in] last end of the range of elements to insert\n\n    @throw type_error.312 if called on JSON values other than objects; example:\n    `\"cannot use update() with string\"`\n    @throw invalid_iterator.202 if iterator @a first or @a last does does not\n    point to an object; example: `\"iterators first and last must point to\n    objects\"`\n    @throw invalid_iterator.210 if @a first and @a last do not belong to the\n    same JSON value; example: `\"iterators do not fit\"`\n\n    @complexity O(N*log(size() + N)), where N is the number of elements to\n                insert.\n\n    @liveexample{The example shows how `update()` is used__range.,update}\n\n    @sa https://docs.python.org/3.6/library/stdtypes.html#dict.update\n\n    @since version 3.0.0\n    */\n    void update(const_iterator first, const_iterator last)\n    {\n        // implicitly convert null value to an empty object\n        if (is_null())\n        {\n            m_type = value_t::object;\n            m_value.object = create<object_t>();\n            assert_invariant();\n        }\n\n        if (JSON_UNLIKELY(not is_object()))\n        {\n            JSON_THROW(type_error::create(312, \"cannot use update() with \" + std::string(type_name())));\n        }\n\n        // check if range iterators belong to the same JSON object\n        if (JSON_UNLIKELY(first.m_object != last.m_object))\n        {\n            JSON_THROW(invalid_iterator::create(210, \"iterators do not fit\"));\n        }\n\n        // passed iterators must belong to objects\n        if (JSON_UNLIKELY(not first.m_object->is_object()\n                          or not last.m_object->is_object()))\n        {\n            JSON_THROW(invalid_iterator::create(202, \"iterators first and last must point to objects\"));\n        }\n\n        for (auto it = first; it != last; ++it)\n        {\n            m_value.object->operator[](it.key()) = it.value();\n        }\n    }\n\n    /*!\n    @brief exchanges the values\n\n    Exchanges the contents of the JSON value with those of @a other. Does not\n    invoke any move, copy, or swap operations on individual elements. All\n    iterators and references remain valid. The past-the-end iterator is\n    invalidated.\n\n    @param[in,out] other JSON value to exchange the contents with\n\n    @complexity Constant.\n\n    @liveexample{The example below shows how JSON values can be swapped with\n    `swap()`.,swap__reference}\n\n    @since version 1.0.0\n    */\n    void swap(reference other) noexcept (\n        std::is_nothrow_move_constructible<value_t>::value and\n        std::is_nothrow_move_assignable<value_t>::value and\n        std::is_nothrow_move_constructible<json_value>::value and\n        std::is_nothrow_move_assignable<json_value>::value\n    )\n    {\n        std::swap(m_type, other.m_type);\n        std::swap(m_value, other.m_value);\n        assert_invariant();\n    }\n\n    /*!\n    @brief exchanges the values\n\n    Exchanges the contents of a JSON array with those of @a other. Does not\n    invoke any move, copy, or swap operations on individual elements. All\n    iterators and references remain valid. The past-the-end iterator is\n    invalidated.\n\n    @param[in,out] other array to exchange the contents with\n\n    @throw type_error.310 when JSON value is not an array; example: `\"cannot\n    use swap() with string\"`\n\n    @complexity Constant.\n\n    @liveexample{The example below shows how arrays can be swapped with\n    `swap()`.,swap__array_t}\n\n    @since version 1.0.0\n    */\n    void swap(array_t& other)\n    {\n        // swap only works for arrays\n        if (JSON_LIKELY(is_array()))\n        {\n            std::swap(*(m_value.array), other);\n        }\n        else\n        {\n            JSON_THROW(type_error::create(310, \"cannot use swap() with \" + std::string(type_name())));\n        }\n    }\n\n    /*!\n    @brief exchanges the values\n\n    Exchanges the contents of a JSON object with those of @a other. Does not\n    invoke any move, copy, or swap operations on individual elements. All\n    iterators and references remain valid. The past-the-end iterator is\n    invalidated.\n\n    @param[in,out] other object to exchange the contents with\n\n    @throw type_error.310 when JSON value is not an object; example:\n    `\"cannot use swap() with string\"`\n\n    @complexity Constant.\n\n    @liveexample{The example below shows how objects can be swapped with\n    `swap()`.,swap__object_t}\n\n    @since version 1.0.0\n    */\n    void swap(object_t& other)\n    {\n        // swap only works for objects\n        if (JSON_LIKELY(is_object()))\n        {\n            std::swap(*(m_value.object), other);\n        }\n        else\n        {\n            JSON_THROW(type_error::create(310, \"cannot use swap() with \" + std::string(type_name())));\n        }\n    }\n\n    /*!\n    @brief exchanges the values\n\n    Exchanges the contents of a JSON string with those of @a other. Does not\n    invoke any move, copy, or swap operations on individual elements. All\n    iterators and references remain valid. The past-the-end iterator is\n    invalidated.\n\n    @param[in,out] other string to exchange the contents with\n\n    @throw type_error.310 when JSON value is not a string; example: `\"cannot\n    use swap() with boolean\"`\n\n    @complexity Constant.\n\n    @liveexample{The example below shows how strings can be swapped with\n    `swap()`.,swap__string_t}\n\n    @since version 1.0.0\n    */\n    void swap(string_t& other)\n    {\n        // swap only works for strings\n        if (JSON_LIKELY(is_string()))\n        {\n            std::swap(*(m_value.string), other);\n        }\n        else\n        {\n            JSON_THROW(type_error::create(310, \"cannot use swap() with \" + std::string(type_name())));\n        }\n    }\n\n    /// @}\n\n  public:\n    //////////////////////////////////////////\n    // lexicographical comparison operators //\n    //////////////////////////////////////////\n\n    /// @name lexicographical comparison operators\n    /// @{\n\n    /*!\n    @brief comparison: equal\n\n    Compares two JSON values for equality according to the following rules:\n    - Two JSON values are equal if (1) they are from the same type and (2)\n      their stored values are the same according to their respective\n      `operator==`.\n    - Integer and floating-point numbers are automatically converted before\n      comparison. Note than two NaN values are always treated as unequal.\n    - Two JSON null values are equal.\n\n    @note Floating-point inside JSON values numbers are compared with\n    `json::number_float_t::operator==` which is `double::operator==` by\n    default. To compare floating-point while respecting an epsilon, an alternative\n    [comparison function](https://github.com/mariokonrad/marnav/blob/master/src/marnav/math/floatingpoint.hpp#L34-#L39)\n    could be used, for instance\n    @code {.cpp}\n    template<typename T, typename = typename std::enable_if<std::is_floating_point<T>::value, T>::type>\n    inline bool is_same(T a, T b, T epsilon = std::numeric_limits<T>::epsilon()) noexcept\n    {\n        return std::abs(a - b) <= epsilon;\n    }\n    @endcode\n\n    @note NaN values never compare equal to themselves or to other NaN values.\n\n    @param[in] lhs  first JSON value to consider\n    @param[in] rhs  second JSON value to consider\n    @return whether the values @a lhs and @a rhs are equal\n\n    @exceptionsafety No-throw guarantee: this function never throws exceptions.\n\n    @complexity Linear.\n\n    @liveexample{The example demonstrates comparing several JSON\n    types.,operator__equal}\n\n    @since version 1.0.0\n    */\n    friend bool operator==(const_reference lhs, const_reference rhs) noexcept\n    {\n        const auto lhs_type = lhs.type();\n        const auto rhs_type = rhs.type();\n\n        if (lhs_type == rhs_type)\n        {\n            switch (lhs_type)\n            {\n                case value_t::array:\n                    return (*lhs.m_value.array == *rhs.m_value.array);\n\n                case value_t::object:\n                    return (*lhs.m_value.object == *rhs.m_value.object);\n\n                case value_t::null:\n                    return true;\n\n                case value_t::string:\n                    return (*lhs.m_value.string == *rhs.m_value.string);\n\n                case value_t::boolean:\n                    return (lhs.m_value.boolean == rhs.m_value.boolean);\n\n                case value_t::number_integer:\n                    return (lhs.m_value.number_integer == rhs.m_value.number_integer);\n\n                case value_t::number_unsigned:\n                    return (lhs.m_value.number_unsigned == rhs.m_value.number_unsigned);\n\n                case value_t::number_float:\n                    return (lhs.m_value.number_float == rhs.m_value.number_float);\n\n                default:\n                    return false;\n            }\n        }\n        else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float)\n        {\n            return (static_cast<number_float_t>(lhs.m_value.number_integer) == rhs.m_value.number_float);\n        }\n        else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer)\n        {\n            return (lhs.m_value.number_float == static_cast<number_float_t>(rhs.m_value.number_integer));\n        }\n        else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float)\n        {\n            return (static_cast<number_float_t>(lhs.m_value.number_unsigned) == rhs.m_value.number_float);\n        }\n        else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned)\n        {\n            return (lhs.m_value.number_float == static_cast<number_float_t>(rhs.m_value.number_unsigned));\n        }\n        else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer)\n        {\n            return (static_cast<number_integer_t>(lhs.m_value.number_unsigned) == rhs.m_value.number_integer);\n        }\n        else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned)\n        {\n            return (lhs.m_value.number_integer == static_cast<number_integer_t>(rhs.m_value.number_unsigned));\n        }\n\n        return false;\n    }\n\n    /*!\n    @brief comparison: equal\n    @copydoc operator==(const_reference, const_reference)\n    */\n    template<typename ScalarType, typename std::enable_if<\n                 std::is_scalar<ScalarType>::value, int>::type = 0>\n    friend bool operator==(const_reference lhs, const ScalarType rhs) noexcept\n    {\n        return (lhs == basic_json(rhs));\n    }\n\n    /*!\n    @brief comparison: equal\n    @copydoc operator==(const_reference, const_reference)\n    */\n    template<typename ScalarType, typename std::enable_if<\n                 std::is_scalar<ScalarType>::value, int>::type = 0>\n    friend bool operator==(const ScalarType lhs, const_reference rhs) noexcept\n    {\n        return (basic_json(lhs) == rhs);\n    }\n\n    /*!\n    @brief comparison: not equal\n\n    Compares two JSON values for inequality by calculating `not (lhs == rhs)`.\n\n    @param[in] lhs  first JSON value to consider\n    @param[in] rhs  second JSON value to consider\n    @return whether the values @a lhs and @a rhs are not equal\n\n    @complexity Linear.\n\n    @exceptionsafety No-throw guarantee: this function never throws exceptions.\n\n    @liveexample{The example demonstrates comparing several JSON\n    types.,operator__notequal}\n\n    @since version 1.0.0\n    */\n    friend bool operator!=(const_reference lhs, const_reference rhs) noexcept\n    {\n        return not (lhs == rhs);\n    }\n\n    /*!\n    @brief comparison: not equal\n    @copydoc operator!=(const_reference, const_reference)\n    */\n    template<typename ScalarType, typename std::enable_if<\n                 std::is_scalar<ScalarType>::value, int>::type = 0>\n    friend bool operator!=(const_reference lhs, const ScalarType rhs) noexcept\n    {\n        return (lhs != basic_json(rhs));\n    }\n\n    /*!\n    @brief comparison: not equal\n    @copydoc operator!=(const_reference, const_reference)\n    */\n    template<typename ScalarType, typename std::enable_if<\n                 std::is_scalar<ScalarType>::value, int>::type = 0>\n    friend bool operator!=(const ScalarType lhs, const_reference rhs) noexcept\n    {\n        return (basic_json(lhs) != rhs);\n    }\n\n    /*!\n    @brief comparison: less than\n\n    Compares whether one JSON value @a lhs is less than another JSON value @a\n    rhs according to the following rules:\n    - If @a lhs and @a rhs have the same type, the values are compared using\n      the default `<` operator.\n    - Integer and floating-point numbers are automatically converted before\n      comparison\n    - In case @a lhs and @a rhs have different types, the values are ignored\n      and the order of the types is considered, see\n      @ref operator<(const value_t, const value_t).\n\n    @param[in] lhs  first JSON value to consider\n    @param[in] rhs  second JSON value to consider\n    @return whether @a lhs is less than @a rhs\n\n    @complexity Linear.\n\n    @exceptionsafety No-throw guarantee: this function never throws exceptions.\n\n    @liveexample{The example demonstrates comparing several JSON\n    types.,operator__less}\n\n    @since version 1.0.0\n    */\n    friend bool operator<(const_reference lhs, const_reference rhs) noexcept\n    {\n        const auto lhs_type = lhs.type();\n        const auto rhs_type = rhs.type();\n\n        if (lhs_type == rhs_type)\n        {\n            switch (lhs_type)\n            {\n                case value_t::array:\n                    return (*lhs.m_value.array) < (*rhs.m_value.array);\n\n                case value_t::object:\n                    return *lhs.m_value.object < *rhs.m_value.object;\n\n                case value_t::null:\n                    return false;\n\n                case value_t::string:\n                    return *lhs.m_value.string < *rhs.m_value.string;\n\n                case value_t::boolean:\n                    return lhs.m_value.boolean < rhs.m_value.boolean;\n\n                case value_t::number_integer:\n                    return lhs.m_value.number_integer < rhs.m_value.number_integer;\n\n                case value_t::number_unsigned:\n                    return lhs.m_value.number_unsigned < rhs.m_value.number_unsigned;\n\n                case value_t::number_float:\n                    return lhs.m_value.number_float < rhs.m_value.number_float;\n\n                default:\n                    return false;\n            }\n        }\n        else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float)\n        {\n            return static_cast<number_float_t>(lhs.m_value.number_integer) < rhs.m_value.number_float;\n        }\n        else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer)\n        {\n            return lhs.m_value.number_float < static_cast<number_float_t>(rhs.m_value.number_integer);\n        }\n        else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float)\n        {\n            return static_cast<number_float_t>(lhs.m_value.number_unsigned) < rhs.m_value.number_float;\n        }\n        else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned)\n        {\n            return lhs.m_value.number_float < static_cast<number_float_t>(rhs.m_value.number_unsigned);\n        }\n        else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned)\n        {\n            return lhs.m_value.number_integer < static_cast<number_integer_t>(rhs.m_value.number_unsigned);\n        }\n        else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer)\n        {\n            return static_cast<number_integer_t>(lhs.m_value.number_unsigned) < rhs.m_value.number_integer;\n        }\n\n        // We only reach this line if we cannot compare values. In that case,\n        // we compare types. Note we have to call the operator explicitly,\n        // because MSVC has problems otherwise.\n        return operator<(lhs_type, rhs_type);\n    }\n\n    /*!\n    @brief comparison: less than\n    @copydoc operator<(const_reference, const_reference)\n    */\n    template<typename ScalarType, typename std::enable_if<\n                 std::is_scalar<ScalarType>::value, int>::type = 0>\n    friend bool operator<(const_reference lhs, const ScalarType rhs) noexcept\n    {\n        return (lhs < basic_json(rhs));\n    }\n\n    /*!\n    @brief comparison: less than\n    @copydoc operator<(const_reference, const_reference)\n    */\n    template<typename ScalarType, typename std::enable_if<\n                 std::is_scalar<ScalarType>::value, int>::type = 0>\n    friend bool operator<(const ScalarType lhs, const_reference rhs) noexcept\n    {\n        return (basic_json(lhs) < rhs);\n    }\n\n    /*!\n    @brief comparison: less than or equal\n\n    Compares whether one JSON value @a lhs is less than or equal to another\n    JSON value by calculating `not (rhs < lhs)`.\n\n    @param[in] lhs  first JSON value to consider\n    @param[in] rhs  second JSON value to consider\n    @return whether @a lhs is less than or equal to @a rhs\n\n    @complexity Linear.\n\n    @exceptionsafety No-throw guarantee: this function never throws exceptions.\n\n    @liveexample{The example demonstrates comparing several JSON\n    types.,operator__greater}\n\n    @since version 1.0.0\n    */\n    friend bool operator<=(const_reference lhs, const_reference rhs) noexcept\n    {\n        return not (rhs < lhs);\n    }\n\n    /*!\n    @brief comparison: less than or equal\n    @copydoc operator<=(const_reference, const_reference)\n    */\n    template<typename ScalarType, typename std::enable_if<\n                 std::is_scalar<ScalarType>::value, int>::type = 0>\n    friend bool operator<=(const_reference lhs, const ScalarType rhs) noexcept\n    {\n        return (lhs <= basic_json(rhs));\n    }\n\n    /*!\n    @brief comparison: less than or equal\n    @copydoc operator<=(const_reference, const_reference)\n    */\n    template<typename ScalarType, typename std::enable_if<\n                 std::is_scalar<ScalarType>::value, int>::type = 0>\n    friend bool operator<=(const ScalarType lhs, const_reference rhs) noexcept\n    {\n        return (basic_json(lhs) <= rhs);\n    }\n\n    /*!\n    @brief comparison: greater than\n\n    Compares whether one JSON value @a lhs is greater than another\n    JSON value by calculating `not (lhs <= rhs)`.\n\n    @param[in] lhs  first JSON value to consider\n    @param[in] rhs  second JSON value to consider\n    @return whether @a lhs is greater than to @a rhs\n\n    @complexity Linear.\n\n    @exceptionsafety No-throw guarantee: this function never throws exceptions.\n\n    @liveexample{The example demonstrates comparing several JSON\n    types.,operator__lessequal}\n\n    @since version 1.0.0\n    */\n    friend bool operator>(const_reference lhs, const_reference rhs) noexcept\n    {\n        return not (lhs <= rhs);\n    }\n\n    /*!\n    @brief comparison: greater than\n    @copydoc operator>(const_reference, const_reference)\n    */\n    template<typename ScalarType, typename std::enable_if<\n                 std::is_scalar<ScalarType>::value, int>::type = 0>\n    friend bool operator>(const_reference lhs, const ScalarType rhs) noexcept\n    {\n        return (lhs > basic_json(rhs));\n    }\n\n    /*!\n    @brief comparison: greater than\n    @copydoc operator>(const_reference, const_reference)\n    */\n    template<typename ScalarType, typename std::enable_if<\n                 std::is_scalar<ScalarType>::value, int>::type = 0>\n    friend bool operator>(const ScalarType lhs, const_reference rhs) noexcept\n    {\n        return (basic_json(lhs) > rhs);\n    }\n\n    /*!\n    @brief comparison: greater than or equal\n\n    Compares whether one JSON value @a lhs is greater than or equal to another\n    JSON value by calculating `not (lhs < rhs)`.\n\n    @param[in] lhs  first JSON value to consider\n    @param[in] rhs  second JSON value to consider\n    @return whether @a lhs is greater than or equal to @a rhs\n\n    @complexity Linear.\n\n    @exceptionsafety No-throw guarantee: this function never throws exceptions.\n\n    @liveexample{The example demonstrates comparing several JSON\n    types.,operator__greaterequal}\n\n    @since version 1.0.0\n    */\n    friend bool operator>=(const_reference lhs, const_reference rhs) noexcept\n    {\n        return not (lhs < rhs);\n    }\n\n    /*!\n    @brief comparison: greater than or equal\n    @copydoc operator>=(const_reference, const_reference)\n    */\n    template<typename ScalarType, typename std::enable_if<\n                 std::is_scalar<ScalarType>::value, int>::type = 0>\n    friend bool operator>=(const_reference lhs, const ScalarType rhs) noexcept\n    {\n        return (lhs >= basic_json(rhs));\n    }\n\n    /*!\n    @brief comparison: greater than or equal\n    @copydoc operator>=(const_reference, const_reference)\n    */\n    template<typename ScalarType, typename std::enable_if<\n                 std::is_scalar<ScalarType>::value, int>::type = 0>\n    friend bool operator>=(const ScalarType lhs, const_reference rhs) noexcept\n    {\n        return (basic_json(lhs) >= rhs);\n    }\n\n    /// @}\n\n    ///////////////////\n    // serialization //\n    ///////////////////\n\n    /// @name serialization\n    /// @{\n\n    /*!\n    @brief serialize to stream\n\n    Serialize the given JSON value @a j to the output stream @a o. The JSON\n    value will be serialized using the @ref dump member function.\n\n    - The indentation of the output can be controlled with the member variable\n      `width` of the output stream @a o. For instance, using the manipulator\n      `std::setw(4)` on @a o sets the indentation level to `4` and the\n      serialization result is the same as calling `dump(4)`.\n\n    - The indentation character can be controlled with the member variable\n      `fill` of the output stream @a o. For instance, the manipulator\n      `std::setfill('\\\\t')` sets indentation to use a tab character rather than\n      the default space character.\n\n    @param[in,out] o  stream to serialize to\n    @param[in] j  JSON value to serialize\n\n    @return the stream @a o\n\n    @throw type_error.316 if a string stored inside the JSON value is not\n                          UTF-8 encoded\n\n    @complexity Linear.\n\n    @liveexample{The example below shows the serialization with different\n    parameters to `width` to adjust the indentation level.,operator_serialize}\n\n    @since version 1.0.0; indentation character added in version 3.0.0\n    */\n    friend std::ostream& operator<<(std::ostream& o, const basic_json& j)\n    {\n        // read width member and use it as indentation parameter if nonzero\n        const bool pretty_print = (o.width() > 0);\n        const auto indentation = (pretty_print ? o.width() : 0);\n\n        // reset width to 0 for subsequent calls to this stream\n        o.width(0);\n\n        // do the actual serialization\n        serializer s(detail::output_adapter<char>(o), o.fill());\n        s.dump(j, pretty_print, false, static_cast<unsigned int>(indentation));\n        return o;\n    }\n\n    /*!\n    @brief serialize to stream\n    @deprecated This stream operator is deprecated and will be removed in\n                future 4.0.0 of the library. Please use\n                @ref operator<<(std::ostream&, const basic_json&)\n                instead; that is, replace calls like `j >> o;` with `o << j;`.\n    @since version 1.0.0; deprecated since version 3.0.0\n    */\n    JSON_DEPRECATED\n    friend std::ostream& operator>>(const basic_json& j, std::ostream& o)\n    {\n        return o << j;\n    }\n\n    /// @}\n\n\n    /////////////////////\n    // deserialization //\n    /////////////////////\n\n    /// @name deserialization\n    /// @{\n\n    /*!\n    @brief deserialize from a compatible input\n\n    This function reads from a compatible input. Examples are:\n    - an array of 1-byte values\n    - strings with character/literal type with size of 1 byte\n    - input streams\n    - container with contiguous storage of 1-byte values. Compatible container\n      types include `std::vector`, `std::string`, `std::array`,\n      `std::valarray`, and `std::initializer_list`. Furthermore, C-style\n      arrays can be used with `std::begin()`/`std::end()`. User-defined\n      containers can be used as long as they implement random-access iterators\n      and a contiguous storage.\n\n    @pre Each element of the container has a size of 1 byte. Violating this\n    precondition yields undefined behavior. **This precondition is enforced\n    with a static assertion.**\n\n    @pre The container storage is contiguous. Violating this precondition\n    yields undefined behavior. **This precondition is enforced with an\n    assertion.**\n    @pre Each element of the container has a size of 1 byte. Violating this\n    precondition yields undefined behavior. **This precondition is enforced\n    with a static assertion.**\n\n    @warning There is no way to enforce all preconditions at compile-time. If\n             the function is called with a noncompliant container and with\n             assertions switched off, the behavior is undefined and will most\n             likely yield segmentation violation.\n\n    @param[in] i  input to read from\n    @param[in] cb  a parser callback function of type @ref parser_callback_t\n    which is used to control the deserialization by filtering unwanted values\n    (optional)\n    @param[in] allow_exceptions  whether to throw exceptions in case of a\n    parse error (optional, true by default)\n\n    @return result of the deserialization\n\n    @throw parse_error.101 if a parse error occurs; example: `\"\"unexpected end\n    of input; expected string literal\"\"`\n    @throw parse_error.102 if to_unicode fails or surrogate error\n    @throw parse_error.103 if to_unicode fails\n\n    @complexity Linear in the length of the input. The parser is a predictive\n    LL(1) parser. The complexity can be higher if the parser callback function\n    @a cb has a super-linear complexity.\n\n    @note A UTF-8 byte order mark is silently ignored.\n\n    @liveexample{The example below demonstrates the `parse()` function reading\n    from an array.,parse__array__parser_callback_t}\n\n    @liveexample{The example below demonstrates the `parse()` function with\n    and without callback function.,parse__string__parser_callback_t}\n\n    @liveexample{The example below demonstrates the `parse()` function with\n    and without callback function.,parse__istream__parser_callback_t}\n\n    @liveexample{The example below demonstrates the `parse()` function reading\n    from a contiguous container.,parse__contiguouscontainer__parser_callback_t}\n\n    @since version 2.0.3 (contiguous containers)\n    */\n    static basic_json parse(detail::input_adapter&& i,\n                            const parser_callback_t cb = nullptr,\n                            const bool allow_exceptions = true)\n    {\n        basic_json result;\n        parser(i, cb, allow_exceptions).parse(true, result);\n        return result;\n    }\n\n    static bool accept(detail::input_adapter&& i)\n    {\n        return parser(i).accept(true);\n    }\n\n    /*!\n    @brief generate SAX events\n\n    The SAX event lister must follow the interface of @ref json_sax.\n\n    This function reads from a compatible input. Examples are:\n    - an array of 1-byte values\n    - strings with character/literal type with size of 1 byte\n    - input streams\n    - container with contiguous storage of 1-byte values. Compatible container\n      types include `std::vector`, `std::string`, `std::array`,\n      `std::valarray`, and `std::initializer_list`. Furthermore, C-style\n      arrays can be used with `std::begin()`/`std::end()`. User-defined\n      containers can be used as long as they implement random-access iterators\n      and a contiguous storage.\n\n    @pre Each element of the container has a size of 1 byte. Violating this\n    precondition yields undefined behavior. **This precondition is enforced\n    with a static assertion.**\n\n    @pre The container storage is contiguous. Violating this precondition\n    yields undefined behavior. **This precondition is enforced with an\n    assertion.**\n    @pre Each element of the container has a size of 1 byte. Violating this\n    precondition yields undefined behavior. **This precondition is enforced\n    with a static assertion.**\n\n    @warning There is no way to enforce all preconditions at compile-time. If\n             the function is called with a noncompliant container and with\n             assertions switched off, the behavior is undefined and will most\n             likely yield segmentation violation.\n\n    @param[in] i  input to read from\n    @param[in,out] sax  SAX event listener\n    @param[in] format  the format to parse (JSON, CBOR, MessagePack, or UBJSON)\n    @param[in] strict  whether the input has to be consumed completely\n\n    @return return value of the last processed SAX event\n\n    @throw parse_error.101 if a parse error occurs; example: `\"\"unexpected end\n    of input; expected string literal\"\"`\n    @throw parse_error.102 if to_unicode fails or surrogate error\n    @throw parse_error.103 if to_unicode fails\n\n    @complexity Linear in the length of the input. The parser is a predictive\n    LL(1) parser. The complexity can be higher if the SAX consumer @a sax has\n    a super-linear complexity.\n\n    @note A UTF-8 byte order mark is silently ignored.\n\n    @liveexample{The example below demonstrates the `sax_parse()` function\n    reading from string and processing the events with a user-defined SAX\n    event consumer.,sax_parse}\n\n    @since version 3.2.0\n    */\n    template <typename SAX>\n    static bool sax_parse(detail::input_adapter&& i, SAX* sax,\n                          input_format_t format = input_format_t::json,\n                          const bool strict = true)\n    {\n        assert(sax);\n        switch (format)\n        {\n            case input_format_t::json:\n                return parser(std::move(i)).sax_parse(sax, strict);\n            default:\n                return detail::binary_reader<basic_json, SAX>(std::move(i)).sax_parse(format, sax, strict);\n        }\n    }\n\n    /*!\n    @brief deserialize from an iterator range with contiguous storage\n\n    This function reads from an iterator range of a container with contiguous\n    storage of 1-byte values. Compatible container types include\n    `std::vector`, `std::string`, `std::array`, `std::valarray`, and\n    `std::initializer_list`. Furthermore, C-style arrays can be used with\n    `std::begin()`/`std::end()`. User-defined containers can be used as long\n    as they implement random-access iterators and a contiguous storage.\n\n    @pre The iterator range is contiguous. Violating this precondition yields\n    undefined behavior. **This precondition is enforced with an assertion.**\n    @pre Each element in the range has a size of 1 byte. Violating this\n    precondition yields undefined behavior. **This precondition is enforced\n    with a static assertion.**\n\n    @warning There is no way to enforce all preconditions at compile-time. If\n             the function is called with noncompliant iterators and with\n             assertions switched off, the behavior is undefined and will most\n             likely yield segmentation violation.\n\n    @tparam IteratorType iterator of container with contiguous storage\n    @param[in] first  begin of the range to parse (included)\n    @param[in] last  end of the range to parse (excluded)\n    @param[in] cb  a parser callback function of type @ref parser_callback_t\n    which is used to control the deserialization by filtering unwanted values\n    (optional)\n    @param[in] allow_exceptions  whether to throw exceptions in case of a\n    parse error (optional, true by default)\n\n    @return result of the deserialization\n\n    @throw parse_error.101 in case of an unexpected token\n    @throw parse_error.102 if to_unicode fails or surrogate error\n    @throw parse_error.103 if to_unicode fails\n\n    @complexity Linear in the length of the input. The parser is a predictive\n    LL(1) parser. The complexity can be higher if the parser callback function\n    @a cb has a super-linear complexity.\n\n    @note A UTF-8 byte order mark is silently ignored.\n\n    @liveexample{The example below demonstrates the `parse()` function reading\n    from an iterator range.,parse__iteratortype__parser_callback_t}\n\n    @since version 2.0.3\n    */\n    template<class IteratorType, typename std::enable_if<\n                 std::is_base_of<\n                     std::random_access_iterator_tag,\n                     typename std::iterator_traits<IteratorType>::iterator_category>::value, int>::type = 0>\n    static basic_json parse(IteratorType first, IteratorType last,\n                            const parser_callback_t cb = nullptr,\n                            const bool allow_exceptions = true)\n    {\n        basic_json result;\n        parser(detail::input_adapter(first, last), cb, allow_exceptions).parse(true, result);\n        return result;\n    }\n\n    template<class IteratorType, typename std::enable_if<\n                 std::is_base_of<\n                     std::random_access_iterator_tag,\n                     typename std::iterator_traits<IteratorType>::iterator_category>::value, int>::type = 0>\n    static bool accept(IteratorType first, IteratorType last)\n    {\n        return parser(detail::input_adapter(first, last)).accept(true);\n    }\n\n    template<class IteratorType, class SAX, typename std::enable_if<\n                 std::is_base_of<\n                     std::random_access_iterator_tag,\n                     typename std::iterator_traits<IteratorType>::iterator_category>::value, int>::type = 0>\n    static bool sax_parse(IteratorType first, IteratorType last, SAX* sax)\n    {\n        return parser(detail::input_adapter(first, last)).sax_parse(sax);\n    }\n\n    /*!\n    @brief deserialize from stream\n    @deprecated This stream operator is deprecated and will be removed in\n                version 4.0.0 of the library. Please use\n                @ref operator>>(std::istream&, basic_json&)\n                instead; that is, replace calls like `j << i;` with `i >> j;`.\n    @since version 1.0.0; deprecated since version 3.0.0\n    */\n    JSON_DEPRECATED\n    friend std::istream& operator<<(basic_json& j, std::istream& i)\n    {\n        return operator>>(i, j);\n    }\n\n    /*!\n    @brief deserialize from stream\n\n    Deserializes an input stream to a JSON value.\n\n    @param[in,out] i  input stream to read a serialized JSON value from\n    @param[in,out] j  JSON value to write the deserialized input to\n\n    @throw parse_error.101 in case of an unexpected token\n    @throw parse_error.102 if to_unicode fails or surrogate error\n    @throw parse_error.103 if to_unicode fails\n\n    @complexity Linear in the length of the input. The parser is a predictive\n    LL(1) parser.\n\n    @note A UTF-8 byte order mark is silently ignored.\n\n    @liveexample{The example below shows how a JSON value is constructed by\n    reading a serialization from a stream.,operator_deserialize}\n\n    @sa parse(std::istream&, const parser_callback_t) for a variant with a\n    parser callback function to filter values while parsing\n\n    @since version 1.0.0\n    */\n    friend std::istream& operator>>(std::istream& i, basic_json& j)\n    {\n        parser(detail::input_adapter(i)).parse(false, j);\n        return i;\n    }\n\n    /// @}\n\n    ///////////////////////////\n    // convenience functions //\n    ///////////////////////////\n\n    /*!\n    @brief return the type as string\n\n    Returns the type name as string to be used in error messages - usually to\n    indicate that a function was called on a wrong JSON type.\n\n    @return a string representation of a the @a m_type member:\n            Value type  | return value\n            ----------- | -------------\n            null        | `\"null\"`\n            boolean     | `\"boolean\"`\n            string      | `\"string\"`\n            number      | `\"number\"` (for all number types)\n            object      | `\"object\"`\n            array       | `\"array\"`\n            discarded   | `\"discarded\"`\n\n    @exceptionsafety No-throw guarantee: this function never throws exceptions.\n\n    @complexity Constant.\n\n    @liveexample{The following code exemplifies `type_name()` for all JSON\n    types.,type_name}\n\n    @sa @ref type() -- return the type of the JSON value\n    @sa @ref operator value_t() -- return the type of the JSON value (implicit)\n\n    @since version 1.0.0, public since 2.1.0, `const char*` and `noexcept`\n    since 3.0.0\n    */\n    const char* type_name() const noexcept\n    {\n        {\n            switch (m_type)\n            {\n                case value_t::null:\n                    return \"null\";\n                case value_t::object:\n                    return \"object\";\n                case value_t::array:\n                    return \"array\";\n                case value_t::string:\n                    return \"string\";\n                case value_t::boolean:\n                    return \"boolean\";\n                case value_t::discarded:\n                    return \"discarded\";\n                default:\n                    return \"number\";\n            }\n        }\n    }\n\n\n  private:\n    //////////////////////\n    // member variables //\n    //////////////////////\n\n    /// the type of the current element\n    value_t m_type = value_t::null;\n\n    /// the value of the current element\n    json_value m_value = {};\n\n    //////////////////////////////////////////\n    // binary serialization/deserialization //\n    //////////////////////////////////////////\n\n    /// @name binary serialization/deserialization support\n    /// @{\n\n  public:\n    /*!\n    @brief create a CBOR serialization of a given JSON value\n\n    Serializes a given JSON value @a j to a byte vector using the CBOR (Concise\n    Binary Object Representation) serialization format. CBOR is a binary\n    serialization format which aims to be more compact than JSON itself, yet\n    more efficient to parse.\n\n    The library uses the following mapping from JSON values types to\n    CBOR types according to the CBOR specification (RFC 7049):\n\n    JSON value type | value/range                                | CBOR type                          | first byte\n    --------------- | ------------------------------------------ | ---------------------------------- | ---------------\n    null            | `null`                                     | Null                               | 0xF6\n    boolean         | `true`                                     | True                               | 0xF5\n    boolean         | `false`                                    | False                              | 0xF4\n    number_integer  | -9223372036854775808..-2147483649          | Negative integer (8 bytes follow)  | 0x3B\n    number_integer  | -2147483648..-32769                        | Negative integer (4 bytes follow)  | 0x3A\n    number_integer  | -32768..-129                               | Negative integer (2 bytes follow)  | 0x39\n    number_integer  | -128..-25                                  | Negative integer (1 byte follow)   | 0x38\n    number_integer  | -24..-1                                    | Negative integer                   | 0x20..0x37\n    number_integer  | 0..23                                      | Integer                            | 0x00..0x17\n    number_integer  | 24..255                                    | Unsigned integer (1 byte follow)   | 0x18\n    number_integer  | 256..65535                                 | Unsigned integer (2 bytes follow)  | 0x19\n    number_integer  | 65536..4294967295                          | Unsigned integer (4 bytes follow)  | 0x1A\n    number_integer  | 4294967296..18446744073709551615           | Unsigned integer (8 bytes follow)  | 0x1B\n    number_unsigned | 0..23                                      | Integer                            | 0x00..0x17\n    number_unsigned | 24..255                                    | Unsigned integer (1 byte follow)   | 0x18\n    number_unsigned | 256..65535                                 | Unsigned integer (2 bytes follow)  | 0x19\n    number_unsigned | 65536..4294967295                          | Unsigned integer (4 bytes follow)  | 0x1A\n    number_unsigned | 4294967296..18446744073709551615           | Unsigned integer (8 bytes follow)  | 0x1B\n    number_float    | *any value*                                | Double-Precision Float             | 0xFB\n    string          | *length*: 0..23                            | UTF-8 string                       | 0x60..0x77\n    string          | *length*: 23..255                          | UTF-8 string (1 byte follow)       | 0x78\n    string          | *length*: 256..65535                       | UTF-8 string (2 bytes follow)      | 0x79\n    string          | *length*: 65536..4294967295                | UTF-8 string (4 bytes follow)      | 0x7A\n    string          | *length*: 4294967296..18446744073709551615 | UTF-8 string (8 bytes follow)      | 0x7B\n    array           | *size*: 0..23                              | array                              | 0x80..0x97\n    array           | *size*: 23..255                            | array (1 byte follow)              | 0x98\n    array           | *size*: 256..65535                         | array (2 bytes follow)             | 0x99\n    array           | *size*: 65536..4294967295                  | array (4 bytes follow)             | 0x9A\n    array           | *size*: 4294967296..18446744073709551615   | array (8 bytes follow)             | 0x9B\n    object          | *size*: 0..23                              | map                                | 0xA0..0xB7\n    object          | *size*: 23..255                            | map (1 byte follow)                | 0xB8\n    object          | *size*: 256..65535                         | map (2 bytes follow)               | 0xB9\n    object          | *size*: 65536..4294967295                  | map (4 bytes follow)               | 0xBA\n    object          | *size*: 4294967296..18446744073709551615   | map (8 bytes follow)               | 0xBB\n\n    @note The mapping is **complete** in the sense that any JSON value type\n          can be converted to a CBOR value.\n\n    @note If NaN or Infinity are stored inside a JSON number, they are\n          serialized properly. This behavior differs from the @ref dump()\n          function which serializes NaN or Infinity to `null`.\n\n    @note The following CBOR types are not used in the conversion:\n          - byte strings (0x40..0x5F)\n          - UTF-8 strings terminated by \"break\" (0x7F)\n          - arrays terminated by \"break\" (0x9F)\n          - maps terminated by \"break\" (0xBF)\n          - date/time (0xC0..0xC1)\n          - bignum (0xC2..0xC3)\n          - decimal fraction (0xC4)\n          - bigfloat (0xC5)\n          - tagged items (0xC6..0xD4, 0xD8..0xDB)\n          - expected conversions (0xD5..0xD7)\n          - simple values (0xE0..0xF3, 0xF8)\n          - undefined (0xF7)\n          - half and single-precision floats (0xF9-0xFA)\n          - break (0xFF)\n\n    @param[in] j  JSON value to serialize\n    @return MessagePack serialization as byte vector\n\n    @complexity Linear in the size of the JSON value @a j.\n\n    @liveexample{The example shows the serialization of a JSON value to a byte\n    vector in CBOR format.,to_cbor}\n\n    @sa http://cbor.io\n    @sa @ref from_cbor(detail::input_adapter&&, const bool, const bool) for the\n        analogous deserialization\n    @sa @ref to_msgpack(const basic_json&) for the related MessagePack format\n    @sa @ref to_ubjson(const basic_json&, const bool, const bool) for the\n             related UBJSON format\n\n    @since version 2.0.9\n    */\n    static std::vector<uint8_t> to_cbor(const basic_json& j)\n    {\n        std::vector<uint8_t> result;\n        to_cbor(j, result);\n        return result;\n    }\n\n    static void to_cbor(const basic_json& j, detail::output_adapter<uint8_t> o)\n    {\n        binary_writer<uint8_t>(o).write_cbor(j);\n    }\n\n    static void to_cbor(const basic_json& j, detail::output_adapter<char> o)\n    {\n        binary_writer<char>(o).write_cbor(j);\n    }\n\n    /*!\n    @brief create a MessagePack serialization of a given JSON value\n\n    Serializes a given JSON value @a j to a byte vector using the MessagePack\n    serialization format. MessagePack is a binary serialization format which\n    aims to be more compact than JSON itself, yet more efficient to parse.\n\n    The library uses the following mapping from JSON values types to\n    MessagePack types according to the MessagePack specification:\n\n    JSON value type | value/range                       | MessagePack type | first byte\n    --------------- | --------------------------------- | ---------------- | ----------\n    null            | `null`                            | nil              | 0xC0\n    boolean         | `true`                            | true             | 0xC3\n    boolean         | `false`                           | false            | 0xC2\n    number_integer  | -9223372036854775808..-2147483649 | int64            | 0xD3\n    number_integer  | -2147483648..-32769               | int32            | 0xD2\n    number_integer  | -32768..-129                      | int16            | 0xD1\n    number_integer  | -128..-33                         | int8             | 0xD0\n    number_integer  | -32..-1                           | negative fixint  | 0xE0..0xFF\n    number_integer  | 0..127                            | positive fixint  | 0x00..0x7F\n    number_integer  | 128..255                          | uint 8           | 0xCC\n    number_integer  | 256..65535                        | uint 16          | 0xCD\n    number_integer  | 65536..4294967295                 | uint 32          | 0xCE\n    number_integer  | 4294967296..18446744073709551615  | uint 64          | 0xCF\n    number_unsigned | 0..127                            | positive fixint  | 0x00..0x7F\n    number_unsigned | 128..255                          | uint 8           | 0xCC\n    number_unsigned | 256..65535                        | uint 16          | 0xCD\n    number_unsigned | 65536..4294967295                 | uint 32          | 0xCE\n    number_unsigned | 4294967296..18446744073709551615  | uint 64          | 0xCF\n    number_float    | *any value*                       | float 64         | 0xCB\n    string          | *length*: 0..31                   | fixstr           | 0xA0..0xBF\n    string          | *length*: 32..255                 | str 8            | 0xD9\n    string          | *length*: 256..65535              | str 16           | 0xDA\n    string          | *length*: 65536..4294967295       | str 32           | 0xDB\n    array           | *size*: 0..15                     | fixarray         | 0x90..0x9F\n    array           | *size*: 16..65535                 | array 16         | 0xDC\n    array           | *size*: 65536..4294967295         | array 32         | 0xDD\n    object          | *size*: 0..15                     | fix map          | 0x80..0x8F\n    object          | *size*: 16..65535                 | map 16           | 0xDE\n    object          | *size*: 65536..4294967295         | map 32           | 0xDF\n\n    @note The mapping is **complete** in the sense that any JSON value type\n          can be converted to a MessagePack value.\n\n    @note The following values can **not** be converted to a MessagePack value:\n          - strings with more than 4294967295 bytes\n          - arrays with more than 4294967295 elements\n          - objects with more than 4294967295 elements\n\n    @note The following MessagePack types are not used in the conversion:\n          - bin 8 - bin 32 (0xC4..0xC6)\n          - ext 8 - ext 32 (0xC7..0xC9)\n          - float 32 (0xCA)\n          - fixext 1 - fixext 16 (0xD4..0xD8)\n\n    @note Any MessagePack output created @ref to_msgpack can be successfully\n          parsed by @ref from_msgpack.\n\n    @note If NaN or Infinity are stored inside a JSON number, they are\n          serialized properly. This behavior differs from the @ref dump()\n          function which serializes NaN or Infinity to `null`.\n\n    @param[in] j  JSON value to serialize\n    @return MessagePack serialization as byte vector\n\n    @complexity Linear in the size of the JSON value @a j.\n\n    @liveexample{The example shows the serialization of a JSON value to a byte\n    vector in MessagePack format.,to_msgpack}\n\n    @sa http://msgpack.org\n    @sa @ref from_msgpack for the analogous deserialization\n    @sa @ref to_cbor(const basic_json& for the related CBOR format\n    @sa @ref to_ubjson(const basic_json&, const bool, const bool) for the\n             related UBJSON format\n\n    @since version 2.0.9\n    */\n    static std::vector<uint8_t> to_msgpack(const basic_json& j)\n    {\n        std::vector<uint8_t> result;\n        to_msgpack(j, result);\n        return result;\n    }\n\n    static void to_msgpack(const basic_json& j, detail::output_adapter<uint8_t> o)\n    {\n        binary_writer<uint8_t>(o).write_msgpack(j);\n    }\n\n    static void to_msgpack(const basic_json& j, detail::output_adapter<char> o)\n    {\n        binary_writer<char>(o).write_msgpack(j);\n    }\n\n    /*!\n    @brief create a UBJSON serialization of a given JSON value\n\n    Serializes a given JSON value @a j to a byte vector using the UBJSON\n    (Universal Binary JSON) serialization format. UBJSON aims to be more compact\n    than JSON itself, yet more efficient to parse.\n\n    The library uses the following mapping from JSON values types to\n    UBJSON types according to the UBJSON specification:\n\n    JSON value type | value/range                       | UBJSON type | marker\n    --------------- | --------------------------------- | ----------- | ------\n    null            | `null`                            | null        | `Z`\n    boolean         | `true`                            | true        | `T`\n    boolean         | `false`                           | false       | `F`\n    number_integer  | -9223372036854775808..-2147483649 | int64       | `L`\n    number_integer  | -2147483648..-32769               | int32       | `l`\n    number_integer  | -32768..-129                      | int16       | `I`\n    number_integer  | -128..127                         | int8        | `i`\n    number_integer  | 128..255                          | uint8       | `U`\n    number_integer  | 256..32767                        | int16       | `I`\n    number_integer  | 32768..2147483647                 | int32       | `l`\n    number_integer  | 2147483648..9223372036854775807   | int64       | `L`\n    number_unsigned | 0..127                            | int8        | `i`\n    number_unsigned | 128..255                          | uint8       | `U`\n    number_unsigned | 256..32767                        | int16       | `I`\n    number_unsigned | 32768..2147483647                 | int32       | `l`\n    number_unsigned | 2147483648..9223372036854775807   | int64       | `L`\n    number_float    | *any value*                       | float64     | `D`\n    string          | *with shortest length indicator*  | string      | `S`\n    array           | *see notes on optimized format*   | array       | `[`\n    object          | *see notes on optimized format*   | map         | `{`\n\n    @note The mapping is **complete** in the sense that any JSON value type\n          can be converted to a UBJSON value.\n\n    @note The following values can **not** be converted to a UBJSON value:\n          - strings with more than 9223372036854775807 bytes (theoretical)\n          - unsigned integer numbers above 9223372036854775807\n\n    @note The following markers are not used in the conversion:\n          - `Z`: no-op values are not created.\n          - `C`: single-byte strings are serialized with `S` markers.\n\n    @note Any UBJSON output created @ref to_ubjson can be successfully parsed\n          by @ref from_ubjson.\n\n    @note If NaN or Infinity are stored inside a JSON number, they are\n          serialized properly. This behavior differs from the @ref dump()\n          function which serializes NaN or Infinity to `null`.\n\n    @note The optimized formats for containers are supported: Parameter\n          @a use_size adds size information to the beginning of a container and\n          removes the closing marker. Parameter @a use_type further checks\n          whether all elements of a container have the same type and adds the\n          type marker to the beginning of the container. The @a use_type\n          parameter must only be used together with @a use_size = true. Note\n          that @a use_size = true alone may result in larger representations -\n          the benefit of this parameter is that the receiving side is\n          immediately informed on the number of elements of the container.\n\n    @param[in] j  JSON value to serialize\n    @param[in] use_size  whether to add size annotations to container types\n    @param[in] use_type  whether to add type annotations to container types\n                         (must be combined with @a use_size = true)\n    @return UBJSON serialization as byte vector\n\n    @complexity Linear in the size of the JSON value @a j.\n\n    @liveexample{The example shows the serialization of a JSON value to a byte\n    vector in UBJSON format.,to_ubjson}\n\n    @sa http://ubjson.org\n    @sa @ref from_ubjson(detail::input_adapter&&, const bool, const bool) for the\n        analogous deserialization\n    @sa @ref to_cbor(const basic_json& for the related CBOR format\n    @sa @ref to_msgpack(const basic_json&) for the related MessagePack format\n\n    @since version 3.1.0\n    */\n    static std::vector<uint8_t> to_ubjson(const basic_json& j,\n                                          const bool use_size = false,\n                                          const bool use_type = false)\n    {\n        std::vector<uint8_t> result;\n        to_ubjson(j, result, use_size, use_type);\n        return result;\n    }\n\n    static void to_ubjson(const basic_json& j, detail::output_adapter<uint8_t> o,\n                          const bool use_size = false, const bool use_type = false)\n    {\n        binary_writer<uint8_t>(o).write_ubjson(j, use_size, use_type);\n    }\n\n    static void to_ubjson(const basic_json& j, detail::output_adapter<char> o,\n                          const bool use_size = false, const bool use_type = false)\n    {\n        binary_writer<char>(o).write_ubjson(j, use_size, use_type);\n    }\n\n\n    /*!\n    @brief Serializes the given JSON object `j` to BSON and returns a vector\n           containing the corresponding BSON-representation.\n\n    BSON (Binary JSON) is a binary format in which zero or more ordered key/value pairs are\n    stored as a single entity (a so-called document).\n\n    The library uses the following mapping from JSON values types to BSON types:\n\n    JSON value type | value/range                       | BSON type   | marker\n    --------------- | --------------------------------- | ----------- | ------\n    null            | `null`                            | null        | 0x0A\n    boolean         | `true`, `false`                   | boolean     | 0x08\n    number_integer  | -9223372036854775808..-2147483649 | int64       | 0x12\n    number_integer  | -2147483648..2147483647           | int32       | 0x10\n    number_integer  | 2147483648..9223372036854775807   | int64       | 0x12\n    number_unsigned | 0..2147483647                     | int32       | 0x10\n    number_unsigned | 2147483648..9223372036854775807   | int64       | 0x12\n    number_unsigned | 9223372036854775808..18446744073709551615| --   | --\n    number_float    | *any value*                       | double      | 0x01\n    string          | *any value*                       | string      | 0x02\n    array           | *any value*                       | document    | 0x04\n    object          | *any value*                       | document    | 0x03\n\n    @warning The mapping is **incomplete**, since only JSON-objects (and things\n    contained therein) can be serialized to BSON.\n    Also, integers larger than 9223372036854775807 cannot be serialized to BSON,\n    and the keys may not contain U+0000, since they are serialized a\n    zero-terminated c-strings.\n\n    @throw out_of_range.407  if `j.is_number_unsigned() && j.get<std::uint64_t>() > 9223372036854775807`\n    @throw out_of_range.409  if a key in `j` contains a NULL (U+0000)\n    @throw type_error.317    if `!j.is_object()`\n\n    @pre The input `j` is required to be an object: `j.is_object() == true`.\n\n    @note Any BSON output created via @ref to_bson can be successfully parsed\n          by @ref from_bson.\n\n    @param[in] j  JSON value to serialize\n    @return BSON serialization as byte vector\n\n    @complexity Linear in the size of the JSON value @a j.\n\n    @liveexample{The example shows the serialization of a JSON value to a byte\n    vector in BSON format.,to_bson}\n\n    @sa http://bsonspec.org/spec.html\n    @sa @ref from_bson(detail::input_adapter&&, const bool strict) for the\n        analogous deserialization\n    @sa @ref to_ubjson(const basic_json&, const bool, const bool) for the\n             related UBJSON format\n    @sa @ref to_cbor(const basic_json&) for the related CBOR format\n    @sa @ref to_msgpack(const basic_json&) for the related MessagePack format\n    */\n    static std::vector<uint8_t> to_bson(const basic_json& j)\n    {\n        std::vector<uint8_t> result;\n        to_bson(j, result);\n        return result;\n    }\n\n    /*!\n    @brief Serializes the given JSON object `j` to BSON and forwards the\n           corresponding BSON-representation to the given output_adapter `o`.\n    @param j The JSON object to convert to BSON.\n    @param o The output adapter that receives the binary BSON representation.\n    @pre The input `j` shall be an object: `j.is_object() == true`\n    @sa @ref to_bson(const basic_json&)\n    */\n    static void to_bson(const basic_json& j, detail::output_adapter<uint8_t> o)\n    {\n        binary_writer<uint8_t>(o).write_bson(j);\n    }\n\n    /*!\n    @copydoc to_bson(const basic_json&, detail::output_adapter<uint8_t>)\n    */\n    static void to_bson(const basic_json& j, detail::output_adapter<char> o)\n    {\n        binary_writer<char>(o).write_bson(j);\n    }\n\n\n    /*!\n    @brief create a JSON value from an input in CBOR format\n\n    Deserializes a given input @a i to a JSON value using the CBOR (Concise\n    Binary Object Representation) serialization format.\n\n    The library maps CBOR types to JSON value types as follows:\n\n    CBOR type              | JSON value type | first byte\n    ---------------------- | --------------- | ----------\n    Integer                | number_unsigned | 0x00..0x17\n    Unsigned integer       | number_unsigned | 0x18\n    Unsigned integer       | number_unsigned | 0x19\n    Unsigned integer       | number_unsigned | 0x1A\n    Unsigned integer       | number_unsigned | 0x1B\n    Negative integer       | number_integer  | 0x20..0x37\n    Negative integer       | number_integer  | 0x38\n    Negative integer       | number_integer  | 0x39\n    Negative integer       | number_integer  | 0x3A\n    Negative integer       | number_integer  | 0x3B\n    Negative integer       | number_integer  | 0x40..0x57\n    UTF-8 string           | string          | 0x60..0x77\n    UTF-8 string           | string          | 0x78\n    UTF-8 string           | string          | 0x79\n    UTF-8 string           | string          | 0x7A\n    UTF-8 string           | string          | 0x7B\n    UTF-8 string           | string          | 0x7F\n    array                  | array           | 0x80..0x97\n    array                  | array           | 0x98\n    array                  | array           | 0x99\n    array                  | array           | 0x9A\n    array                  | array           | 0x9B\n    array                  | array           | 0x9F\n    map                    | object          | 0xA0..0xB7\n    map                    | object          | 0xB8\n    map                    | object          | 0xB9\n    map                    | object          | 0xBA\n    map                    | object          | 0xBB\n    map                    | object          | 0xBF\n    False                  | `false`         | 0xF4\n    True                   | `true`          | 0xF5\n    Null                   | `null`          | 0xF6\n    Half-Precision Float   | number_float    | 0xF9\n    Single-Precision Float | number_float    | 0xFA\n    Double-Precision Float | number_float    | 0xFB\n\n    @warning The mapping is **incomplete** in the sense that not all CBOR\n             types can be converted to a JSON value. The following CBOR types\n             are not supported and will yield parse errors (parse_error.112):\n             - byte strings (0x40..0x5F)\n             - date/time (0xC0..0xC1)\n             - bignum (0xC2..0xC3)\n             - decimal fraction (0xC4)\n             - bigfloat (0xC5)\n             - tagged items (0xC6..0xD4, 0xD8..0xDB)\n             - expected conversions (0xD5..0xD7)\n             - simple values (0xE0..0xF3, 0xF8)\n             - undefined (0xF7)\n\n    @warning CBOR allows map keys of any type, whereas JSON only allows\n             strings as keys in object values. Therefore, CBOR maps with keys\n             other than UTF-8 strings are rejected (parse_error.113).\n\n    @note Any CBOR output created @ref to_cbor can be successfully parsed by\n          @ref from_cbor.\n\n    @param[in] i  an input in CBOR format convertible to an input adapter\n    @param[in] strict  whether to expect the input to be consumed until EOF\n                       (true by default)\n    @param[in] allow_exceptions  whether to throw exceptions in case of a\n    parse error (optional, true by default)\n\n    @return deserialized JSON value\n\n    @throw parse_error.110 if the given input ends prematurely or the end of\n    file was not reached when @a strict was set to true\n    @throw parse_error.112 if unsupported features from CBOR were\n    used in the given input @a v or if the input is not valid CBOR\n    @throw parse_error.113 if a string was expected as map key, but not found\n\n    @complexity Linear in the size of the input @a i.\n\n    @liveexample{The example shows the deserialization of a byte vector in CBOR\n    format to a JSON value.,from_cbor}\n\n    @sa http://cbor.io\n    @sa @ref to_cbor(const basic_json&) for the analogous serialization\n    @sa @ref from_msgpack(detail::input_adapter&&, const bool, const bool) for the\n        related MessagePack format\n    @sa @ref from_ubjson(detail::input_adapter&&, const bool, const bool) for the\n        related UBJSON format\n\n    @since version 2.0.9; parameter @a start_index since 2.1.1; changed to\n           consume input adapters, removed start_index parameter, and added\n           @a strict parameter since 3.0.0; added @a allow_exceptions parameter\n           since 3.2.0\n    */\n    static basic_json from_cbor(detail::input_adapter&& i,\n                                const bool strict = true,\n                                const bool allow_exceptions = true)\n    {\n        basic_json result;\n        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);\n        const bool res = binary_reader(detail::input_adapter(i)).sax_parse(input_format_t::cbor, &sdp, strict);\n        return res ? result : basic_json(value_t::discarded);\n    }\n\n    /*!\n    @copydoc from_cbor(detail::input_adapter&&, const bool, const bool)\n    */\n    template<typename A1, typename A2,\n             detail::enable_if_t<std::is_constructible<detail::input_adapter, A1, A2>::value, int> = 0>\n    static basic_json from_cbor(A1 && a1, A2 && a2,\n                                const bool strict = true,\n                                const bool allow_exceptions = true)\n    {\n        basic_json result;\n        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);\n        const bool res = binary_reader(detail::input_adapter(std::forward<A1>(a1), std::forward<A2>(a2))).sax_parse(input_format_t::cbor, &sdp, strict);\n        return res ? result : basic_json(value_t::discarded);\n    }\n\n    /*!\n    @brief create a JSON value from an input in MessagePack format\n\n    Deserializes a given input @a i to a JSON value using the MessagePack\n    serialization format.\n\n    The library maps MessagePack types to JSON value types as follows:\n\n    MessagePack type | JSON value type | first byte\n    ---------------- | --------------- | ----------\n    positive fixint  | number_unsigned | 0x00..0x7F\n    fixmap           | object          | 0x80..0x8F\n    fixarray         | array           | 0x90..0x9F\n    fixstr           | string          | 0xA0..0xBF\n    nil              | `null`          | 0xC0\n    false            | `false`         | 0xC2\n    true             | `true`          | 0xC3\n    float 32         | number_float    | 0xCA\n    float 64         | number_float    | 0xCB\n    uint 8           | number_unsigned | 0xCC\n    uint 16          | number_unsigned | 0xCD\n    uint 32          | number_unsigned | 0xCE\n    uint 64          | number_unsigned | 0xCF\n    int 8            | number_integer  | 0xD0\n    int 16           | number_integer  | 0xD1\n    int 32           | number_integer  | 0xD2\n    int 64           | number_integer  | 0xD3\n    str 8            | string          | 0xD9\n    str 16           | string          | 0xDA\n    str 32           | string          | 0xDB\n    array 16         | array           | 0xDC\n    array 32         | array           | 0xDD\n    map 16           | object          | 0xDE\n    map 32           | object          | 0xDF\n    negative fixint  | number_integer  | 0xE0-0xFF\n\n    @warning The mapping is **incomplete** in the sense that not all\n             MessagePack types can be converted to a JSON value. The following\n             MessagePack types are not supported and will yield parse errors:\n              - bin 8 - bin 32 (0xC4..0xC6)\n              - ext 8 - ext 32 (0xC7..0xC9)\n              - fixext 1 - fixext 16 (0xD4..0xD8)\n\n    @note Any MessagePack output created @ref to_msgpack can be successfully\n          parsed by @ref from_msgpack.\n\n    @param[in] i  an input in MessagePack format convertible to an input\n                  adapter\n    @param[in] strict  whether to expect the input to be consumed until EOF\n                       (true by default)\n    @param[in] allow_exceptions  whether to throw exceptions in case of a\n    parse error (optional, true by default)\n\n    @return deserialized JSON value\n\n    @throw parse_error.110 if the given input ends prematurely or the end of\n    file was not reached when @a strict was set to true\n    @throw parse_error.112 if unsupported features from MessagePack were\n    used in the given input @a i or if the input is not valid MessagePack\n    @throw parse_error.113 if a string was expected as map key, but not found\n\n    @complexity Linear in the size of the input @a i.\n\n    @liveexample{The example shows the deserialization of a byte vector in\n    MessagePack format to a JSON value.,from_msgpack}\n\n    @sa http://msgpack.org\n    @sa @ref to_msgpack(const basic_json&) for the analogous serialization\n    @sa @ref from_cbor(detail::input_adapter&&, const bool, const bool) for the\n        related CBOR format\n    @sa @ref from_ubjson(detail::input_adapter&&, const bool, const bool) for\n        the related UBJSON format\n    @sa @ref from_bson(detail::input_adapter&&, const bool, const bool) for\n        the related BSON format\n\n    @since version 2.0.9; parameter @a start_index since 2.1.1; changed to\n           consume input adapters, removed start_index parameter, and added\n           @a strict parameter since 3.0.0; added @a allow_exceptions parameter\n           since 3.2.0\n    */\n    static basic_json from_msgpack(detail::input_adapter&& i,\n                                   const bool strict = true,\n                                   const bool allow_exceptions = true)\n    {\n        basic_json result;\n        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);\n        const bool res = binary_reader(detail::input_adapter(i)).sax_parse(input_format_t::msgpack, &sdp, strict);\n        return res ? result : basic_json(value_t::discarded);\n    }\n\n    /*!\n    @copydoc from_msgpack(detail::input_adapter&&, const bool, const bool)\n    */\n    template<typename A1, typename A2,\n             detail::enable_if_t<std::is_constructible<detail::input_adapter, A1, A2>::value, int> = 0>\n    static basic_json from_msgpack(A1 && a1, A2 && a2,\n                                   const bool strict = true,\n                                   const bool allow_exceptions = true)\n    {\n        basic_json result;\n        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);\n        const bool res = binary_reader(detail::input_adapter(std::forward<A1>(a1), std::forward<A2>(a2))).sax_parse(input_format_t::msgpack, &sdp, strict);\n        return res ? result : basic_json(value_t::discarded);\n    }\n\n    /*!\n    @brief create a JSON value from an input in UBJSON format\n\n    Deserializes a given input @a i to a JSON value using the UBJSON (Universal\n    Binary JSON) serialization format.\n\n    The library maps UBJSON types to JSON value types as follows:\n\n    UBJSON type | JSON value type                         | marker\n    ----------- | --------------------------------------- | ------\n    no-op       | *no value, next value is read*          | `N`\n    null        | `null`                                  | `Z`\n    false       | `false`                                 | `F`\n    true        | `true`                                  | `T`\n    float32     | number_float                            | `d`\n    float64     | number_float                            | `D`\n    uint8       | number_unsigned                         | `U`\n    int8        | number_integer                          | `i`\n    int16       | number_integer                          | `I`\n    int32       | number_integer                          | `l`\n    int64       | number_integer                          | `L`\n    string      | string                                  | `S`\n    char        | string                                  | `C`\n    array       | array (optimized values are supported)  | `[`\n    object      | object (optimized values are supported) | `{`\n\n    @note The mapping is **complete** in the sense that any UBJSON value can\n          be converted to a JSON value.\n\n    @param[in] i  an input in UBJSON format convertible to an input adapter\n    @param[in] strict  whether to expect the input to be consumed until EOF\n                       (true by default)\n    @param[in] allow_exceptions  whether to throw exceptions in case of a\n    parse error (optional, true by default)\n\n    @return deserialized JSON value\n\n    @throw parse_error.110 if the given input ends prematurely or the end of\n    file was not reached when @a strict was set to true\n    @throw parse_error.112 if a parse error occurs\n    @throw parse_error.113 if a string could not be parsed successfully\n\n    @complexity Linear in the size of the input @a i.\n\n    @liveexample{The example shows the deserialization of a byte vector in\n    UBJSON format to a JSON value.,from_ubjson}\n\n    @sa http://ubjson.org\n    @sa @ref to_ubjson(const basic_json&, const bool, const bool) for the\n             analogous serialization\n    @sa @ref from_cbor(detail::input_adapter&&, const bool, const bool) for the\n        related CBOR format\n    @sa @ref from_msgpack(detail::input_adapter&&, const bool, const bool) for\n        the related MessagePack format\n    @sa @ref from_bson(detail::input_adapter&&, const bool, const bool) for\n        the related BSON format\n\n    @since version 3.1.0; added @a allow_exceptions parameter since 3.2.0\n    */\n    static basic_json from_ubjson(detail::input_adapter&& i,\n                                  const bool strict = true,\n                                  const bool allow_exceptions = true)\n    {\n        basic_json result;\n        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);\n        const bool res = binary_reader(detail::input_adapter(i)).sax_parse(input_format_t::ubjson, &sdp, strict);\n        return res ? result : basic_json(value_t::discarded);\n    }\n\n    /*!\n    @copydoc from_ubjson(detail::input_adapter&&, const bool, const bool)\n    */\n    template<typename A1, typename A2,\n             detail::enable_if_t<std::is_constructible<detail::input_adapter, A1, A2>::value, int> = 0>\n    static basic_json from_ubjson(A1 && a1, A2 && a2,\n                                  const bool strict = true,\n                                  const bool allow_exceptions = true)\n    {\n        basic_json result;\n        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);\n        const bool res = binary_reader(detail::input_adapter(std::forward<A1>(a1), std::forward<A2>(a2))).sax_parse(input_format_t::ubjson, &sdp, strict);\n        return res ? result : basic_json(value_t::discarded);\n    }\n\n    /*!\n    @brief Create a JSON value from an input in BSON format\n\n    Deserializes a given input @a i to a JSON value using the BSON (Binary JSON)\n    serialization format.\n\n    The library maps BSON record types to JSON value types as follows:\n\n    BSON type       | BSON marker byte | JSON value type\n    --------------- | ---------------- | ---------------------------\n    double          | 0x01             | number_float\n    string          | 0x02             | string\n    document        | 0x03             | object\n    array           | 0x04             | array\n    binary          | 0x05             | still unsupported\n    undefined       | 0x06             | still unsupported\n    ObjectId        | 0x07             | still unsupported\n    boolean         | 0x08             | boolean\n    UTC Date-Time   | 0x09             | still unsupported\n    null            | 0x0A             | null\n    Regular Expr.   | 0x0B             | still unsupported\n    DB Pointer      | 0x0C             | still unsupported\n    JavaScript Code | 0x0D             | still unsupported\n    Symbol          | 0x0E             | still unsupported\n    JavaScript Code | 0x0F             | still unsupported\n    int32           | 0x10             | number_integer\n    Timestamp       | 0x11             | still unsupported\n    128-bit decimal float | 0x13       | still unsupported\n    Max Key         | 0x7F             | still unsupported\n    Min Key         | 0xFF             | still unsupported\n\n    @warning The mapping is **incomplete**. The unsupported mappings\n             are indicated in the table above.\n\n    @param[in] i  an input in BSON format convertible to an input adapter\n    @param[in] strict  whether to expect the input to be consumed until EOF\n                       (true by default)\n    @param[in] allow_exceptions  whether to throw exceptions in case of a\n    parse error (optional, true by default)\n\n    @return deserialized JSON value\n\n    @throw parse_error.114 if an unsupported BSON record type is encountered\n\n    @complexity Linear in the size of the input @a i.\n\n    @liveexample{The example shows the deserialization of a byte vector in\n    BSON format to a JSON value.,from_bson}\n\n    @sa http://bsonspec.org/spec.html\n    @sa @ref to_bson(const basic_json&) for the analogous serialization\n    @sa @ref from_cbor(detail::input_adapter&&, const bool, const bool) for the\n        related CBOR format\n    @sa @ref from_msgpack(detail::input_adapter&&, const bool, const bool) for\n        the related MessagePack format\n    @sa @ref from_ubjson(detail::input_adapter&&, const bool, const bool) for the\n        related UBJSON format\n    */\n    static basic_json from_bson(detail::input_adapter&& i,\n                                const bool strict = true,\n                                const bool allow_exceptions = true)\n    {\n        basic_json result;\n        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);\n        const bool res = binary_reader(detail::input_adapter(i)).sax_parse(input_format_t::bson, &sdp, strict);\n        return res ? result : basic_json(value_t::discarded);\n    }\n\n    /*!\n    @copydoc from_bson(detail::input_adapter&&, const bool, const bool)\n    */\n    template<typename A1, typename A2,\n             detail::enable_if_t<std::is_constructible<detail::input_adapter, A1, A2>::value, int> = 0>\n    static basic_json from_bson(A1 && a1, A2 && a2,\n                                const bool strict = true,\n                                const bool allow_exceptions = true)\n    {\n        basic_json result;\n        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);\n        const bool res = binary_reader(detail::input_adapter(std::forward<A1>(a1), std::forward<A2>(a2))).sax_parse(input_format_t::bson, &sdp, strict);\n        return res ? result : basic_json(value_t::discarded);\n    }\n\n\n\n    /// @}\n\n    //////////////////////////\n    // JSON Pointer support //\n    //////////////////////////\n\n    /// @name JSON Pointer functions\n    /// @{\n\n    /*!\n    @brief access specified element via JSON Pointer\n\n    Uses a JSON pointer to retrieve a reference to the respective JSON value.\n    No bound checking is performed. Similar to @ref operator[](const typename\n    object_t::key_type&), `null` values are created in arrays and objects if\n    necessary.\n\n    In particular:\n    - If the JSON pointer points to an object key that does not exist, it\n      is created an filled with a `null` value before a reference to it\n      is returned.\n    - If the JSON pointer points to an array index that does not exist, it\n      is created an filled with a `null` value before a reference to it\n      is returned. All indices between the current maximum and the given\n      index are also filled with `null`.\n    - The special value `-` is treated as a synonym for the index past the\n      end.\n\n    @param[in] ptr  a JSON pointer\n\n    @return reference to the element pointed to by @a ptr\n\n    @complexity Constant.\n\n    @throw parse_error.106   if an array index begins with '0'\n    @throw parse_error.109   if an array index was not a number\n    @throw out_of_range.404  if the JSON pointer can not be resolved\n\n    @liveexample{The behavior is shown in the example.,operatorjson_pointer}\n\n    @since version 2.0.0\n    */\n    reference operator[](const json_pointer& ptr)\n    {\n        return ptr.get_unchecked(this);\n    }\n\n    /*!\n    @brief access specified element via JSON Pointer\n\n    Uses a JSON pointer to retrieve a reference to the respective JSON value.\n    No bound checking is performed. The function does not change the JSON\n    value; no `null` values are created. In particular, the the special value\n    `-` yields an exception.\n\n    @param[in] ptr  JSON pointer to the desired element\n\n    @return const reference to the element pointed to by @a ptr\n\n    @complexity Constant.\n\n    @throw parse_error.106   if an array index begins with '0'\n    @throw parse_error.109   if an array index was not a number\n    @throw out_of_range.402  if the array index '-' is used\n    @throw out_of_range.404  if the JSON pointer can not be resolved\n\n    @liveexample{The behavior is shown in the example.,operatorjson_pointer_const}\n\n    @since version 2.0.0\n    */\n    const_reference operator[](const json_pointer& ptr) const\n    {\n        return ptr.get_unchecked(this);\n    }\n\n    /*!\n    @brief access specified element via JSON Pointer\n\n    Returns a reference to the element at with specified JSON pointer @a ptr,\n    with bounds checking.\n\n    @param[in] ptr  JSON pointer to the desired element\n\n    @return reference to the element pointed to by @a ptr\n\n    @throw parse_error.106 if an array index in the passed JSON pointer @a ptr\n    begins with '0'. See example below.\n\n    @throw parse_error.109 if an array index in the passed JSON pointer @a ptr\n    is not a number. See example below.\n\n    @throw out_of_range.401 if an array index in the passed JSON pointer @a ptr\n    is out of range. See example below.\n\n    @throw out_of_range.402 if the array index '-' is used in the passed JSON\n    pointer @a ptr. As `at` provides checked access (and no elements are\n    implicitly inserted), the index '-' is always invalid. See example below.\n\n    @throw out_of_range.403 if the JSON pointer describes a key of an object\n    which cannot be found. See example below.\n\n    @throw out_of_range.404 if the JSON pointer @a ptr can not be resolved.\n    See example below.\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes in the JSON value.\n\n    @complexity Constant.\n\n    @since version 2.0.0\n\n    @liveexample{The behavior is shown in the example.,at_json_pointer}\n    */\n    reference at(const json_pointer& ptr)\n    {\n        return ptr.get_checked(this);\n    }\n\n    /*!\n    @brief access specified element via JSON Pointer\n\n    Returns a const reference to the element at with specified JSON pointer @a\n    ptr, with bounds checking.\n\n    @param[in] ptr  JSON pointer to the desired element\n\n    @return reference to the element pointed to by @a ptr\n\n    @throw parse_error.106 if an array index in the passed JSON pointer @a ptr\n    begins with '0'. See example below.\n\n    @throw parse_error.109 if an array index in the passed JSON pointer @a ptr\n    is not a number. See example below.\n\n    @throw out_of_range.401 if an array index in the passed JSON pointer @a ptr\n    is out of range. See example below.\n\n    @throw out_of_range.402 if the array index '-' is used in the passed JSON\n    pointer @a ptr. As `at` provides checked access (and no elements are\n    implicitly inserted), the index '-' is always invalid. See example below.\n\n    @throw out_of_range.403 if the JSON pointer describes a key of an object\n    which cannot be found. See example below.\n\n    @throw out_of_range.404 if the JSON pointer @a ptr can not be resolved.\n    See example below.\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes in the JSON value.\n\n    @complexity Constant.\n\n    @since version 2.0.0\n\n    @liveexample{The behavior is shown in the example.,at_json_pointer_const}\n    */\n    const_reference at(const json_pointer& ptr) const\n    {\n        return ptr.get_checked(this);\n    }\n\n    /*!\n    @brief return flattened JSON value\n\n    The function creates a JSON object whose keys are JSON pointers (see [RFC\n    6901](https://tools.ietf.org/html/rfc6901)) and whose values are all\n    primitive. The original JSON value can be restored using the @ref\n    unflatten() function.\n\n    @return an object that maps JSON pointers to primitive values\n\n    @note Empty objects and arrays are flattened to `null` and will not be\n          reconstructed correctly by the @ref unflatten() function.\n\n    @complexity Linear in the size the JSON value.\n\n    @liveexample{The following code shows how a JSON object is flattened to an\n    object whose keys consist of JSON pointers.,flatten}\n\n    @sa @ref unflatten() for the reverse function\n\n    @since version 2.0.0\n    */\n    basic_json flatten() const\n    {\n        basic_json result(value_t::object);\n        json_pointer::flatten(\"\", *this, result);\n        return result;\n    }\n\n    /*!\n    @brief unflatten a previously flattened JSON value\n\n    The function restores the arbitrary nesting of a JSON value that has been\n    flattened before using the @ref flatten() function. The JSON value must\n    meet certain constraints:\n    1. The value must be an object.\n    2. The keys must be JSON pointers (see\n       [RFC 6901](https://tools.ietf.org/html/rfc6901))\n    3. The mapped values must be primitive JSON types.\n\n    @return the original JSON from a flattened version\n\n    @note Empty objects and arrays are flattened by @ref flatten() to `null`\n          values and can not unflattened to their original type. Apart from\n          this example, for a JSON value `j`, the following is always true:\n          `j == j.flatten().unflatten()`.\n\n    @complexity Linear in the size the JSON value.\n\n    @throw type_error.314  if value is not an object\n    @throw type_error.315  if object values are not primitive\n\n    @liveexample{The following code shows how a flattened JSON object is\n    unflattened into the original nested JSON object.,unflatten}\n\n    @sa @ref flatten() for the reverse function\n\n    @since version 2.0.0\n    */\n    basic_json unflatten() const\n    {\n        return json_pointer::unflatten(*this);\n    }\n\n    /// @}\n\n    //////////////////////////\n    // JSON Patch functions //\n    //////////////////////////\n\n    /// @name JSON Patch functions\n    /// @{\n\n    /*!\n    @brief applies a JSON patch\n\n    [JSON Patch](http://jsonpatch.com) defines a JSON document structure for\n    expressing a sequence of operations to apply to a JSON) document. With\n    this function, a JSON Patch is applied to the current JSON value by\n    executing all operations from the patch.\n\n    @param[in] json_patch  JSON patch document\n    @return patched document\n\n    @note The application of a patch is atomic: Either all operations succeed\n          and the patched document is returned or an exception is thrown. In\n          any case, the original value is not changed: the patch is applied\n          to a copy of the value.\n\n    @throw parse_error.104 if the JSON patch does not consist of an array of\n    objects\n\n    @throw parse_error.105 if the JSON patch is malformed (e.g., mandatory\n    attributes are missing); example: `\"operation add must have member path\"`\n\n    @throw out_of_range.401 if an array index is out of range.\n\n    @throw out_of_range.403 if a JSON pointer inside the patch could not be\n    resolved successfully in the current JSON value; example: `\"key baz not\n    found\"`\n\n    @throw out_of_range.405 if JSON pointer has no parent (\"add\", \"remove\",\n    \"move\")\n\n    @throw other_error.501 if \"test\" operation was unsuccessful\n\n    @complexity Linear in the size of the JSON value and the length of the\n    JSON patch. As usually only a fraction of the JSON value is affected by\n    the patch, the complexity can usually be neglected.\n\n    @liveexample{The following code shows how a JSON patch is applied to a\n    value.,patch}\n\n    @sa @ref diff -- create a JSON patch by comparing two JSON values\n\n    @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902)\n    @sa [RFC 6901 (JSON Pointer)](https://tools.ietf.org/html/rfc6901)\n\n    @since version 2.0.0\n    */\n    basic_json patch(const basic_json& json_patch) const\n    {\n        // make a working copy to apply the patch to\n        basic_json result = *this;\n\n        // the valid JSON Patch operations\n        enum class patch_operations {add, remove, replace, move, copy, test, invalid};\n\n        const auto get_op = [](const std::string & op)\n        {\n            if (op == \"add\")\n            {\n                return patch_operations::add;\n            }\n            if (op == \"remove\")\n            {\n                return patch_operations::remove;\n            }\n            if (op == \"replace\")\n            {\n                return patch_operations::replace;\n            }\n            if (op == \"move\")\n            {\n                return patch_operations::move;\n            }\n            if (op == \"copy\")\n            {\n                return patch_operations::copy;\n            }\n            if (op == \"test\")\n            {\n                return patch_operations::test;\n            }\n\n            return patch_operations::invalid;\n        };\n\n        // wrapper for \"add\" operation; add value at ptr\n        const auto operation_add = [&result](json_pointer & ptr, basic_json val)\n        {\n            // adding to the root of the target document means replacing it\n            if (ptr.is_root())\n            {\n                result = val;\n            }\n            else\n            {\n                // make sure the top element of the pointer exists\n                json_pointer top_pointer = ptr.top();\n                if (top_pointer != ptr)\n                {\n                    result.at(top_pointer);\n                }\n\n                // get reference to parent of JSON pointer ptr\n                const auto last_path = ptr.pop_back();\n                basic_json& parent = result[ptr];\n\n                switch (parent.m_type)\n                {\n                    case value_t::null:\n                    case value_t::object:\n                    {\n                        // use operator[] to add value\n                        parent[last_path] = val;\n                        break;\n                    }\n\n                    case value_t::array:\n                    {\n                        if (last_path == \"-\")\n                        {\n                            // special case: append to back\n                            parent.push_back(val);\n                        }\n                        else\n                        {\n                            const auto idx = json_pointer::array_index(last_path);\n                            if (JSON_UNLIKELY(static_cast<size_type>(idx) > parent.size()))\n                            {\n                                // avoid undefined behavior\n                                JSON_THROW(out_of_range::create(401, \"array index \" + std::to_string(idx) + \" is out of range\"));\n                            }\n\n                            // default case: insert add offset\n                            parent.insert(parent.begin() + static_cast<difference_type>(idx), val);\n                        }\n                        break;\n                    }\n\n                    // LCOV_EXCL_START\n                    default:\n                    {\n                        // if there exists a parent it cannot be primitive\n                        assert(false);\n                    }\n                        // LCOV_EXCL_STOP\n                }\n            }\n        };\n\n        // wrapper for \"remove\" operation; remove value at ptr\n        const auto operation_remove = [&result](json_pointer & ptr)\n        {\n            // get reference to parent of JSON pointer ptr\n            const auto last_path = ptr.pop_back();\n            basic_json& parent = result.at(ptr);\n\n            // remove child\n            if (parent.is_object())\n            {\n                // perform range check\n                auto it = parent.find(last_path);\n                if (JSON_LIKELY(it != parent.end()))\n                {\n                    parent.erase(it);\n                }\n                else\n                {\n                    JSON_THROW(out_of_range::create(403, \"key '\" + last_path + \"' not found\"));\n                }\n            }\n            else if (parent.is_array())\n            {\n                // note erase performs range check\n                parent.erase(static_cast<size_type>(json_pointer::array_index(last_path)));\n            }\n        };\n\n        // type check: top level value must be an array\n        if (JSON_UNLIKELY(not json_patch.is_array()))\n        {\n            JSON_THROW(parse_error::create(104, 0, \"JSON patch must be an array of objects\"));\n        }\n\n        // iterate and apply the operations\n        for (const auto& val : json_patch)\n        {\n            // wrapper to get a value for an operation\n            const auto get_value = [&val](const std::string & op,\n                                          const std::string & member,\n                                          bool string_type) -> basic_json &\n            {\n                // find value\n                auto it = val.m_value.object->find(member);\n\n                // context-sensitive error message\n                const auto error_msg = (op == \"op\") ? \"operation\" : \"operation '\" + op + \"'\";\n\n                // check if desired value is present\n                if (JSON_UNLIKELY(it == val.m_value.object->end()))\n                {\n                    JSON_THROW(parse_error::create(105, 0, error_msg + \" must have member '\" + member + \"'\"));\n                }\n\n                // check if result is of type string\n                if (JSON_UNLIKELY(string_type and not it->second.is_string()))\n                {\n                    JSON_THROW(parse_error::create(105, 0, error_msg + \" must have string member '\" + member + \"'\"));\n                }\n\n                // no error: return value\n                return it->second;\n            };\n\n            // type check: every element of the array must be an object\n            if (JSON_UNLIKELY(not val.is_object()))\n            {\n                JSON_THROW(parse_error::create(104, 0, \"JSON patch must be an array of objects\"));\n            }\n\n            // collect mandatory members\n            const std::string op = get_value(\"op\", \"op\", true);\n            const std::string path = get_value(op, \"path\", true);\n            json_pointer ptr(path);\n\n            switch (get_op(op))\n            {\n                case patch_operations::add:\n                {\n                    operation_add(ptr, get_value(\"add\", \"value\", false));\n                    break;\n                }\n\n                case patch_operations::remove:\n                {\n                    operation_remove(ptr);\n                    break;\n                }\n\n                case patch_operations::replace:\n                {\n                    // the \"path\" location must exist - use at()\n                    result.at(ptr) = get_value(\"replace\", \"value\", false);\n                    break;\n                }\n\n                case patch_operations::move:\n                {\n                    const std::string from_path = get_value(\"move\", \"from\", true);\n                    json_pointer from_ptr(from_path);\n\n                    // the \"from\" location must exist - use at()\n                    basic_json v = result.at(from_ptr);\n\n                    // The move operation is functionally identical to a\n                    // \"remove\" operation on the \"from\" location, followed\n                    // immediately by an \"add\" operation at the target\n                    // location with the value that was just removed.\n                    operation_remove(from_ptr);\n                    operation_add(ptr, v);\n                    break;\n                }\n\n                case patch_operations::copy:\n                {\n                    const std::string from_path = get_value(\"copy\", \"from\", true);\n                    const json_pointer from_ptr(from_path);\n\n                    // the \"from\" location must exist - use at()\n                    basic_json v = result.at(from_ptr);\n\n                    // The copy is functionally identical to an \"add\"\n                    // operation at the target location using the value\n                    // specified in the \"from\" member.\n                    operation_add(ptr, v);\n                    break;\n                }\n\n                case patch_operations::test:\n                {\n                    bool success = false;\n                    JSON_TRY\n                    {\n                        // check if \"value\" matches the one at \"path\"\n                        // the \"path\" location must exist - use at()\n                        success = (result.at(ptr) == get_value(\"test\", \"value\", false));\n                    }\n                    JSON_INTERNAL_CATCH (out_of_range&)\n                    {\n                        // ignore out of range errors: success remains false\n                    }\n\n                    // throw an exception if test fails\n                    if (JSON_UNLIKELY(not success))\n                    {\n                        JSON_THROW(other_error::create(501, \"unsuccessful: \" + val.dump()));\n                    }\n\n                    break;\n                }\n\n                case patch_operations::invalid:\n                {\n                    // op must be \"add\", \"remove\", \"replace\", \"move\", \"copy\", or\n                    // \"test\"\n                    JSON_THROW(parse_error::create(105, 0, \"operation value '\" + op + \"' is invalid\"));\n                }\n            }\n        }\n\n        return result;\n    }\n\n    /*!\n    @brief creates a diff as a JSON patch\n\n    Creates a [JSON Patch](http://jsonpatch.com) so that value @a source can\n    be changed into the value @a target by calling @ref patch function.\n\n    @invariant For two JSON values @a source and @a target, the following code\n    yields always `true`:\n    @code {.cpp}\n    source.patch(diff(source, target)) == target;\n    @endcode\n\n    @note Currently, only `remove`, `add`, and `replace` operations are\n          generated.\n\n    @param[in] source  JSON value to compare from\n    @param[in] target  JSON value to compare against\n    @param[in] path    helper value to create JSON pointers\n\n    @return a JSON patch to convert the @a source to @a target\n\n    @complexity Linear in the lengths of @a source and @a target.\n\n    @liveexample{The following code shows how a JSON patch is created as a\n    diff for two JSON values.,diff}\n\n    @sa @ref patch -- apply a JSON patch\n    @sa @ref merge_patch -- apply a JSON Merge Patch\n\n    @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902)\n\n    @since version 2.0.0\n    */\n    static basic_json diff(const basic_json& source, const basic_json& target,\n                           const std::string& path = \"\")\n    {\n        // the patch\n        basic_json result(value_t::array);\n\n        // if the values are the same, return empty patch\n        if (source == target)\n        {\n            return result;\n        }\n\n        if (source.type() != target.type())\n        {\n            // different types: replace value\n            result.push_back(\n            {\n                {\"op\", \"replace\"}, {\"path\", path}, {\"value\", target}\n            });\n        }\n        else\n        {\n            switch (source.type())\n            {\n                case value_t::array:\n                {\n                    // first pass: traverse common elements\n                    std::size_t i = 0;\n                    while (i < source.size() and i < target.size())\n                    {\n                        // recursive call to compare array values at index i\n                        auto temp_diff = diff(source[i], target[i], path + \"/\" + std::to_string(i));\n                        result.insert(result.end(), temp_diff.begin(), temp_diff.end());\n                        ++i;\n                    }\n\n                    // i now reached the end of at least one array\n                    // in a second pass, traverse the remaining elements\n\n                    // remove my remaining elements\n                    const auto end_index = static_cast<difference_type>(result.size());\n                    while (i < source.size())\n                    {\n                        // add operations in reverse order to avoid invalid\n                        // indices\n                        result.insert(result.begin() + end_index, object(\n                        {\n                            {\"op\", \"remove\"},\n                            {\"path\", path + \"/\" + std::to_string(i)}\n                        }));\n                        ++i;\n                    }\n\n                    // add other remaining elements\n                    while (i < target.size())\n                    {\n                        result.push_back(\n                        {\n                            {\"op\", \"add\"},\n                            {\"path\", path + \"/\" + std::to_string(i)},\n                            {\"value\", target[i]}\n                        });\n                        ++i;\n                    }\n\n                    break;\n                }\n\n                case value_t::object:\n                {\n                    // first pass: traverse this object's elements\n                    for (auto it = source.cbegin(); it != source.cend(); ++it)\n                    {\n                        // escape the key name to be used in a JSON patch\n                        const auto key = json_pointer::escape(it.key());\n\n                        if (target.find(it.key()) != target.end())\n                        {\n                            // recursive call to compare object values at key it\n                            auto temp_diff = diff(it.value(), target[it.key()], path + \"/\" + key);\n                            result.insert(result.end(), temp_diff.begin(), temp_diff.end());\n                        }\n                        else\n                        {\n                            // found a key that is not in o -> remove it\n                            result.push_back(object(\n                            {\n                                {\"op\", \"remove\"}, {\"path\", path + \"/\" + key}\n                            }));\n                        }\n                    }\n\n                    // second pass: traverse other object's elements\n                    for (auto it = target.cbegin(); it != target.cend(); ++it)\n                    {\n                        if (source.find(it.key()) == source.end())\n                        {\n                            // found a key that is not in this -> add it\n                            const auto key = json_pointer::escape(it.key());\n                            result.push_back(\n                            {\n                                {\"op\", \"add\"}, {\"path\", path + \"/\" + key},\n                                {\"value\", it.value()}\n                            });\n                        }\n                    }\n\n                    break;\n                }\n\n                default:\n                {\n                    // both primitive type: replace value\n                    result.push_back(\n                    {\n                        {\"op\", \"replace\"}, {\"path\", path}, {\"value\", target}\n                    });\n                    break;\n                }\n            }\n        }\n\n        return result;\n    }\n\n    /// @}\n\n    ////////////////////////////////\n    // JSON Merge Patch functions //\n    ////////////////////////////////\n\n    /// @name JSON Merge Patch functions\n    /// @{\n\n    /*!\n    @brief applies a JSON Merge Patch\n\n    The merge patch format is primarily intended for use with the HTTP PATCH\n    method as a means of describing a set of modifications to a target\n    resource's content. This function applies a merge patch to the current\n    JSON value.\n\n    The function implements the following algorithm from Section 2 of\n    [RFC 7396 (JSON Merge Patch)](https://tools.ietf.org/html/rfc7396):\n\n    ```\n    define MergePatch(Target, Patch):\n      if Patch is an Object:\n        if Target is not an Object:\n          Target = {} // Ignore the contents and set it to an empty Object\n        for each Name/Value pair in Patch:\n          if Value is null:\n            if Name exists in Target:\n              remove the Name/Value pair from Target\n          else:\n            Target[Name] = MergePatch(Target[Name], Value)\n        return Target\n      else:\n        return Patch\n    ```\n\n    Thereby, `Target` is the current object; that is, the patch is applied to\n    the current value.\n\n    @param[in] apply_patch  the patch to apply\n\n    @complexity Linear in the lengths of @a patch.\n\n    @liveexample{The following code shows how a JSON Merge Patch is applied to\n    a JSON document.,merge_patch}\n\n    @sa @ref patch -- apply a JSON patch\n    @sa [RFC 7396 (JSON Merge Patch)](https://tools.ietf.org/html/rfc7396)\n\n    @since version 3.0.0\n    */\n    void merge_patch(const basic_json& apply_patch)\n    {\n        if (apply_patch.is_object())\n        {\n            if (not is_object())\n            {\n                *this = object();\n            }\n            for (auto it = apply_patch.begin(); it != apply_patch.end(); ++it)\n            {\n                if (it.value().is_null())\n                {\n                    erase(it.key());\n                }\n                else\n                {\n                    operator[](it.key()).merge_patch(it.value());\n                }\n            }\n        }\n        else\n        {\n            *this = apply_patch;\n        }\n    }\n\n    /// @}\n};\n} // namespace nlohmann\n\n///////////////////////\n// nonmember support //\n///////////////////////\n\n// specialization of std::swap, and std::hash\nnamespace std\n{\n\n/// hash value for JSON objects\ntemplate<>\nstruct hash<nlohmann::json>\n{\n    /*!\n    @brief return a hash value for a JSON object\n\n    @since version 1.0.0\n    */\n    std::size_t operator()(const nlohmann::json& j) const\n    {\n        // a naive hashing via the string representation\n        const auto& h = hash<nlohmann::json::string_t>();\n        return h(j.dump());\n    }\n};\n\n/// specialization for std::less<value_t>\n/// @note: do not remove the space after '<',\n///        see https://github.com/nlohmann/json/pull/679\ntemplate<>\nstruct less< ::nlohmann::detail::value_t>\n{\n    /*!\n    @brief compare two value_t enum values\n    @since version 3.0.0\n    */\n    bool operator()(nlohmann::detail::value_t lhs,\n                    nlohmann::detail::value_t rhs) const noexcept\n    {\n        return nlohmann::detail::operator<(lhs, rhs);\n    }\n};\n\n/*!\n@brief exchanges the values of two JSON objects\n\n@since version 1.0.0\n*/\ntemplate<>\ninline void swap<nlohmann::json>(nlohmann::json& j1, nlohmann::json& j2) noexcept(\n    is_nothrow_move_constructible<nlohmann::json>::value and\n    is_nothrow_move_assignable<nlohmann::json>::value\n)\n{\n    j1.swap(j2);\n}\n\n} // namespace std\n\n/*!\n@brief user-defined string literal for JSON values\n\nThis operator implements a user-defined string literal for JSON objects. It\ncan be used by adding `\"_json\"` to a string literal and returns a JSON object\nif no parse error occurred.\n\n@param[in] s  a string representation of a JSON object\n@param[in] n  the length of string @a s\n@return a JSON object\n\n@since version 1.0.0\n*/\ninline nlohmann::json operator \"\" _json(const char* s, std::size_t n)\n{\n    return nlohmann::json::parse(s, s + n);\n}\n\n/*!\n@brief user-defined string literal for JSON pointer\n\nThis operator implements a user-defined string literal for JSON Pointers. It\ncan be used by adding `\"_json_pointer\"` to a string literal and returns a JSON pointer\nobject if no parse error occurred.\n\n@param[in] s  a string representation of a JSON Pointer\n@param[in] n  the length of string @a s\n@return a JSON pointer object\n\n@since version 2.0.0\n*/\ninline nlohmann::json::json_pointer operator \"\" _json_pointer(const char* s, std::size_t n)\n{\n    return nlohmann::json::json_pointer(std::string(s, n));\n}\n\n#include <nlohmann/detail/macro_unscope.hpp>\n\n#endif\n"
  },
  {
    "path": "nlohmann_json/include/nlohmann/json_fwd.hpp",
    "content": "#ifndef NLOHMANN_JSON_FWD_HPP\n#define NLOHMANN_JSON_FWD_HPP\n\n#include <cstdint> // int64_t, uint64_t\n#include <map> // map\n#include <memory> // allocator\n#include <string> // string\n#include <vector> // vector\n\n/*!\n@brief namespace for Niels Lohmann\n@see https://github.com/nlohmann\n@since version 1.0.0\n*/\nnamespace nlohmann\n{\n/*!\n@brief default JSONSerializer template argument\n\nThis serializer ignores the template arguments and uses ADL\n([argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl))\nfor serialization.\n*/\ntemplate<typename T = void, typename SFINAE = void>\nstruct adl_serializer;\n\ntemplate<template<typename U, typename V, typename... Args> class ObjectType =\n         std::map,\n         template<typename U, typename... Args> class ArrayType = std::vector,\n         class StringType = std::string, class BooleanType = bool,\n         class NumberIntegerType = std::int64_t,\n         class NumberUnsignedType = std::uint64_t,\n         class NumberFloatType = double,\n         template<typename U> class AllocatorType = std::allocator,\n         template<typename T, typename SFINAE = void> class JSONSerializer =\n         adl_serializer>\nclass basic_json;\n\n/*!\n@brief JSON Pointer\n\nA JSON pointer defines a string syntax for identifying a specific value\nwithin a JSON document. It can be used with functions `at` and\n`operator[]`. Furthermore, JSON pointers are the base for JSON patches.\n\n@sa [RFC 6901](https://tools.ietf.org/html/rfc6901)\n\n@since version 2.0.0\n*/\ntemplate<typename BasicJsonType>\nclass json_pointer;\n\n/*!\n@brief default JSON class\n\nThis type is the default specialization of the @ref basic_json class which\nuses the standard template types.\n\n@since version 1.0.0\n*/\nusing json = basic_json<>;\n}  // namespace nlohmann\n\n#endif\n"
  },
  {
    "path": "nlohmann_json/meson.build",
    "content": "project('nlohmann_json',\n    'cpp',\n    version : '3.5.0',\n    license : 'MIT',\n)\n\nnlohmann_json_dep = declare_dependency(\n    include_directories: include_directories('single_include')\n)\n\nnlohmann_json_multiple_headers = declare_dependency(\n    include_directories: include_directories('include')\n)\n\ninstall_headers('single_include/nlohmann/json.hpp', subdir: 'nlohmann')\n\npkgc = import('pkgconfig')\npkgc.generate(name: 'nlohmann_json',\n    version: meson.project_version(),\n    description: 'JSON for Modern C++'\n)\n"
  },
  {
    "path": "nlohmann_json/nlohmann_json.natvis",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<AutoVisualizer xmlns=\"http://schemas.microsoft.com/vstudio/debugger/natvis/2010\">\n    <Type Name=\"nlohmann::basic_json&lt;*&gt;\">\n        <DisplayString Condition=\"m_type == nlohmann::detail::value_t::null\">null</DisplayString>\n        <DisplayString Condition=\"m_type == nlohmann::detail::value_t::object\">{*(m_value.object)}</DisplayString>\n        <DisplayString Condition=\"m_type == nlohmann::detail::value_t::array\">{*(m_value.array)}</DisplayString>\n        <DisplayString Condition=\"m_type == nlohmann::detail::value_t::string\">{*(m_value.string)}</DisplayString>\n        <DisplayString Condition=\"m_type == nlohmann::detail::value_t::boolean\">{m_value.boolean}</DisplayString>\n        <DisplayString Condition=\"m_type == nlohmann::detail::value_t::number_integer\">{m_value.number_integer}</DisplayString>\n        <DisplayString Condition=\"m_type == nlohmann::detail::value_t::number_unsigned\">{m_value.number_unsigned}</DisplayString>\n        <DisplayString Condition=\"m_type == nlohmann::detail::value_t::number_float\">{m_value.number_float}</DisplayString>\n        <DisplayString Condition=\"m_type == nlohmann::detail::value_t::discarded\">discarded</DisplayString>\n        <Expand>\n            <ExpandedItem Condition=\"m_type == nlohmann::detail::value_t::object\">\n                *(m_value.object),view(simple)\n            </ExpandedItem>\n            <ExpandedItem Condition=\"m_type == nlohmann::detail::value_t::array\">\n                *(m_value.array),view(simple)\n            </ExpandedItem>\n        </Expand>\n    </Type>\n\n    <!--    skip the pair first/second members in the treeview while traversing a map.\n            Only works in VS 2015 Update 2 and beyond using the new visualization -->\n    <Type Name=\"std::pair&lt;*, nlohmann::basic_json&lt;*&gt;&gt;\" IncludeView=\"MapHelper\">\n        <DisplayString>{second}</DisplayString>\n        <Expand>\n            <ExpandedItem>second</ExpandedItem>\n        </Expand>\n    </Type>\n\n</AutoVisualizer>\n"
  },
  {
    "path": "nlohmann_json/single_include/nlohmann/json.hpp",
    "content": "/*\n    __ _____ _____ _____\n __|  |   __|     |   | |  JSON for Modern C++\n|  |  |__   |  |  | | | |  version 3.5.0\n|_____|_____|_____|_|___|  https://github.com/nlohmann/json\n\nLicensed under the MIT License <http://opensource.org/licenses/MIT>.\nSPDX-License-Identifier: MIT\nCopyright (c) 2013-2018 Niels Lohmann <http://nlohmann.me>.\n\nPermission is hereby  granted, free of charge, to any  person obtaining a copy\nof this software and associated  documentation files (the \"Software\"), to deal\nin the Software  without restriction, including without  limitation the rights\nto  use, copy,  modify, merge,  publish, distribute,  sublicense, and/or  sell\ncopies  of  the Software,  and  to  permit persons  to  whom  the Software  is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE  IS PROVIDED \"AS  IS\", WITHOUT WARRANTY  OF ANY KIND,  EXPRESS OR\nIMPLIED,  INCLUDING BUT  NOT  LIMITED TO  THE  WARRANTIES OF  MERCHANTABILITY,\nFITNESS FOR  A PARTICULAR PURPOSE AND  NONINFRINGEMENT. IN NO EVENT  SHALL THE\nAUTHORS  OR COPYRIGHT  HOLDERS  BE  LIABLE FOR  ANY  CLAIM,  DAMAGES OR  OTHER\nLIABILITY, WHETHER IN AN ACTION OF  CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE  OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n*/\n\n#ifndef NLOHMANN_JSON_HPP\n#define NLOHMANN_JSON_HPP\n\n#define NLOHMANN_JSON_VERSION_MAJOR 3\n#define NLOHMANN_JSON_VERSION_MINOR 5\n#define NLOHMANN_JSON_VERSION_PATCH 0\n\n#include <algorithm> // all_of, find, for_each\n#include <cassert> // assert\n#include <ciso646> // and, not, or\n#include <cstddef> // nullptr_t, ptrdiff_t, size_t\n#include <functional> // hash, less\n#include <initializer_list> // initializer_list\n#include <iosfwd> // istream, ostream\n#include <iterator> // random_access_iterator_tag\n#include <numeric> // accumulate\n#include <string> // string, stoi, to_string\n#include <utility> // declval, forward, move, pair, swap\n\n// #include <nlohmann/json_fwd.hpp>\n#ifndef NLOHMANN_JSON_FWD_HPP\n#define NLOHMANN_JSON_FWD_HPP\n\n#include <cstdint> // int64_t, uint64_t\n#include <map> // map\n#include <memory> // allocator\n#include <string> // string\n#include <vector> // vector\n\n/*!\n@brief namespace for Niels Lohmann\n@see https://github.com/nlohmann\n@since version 1.0.0\n*/\nnamespace nlohmann\n{\n/*!\n@brief default JSONSerializer template argument\n\nThis serializer ignores the template arguments and uses ADL\n([argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl))\nfor serialization.\n*/\ntemplate<typename T = void, typename SFINAE = void>\nstruct adl_serializer;\n\ntemplate<template<typename U, typename V, typename... Args> class ObjectType =\n         std::map,\n         template<typename U, typename... Args> class ArrayType = std::vector,\n         class StringType = std::string, class BooleanType = bool,\n         class NumberIntegerType = std::int64_t,\n         class NumberUnsignedType = std::uint64_t,\n         class NumberFloatType = double,\n         template<typename U> class AllocatorType = std::allocator,\n         template<typename T, typename SFINAE = void> class JSONSerializer =\n         adl_serializer>\nclass basic_json;\n\n/*!\n@brief JSON Pointer\n\nA JSON pointer defines a string syntax for identifying a specific value\nwithin a JSON document. It can be used with functions `at` and\n`operator[]`. Furthermore, JSON pointers are the base for JSON patches.\n\n@sa [RFC 6901](https://tools.ietf.org/html/rfc6901)\n\n@since version 2.0.0\n*/\ntemplate<typename BasicJsonType>\nclass json_pointer;\n\n/*!\n@brief default JSON class\n\nThis type is the default specialization of the @ref basic_json class which\nuses the standard template types.\n\n@since version 1.0.0\n*/\nusing json = basic_json<>;\n}  // namespace nlohmann\n\n#endif\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n\n// This file contains all internal macro definitions\n// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them\n\n// exclude unsupported compilers\n#if !defined(JSON_SKIP_UNSUPPORTED_COMPILER_CHECK)\n    #if defined(__clang__)\n        #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400\n            #error \"unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers\"\n        #endif\n    #elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER))\n        #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40800\n            #error \"unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers\"\n        #endif\n    #endif\n#endif\n\n// disable float-equal warnings on GCC/clang\n#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)\n    #pragma GCC diagnostic push\n    #pragma GCC diagnostic ignored \"-Wfloat-equal\"\n#endif\n\n// disable documentation warnings on clang\n#if defined(__clang__)\n    #pragma GCC diagnostic push\n    #pragma GCC diagnostic ignored \"-Wdocumentation\"\n#endif\n\n// allow for portable deprecation warnings\n#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)\n    #define JSON_DEPRECATED __attribute__((deprecated))\n#elif defined(_MSC_VER)\n    #define JSON_DEPRECATED __declspec(deprecated)\n#else\n    #define JSON_DEPRECATED\n#endif\n\n// allow to disable exceptions\n#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION)\n    #define JSON_THROW(exception) throw exception\n    #define JSON_TRY try\n    #define JSON_CATCH(exception) catch(exception)\n    #define JSON_INTERNAL_CATCH(exception) catch(exception)\n#else\n    #define JSON_THROW(exception) std::abort()\n    #define JSON_TRY if(true)\n    #define JSON_CATCH(exception) if(false)\n    #define JSON_INTERNAL_CATCH(exception) if(false)\n#endif\n\n// override exception macros\n#if defined(JSON_THROW_USER)\n    #undef JSON_THROW\n    #define JSON_THROW JSON_THROW_USER\n#endif\n#if defined(JSON_TRY_USER)\n    #undef JSON_TRY\n    #define JSON_TRY JSON_TRY_USER\n#endif\n#if defined(JSON_CATCH_USER)\n    #undef JSON_CATCH\n    #define JSON_CATCH JSON_CATCH_USER\n    #undef JSON_INTERNAL_CATCH\n    #define JSON_INTERNAL_CATCH JSON_CATCH_USER\n#endif\n#if defined(JSON_INTERNAL_CATCH_USER)\n    #undef JSON_INTERNAL_CATCH\n    #define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER\n#endif\n\n// manual branch prediction\n#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)\n    #define JSON_LIKELY(x)      __builtin_expect(!!(x), 1)\n    #define JSON_UNLIKELY(x)    __builtin_expect(!!(x), 0)\n#else\n    #define JSON_LIKELY(x)      x\n    #define JSON_UNLIKELY(x)    x\n#endif\n\n// C++ language standard detection\n#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464\n    #define JSON_HAS_CPP_17\n    #define JSON_HAS_CPP_14\n#elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1)\n    #define JSON_HAS_CPP_14\n#endif\n\n/*!\n@brief macro to briefly define a mapping between an enum and JSON\n@def NLOHMANN_JSON_SERIALIZE_ENUM\n@since version 3.4.0\n*/\n#define NLOHMANN_JSON_SERIALIZE_ENUM(ENUM_TYPE, ...)                                           \\\n    template<typename BasicJsonType>                                                           \\\n    inline void to_json(BasicJsonType& j, const ENUM_TYPE& e)                                  \\\n    {                                                                                          \\\n        static_assert(std::is_enum<ENUM_TYPE>::value, #ENUM_TYPE \" must be an enum!\");         \\\n        static const std::pair<ENUM_TYPE, BasicJsonType> m[] = __VA_ARGS__;                    \\\n        auto it = std::find_if(std::begin(m), std::end(m),                                     \\\n                               [e](const std::pair<ENUM_TYPE, BasicJsonType>& ej_pair) -> bool \\\n        {                                                                                      \\\n            return ej_pair.first == e;                                                         \\\n        });                                                                                    \\\n        j = ((it != std::end(m)) ? it : std::begin(m))->second;                                \\\n    }                                                                                          \\\n    template<typename BasicJsonType>                                                           \\\n    inline void from_json(const BasicJsonType& j, ENUM_TYPE& e)                                \\\n    {                                                                                          \\\n        static_assert(std::is_enum<ENUM_TYPE>::value, #ENUM_TYPE \" must be an enum!\");         \\\n        static const std::pair<ENUM_TYPE, BasicJsonType> m[] = __VA_ARGS__;                    \\\n        auto it = std::find_if(std::begin(m), std::end(m),                                     \\\n                               [j](const std::pair<ENUM_TYPE, BasicJsonType>& ej_pair) -> bool \\\n        {                                                                                      \\\n            return ej_pair.second == j;                                                        \\\n        });                                                                                    \\\n        e = ((it != std::end(m)) ? it : std::begin(m))->first;                                 \\\n    }\n\n// Ugly macros to avoid uglier copy-paste when specializing basic_json. They\n// may be removed in the future once the class is split.\n\n#define NLOHMANN_BASIC_JSON_TPL_DECLARATION                                \\\n    template<template<typename, typename, typename...> class ObjectType,   \\\n             template<typename, typename...> class ArrayType,              \\\n             class StringType, class BooleanType, class NumberIntegerType, \\\n             class NumberUnsignedType, class NumberFloatType,              \\\n             template<typename> class AllocatorType,                       \\\n             template<typename, typename = void> class JSONSerializer>\n\n#define NLOHMANN_BASIC_JSON_TPL                                            \\\n    basic_json<ObjectType, ArrayType, StringType, BooleanType,             \\\n    NumberIntegerType, NumberUnsignedType, NumberFloatType,                \\\n    AllocatorType, JSONSerializer>\n\n// #include <nlohmann/detail/meta/cpp_future.hpp>\n\n\n#include <ciso646> // not\n#include <cstddef> // size_t\n#include <type_traits> // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type\n\nnamespace nlohmann\n{\nnamespace detail\n{\n// alias templates to reduce boilerplate\ntemplate<bool B, typename T = void>\nusing enable_if_t = typename std::enable_if<B, T>::type;\n\ntemplate<typename T>\nusing uncvref_t = typename std::remove_cv<typename std::remove_reference<T>::type>::type;\n\n// implementation of C++14 index_sequence and affiliates\n// source: https://stackoverflow.com/a/32223343\ntemplate<std::size_t... Ints>\nstruct index_sequence\n{\n    using type = index_sequence;\n    using value_type = std::size_t;\n    static constexpr std::size_t size() noexcept\n    {\n        return sizeof...(Ints);\n    }\n};\n\ntemplate<class Sequence1, class Sequence2>\nstruct merge_and_renumber;\n\ntemplate<std::size_t... I1, std::size_t... I2>\nstruct merge_and_renumber<index_sequence<I1...>, index_sequence<I2...>>\n        : index_sequence < I1..., (sizeof...(I1) + I2)... > {};\n\ntemplate<std::size_t N>\nstruct make_index_sequence\n    : merge_and_renumber < typename make_index_sequence < N / 2 >::type,\n      typename make_index_sequence < N - N / 2 >::type > {};\n\ntemplate<> struct make_index_sequence<0> : index_sequence<> {};\ntemplate<> struct make_index_sequence<1> : index_sequence<0> {};\n\ntemplate<typename... Ts>\nusing index_sequence_for = make_index_sequence<sizeof...(Ts)>;\n\n// dispatch utility (taken from ranges-v3)\ntemplate<unsigned N> struct priority_tag : priority_tag < N - 1 > {};\ntemplate<> struct priority_tag<0> {};\n\n// taken from ranges-v3\ntemplate<typename T>\nstruct static_const\n{\n    static constexpr T value{};\n};\n\ntemplate<typename T>\nconstexpr T static_const<T>::value;\n}  // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/meta/type_traits.hpp>\n\n\n#include <ciso646> // not\n#include <limits> // numeric_limits\n#include <type_traits> // false_type, is_constructible, is_integral, is_same, true_type\n#include <utility> // declval\n\n// #include <nlohmann/json_fwd.hpp>\n\n// #include <nlohmann/detail/iterators/iterator_traits.hpp>\n\n\n#include <iterator> // random_access_iterator_tag\n\n// #include <nlohmann/detail/meta/void_t.hpp>\n\n\nnamespace nlohmann\n{\nnamespace detail\n{\ntemplate <typename ...Ts> struct make_void\n{\n    using type = void;\n};\ntemplate <typename ...Ts> using void_t = typename make_void<Ts...>::type;\n} // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/meta/cpp_future.hpp>\n\n\nnamespace nlohmann\n{\nnamespace detail\n{\ntemplate <typename It, typename = void>\nstruct iterator_types {};\n\ntemplate <typename It>\nstruct iterator_types <\n    It,\n    void_t<typename It::difference_type, typename It::value_type, typename It::pointer,\n    typename It::reference, typename It::iterator_category >>\n{\n    using difference_type = typename It::difference_type;\n    using value_type = typename It::value_type;\n    using pointer = typename It::pointer;\n    using reference = typename It::reference;\n    using iterator_category = typename It::iterator_category;\n};\n\n// This is required as some compilers implement std::iterator_traits in a way that\n// doesn't work with SFINAE. See https://github.com/nlohmann/json/issues/1341.\ntemplate <typename T, typename = void>\nstruct iterator_traits\n{\n};\n\ntemplate <typename T>\nstruct iterator_traits < T, enable_if_t < !std::is_pointer<T>::value >>\n            : iterator_types<T>\n{\n};\n\ntemplate <typename T>\nstruct iterator_traits<T*, enable_if_t<std::is_object<T>::value>>\n{\n    using iterator_category = std::random_access_iterator_tag;\n    using value_type = T;\n    using difference_type = ptrdiff_t;\n    using pointer = T*;\n    using reference = T&;\n};\n}\n}\n\n// #include <nlohmann/detail/meta/cpp_future.hpp>\n\n// #include <nlohmann/detail/meta/detected.hpp>\n\n\n#include <type_traits>\n\n// #include <nlohmann/detail/meta/void_t.hpp>\n\n\n// http://en.cppreference.com/w/cpp/experimental/is_detected\nnamespace nlohmann\n{\nnamespace detail\n{\nstruct nonesuch\n{\n    nonesuch() = delete;\n    ~nonesuch() = delete;\n    nonesuch(nonesuch const&) = delete;\n    void operator=(nonesuch const&) = delete;\n};\n\ntemplate <class Default,\n          class AlwaysVoid,\n          template <class...> class Op,\n          class... Args>\nstruct detector\n{\n    using value_t = std::false_type;\n    using type = Default;\n};\n\ntemplate <class Default, template <class...> class Op, class... Args>\nstruct detector<Default, void_t<Op<Args...>>, Op, Args...>\n{\n    using value_t = std::true_type;\n    using type = Op<Args...>;\n};\n\ntemplate <template <class...> class Op, class... Args>\nusing is_detected = typename detector<nonesuch, void, Op, Args...>::value_t;\n\ntemplate <template <class...> class Op, class... Args>\nusing detected_t = typename detector<nonesuch, void, Op, Args...>::type;\n\ntemplate <class Default, template <class...> class Op, class... Args>\nusing detected_or = detector<Default, void, Op, Args...>;\n\ntemplate <class Default, template <class...> class Op, class... Args>\nusing detected_or_t = typename detected_or<Default, Op, Args...>::type;\n\ntemplate <class Expected, template <class...> class Op, class... Args>\nusing is_detected_exact = std::is_same<Expected, detected_t<Op, Args...>>;\n\ntemplate <class To, template <class...> class Op, class... Args>\nusing is_detected_convertible =\n    std::is_convertible<detected_t<Op, Args...>, To>;\n}  // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n\nnamespace nlohmann\n{\n/*!\n@brief detail namespace with internal helper functions\n\nThis namespace collects functions that should not be exposed,\nimplementations of some @ref basic_json methods, and meta-programming helpers.\n\n@since version 2.1.0\n*/\nnamespace detail\n{\n/////////////\n// helpers //\n/////////////\n\n// Note to maintainers:\n//\n// Every trait in this file expects a non CV-qualified type.\n// The only exceptions are in the 'aliases for detected' section\n// (i.e. those of the form: decltype(T::member_function(std::declval<T>())))\n//\n// In this case, T has to be properly CV-qualified to constraint the function arguments\n// (e.g. to_json(BasicJsonType&, const T&))\n\ntemplate<typename> struct is_basic_json : std::false_type {};\n\nNLOHMANN_BASIC_JSON_TPL_DECLARATION\nstruct is_basic_json<NLOHMANN_BASIC_JSON_TPL> : std::true_type {};\n\n//////////////////////////\n// aliases for detected //\n//////////////////////////\n\ntemplate <typename T>\nusing mapped_type_t = typename T::mapped_type;\n\ntemplate <typename T>\nusing key_type_t = typename T::key_type;\n\ntemplate <typename T>\nusing value_type_t = typename T::value_type;\n\ntemplate <typename T>\nusing difference_type_t = typename T::difference_type;\n\ntemplate <typename T>\nusing pointer_t = typename T::pointer;\n\ntemplate <typename T>\nusing reference_t = typename T::reference;\n\ntemplate <typename T>\nusing iterator_category_t = typename T::iterator_category;\n\ntemplate <typename T>\nusing iterator_t = typename T::iterator;\n\ntemplate <typename T, typename... Args>\nusing to_json_function = decltype(T::to_json(std::declval<Args>()...));\n\ntemplate <typename T, typename... Args>\nusing from_json_function = decltype(T::from_json(std::declval<Args>()...));\n\ntemplate <typename T, typename U>\nusing get_template_function = decltype(std::declval<T>().template get<U>());\n\n// trait checking if JSONSerializer<T>::from_json(json const&, udt&) exists\ntemplate <typename BasicJsonType, typename T, typename = void>\nstruct has_from_json : std::false_type {};\n\ntemplate <typename BasicJsonType, typename T>\nstruct has_from_json<BasicJsonType, T,\n           enable_if_t<not is_basic_json<T>::value>>\n{\n    using serializer = typename BasicJsonType::template json_serializer<T, void>;\n\n    static constexpr bool value =\n        is_detected_exact<void, from_json_function, serializer,\n        const BasicJsonType&, T&>::value;\n};\n\n// This trait checks if JSONSerializer<T>::from_json(json const&) exists\n// this overload is used for non-default-constructible user-defined-types\ntemplate <typename BasicJsonType, typename T, typename = void>\nstruct has_non_default_from_json : std::false_type {};\n\ntemplate<typename BasicJsonType, typename T>\nstruct has_non_default_from_json<BasicJsonType, T, enable_if_t<not is_basic_json<T>::value>>\n{\n    using serializer = typename BasicJsonType::template json_serializer<T, void>;\n\n    static constexpr bool value =\n        is_detected_exact<T, from_json_function, serializer,\n        const BasicJsonType&>::value;\n};\n\n// This trait checks if BasicJsonType::json_serializer<T>::to_json exists\n// Do not evaluate the trait when T is a basic_json type, to avoid template instantiation infinite recursion.\ntemplate <typename BasicJsonType, typename T, typename = void>\nstruct has_to_json : std::false_type {};\n\ntemplate <typename BasicJsonType, typename T>\nstruct has_to_json<BasicJsonType, T, enable_if_t<not is_basic_json<T>::value>>\n{\n    using serializer = typename BasicJsonType::template json_serializer<T, void>;\n\n    static constexpr bool value =\n        is_detected_exact<void, to_json_function, serializer, BasicJsonType&,\n        T>::value;\n};\n\n\n///////////////////\n// is_ functions //\n///////////////////\n\ntemplate <typename T, typename = void>\nstruct is_iterator_traits : std::false_type {};\n\ntemplate <typename T>\nstruct is_iterator_traits<iterator_traits<T>>\n{\n  private:\n    using traits = iterator_traits<T>;\n\n  public:\n    static constexpr auto value =\n        is_detected<value_type_t, traits>::value &&\n        is_detected<difference_type_t, traits>::value &&\n        is_detected<pointer_t, traits>::value &&\n        is_detected<iterator_category_t, traits>::value &&\n        is_detected<reference_t, traits>::value;\n};\n\n// source: https://stackoverflow.com/a/37193089/4116453\n\ntemplate <typename T, typename = void>\nstruct is_complete_type : std::false_type {};\n\ntemplate <typename T>\nstruct is_complete_type<T, decltype(void(sizeof(T)))> : std::true_type {};\n\ntemplate <typename BasicJsonType, typename CompatibleObjectType,\n          typename = void>\nstruct is_compatible_object_type_impl : std::false_type {};\n\ntemplate <typename BasicJsonType, typename CompatibleObjectType>\nstruct is_compatible_object_type_impl <\n    BasicJsonType, CompatibleObjectType,\n    enable_if_t<is_detected<mapped_type_t, CompatibleObjectType>::value and\n    is_detected<key_type_t, CompatibleObjectType>::value >>\n{\n\n    using object_t = typename BasicJsonType::object_t;\n\n    // macOS's is_constructible does not play well with nonesuch...\n    static constexpr bool value =\n        std::is_constructible<typename object_t::key_type,\n        typename CompatibleObjectType::key_type>::value and\n        std::is_constructible<typename object_t::mapped_type,\n        typename CompatibleObjectType::mapped_type>::value;\n};\n\ntemplate <typename BasicJsonType, typename CompatibleObjectType>\nstruct is_compatible_object_type\n    : is_compatible_object_type_impl<BasicJsonType, CompatibleObjectType> {};\n\ntemplate <typename BasicJsonType, typename ConstructibleObjectType,\n          typename = void>\nstruct is_constructible_object_type_impl : std::false_type {};\n\ntemplate <typename BasicJsonType, typename ConstructibleObjectType>\nstruct is_constructible_object_type_impl <\n    BasicJsonType, ConstructibleObjectType,\n    enable_if_t<is_detected<mapped_type_t, ConstructibleObjectType>::value and\n    is_detected<key_type_t, ConstructibleObjectType>::value >>\n{\n    using object_t = typename BasicJsonType::object_t;\n\n    static constexpr bool value =\n        (std::is_constructible<typename ConstructibleObjectType::key_type, typename object_t::key_type>::value and\n         std::is_same<typename object_t::mapped_type, typename ConstructibleObjectType::mapped_type>::value) or\n        (has_from_json<BasicJsonType, typename ConstructibleObjectType::mapped_type>::value or\n         has_non_default_from_json<BasicJsonType, typename ConstructibleObjectType::mapped_type >::value);\n};\n\ntemplate <typename BasicJsonType, typename ConstructibleObjectType>\nstruct is_constructible_object_type\n    : is_constructible_object_type_impl<BasicJsonType,\n      ConstructibleObjectType> {};\n\ntemplate <typename BasicJsonType, typename CompatibleStringType,\n          typename = void>\nstruct is_compatible_string_type_impl : std::false_type {};\n\ntemplate <typename BasicJsonType, typename CompatibleStringType>\nstruct is_compatible_string_type_impl <\n    BasicJsonType, CompatibleStringType,\n    enable_if_t<is_detected_exact<typename BasicJsonType::string_t::value_type,\n    value_type_t, CompatibleStringType>::value >>\n{\n    static constexpr auto value =\n        std::is_constructible<typename BasicJsonType::string_t, CompatibleStringType>::value;\n};\n\ntemplate <typename BasicJsonType, typename ConstructibleStringType>\nstruct is_compatible_string_type\n    : is_compatible_string_type_impl<BasicJsonType, ConstructibleStringType> {};\n\ntemplate <typename BasicJsonType, typename ConstructibleStringType,\n          typename = void>\nstruct is_constructible_string_type_impl : std::false_type {};\n\ntemplate <typename BasicJsonType, typename ConstructibleStringType>\nstruct is_constructible_string_type_impl <\n    BasicJsonType, ConstructibleStringType,\n    enable_if_t<is_detected_exact<typename BasicJsonType::string_t::value_type,\n    value_type_t, ConstructibleStringType>::value >>\n{\n    static constexpr auto value =\n        std::is_constructible<ConstructibleStringType,\n        typename BasicJsonType::string_t>::value;\n};\n\ntemplate <typename BasicJsonType, typename ConstructibleStringType>\nstruct is_constructible_string_type\n    : is_constructible_string_type_impl<BasicJsonType, ConstructibleStringType> {};\n\ntemplate <typename BasicJsonType, typename CompatibleArrayType, typename = void>\nstruct is_compatible_array_type_impl : std::false_type {};\n\ntemplate <typename BasicJsonType, typename CompatibleArrayType>\nstruct is_compatible_array_type_impl <\n    BasicJsonType, CompatibleArrayType,\n    enable_if_t<is_detected<value_type_t, CompatibleArrayType>::value and\n    is_detected<iterator_t, CompatibleArrayType>::value and\n// This is needed because json_reverse_iterator has a ::iterator type...\n// Therefore it is detected as a CompatibleArrayType.\n// The real fix would be to have an Iterable concept.\n    not is_iterator_traits<\n    iterator_traits<CompatibleArrayType>>::value >>\n{\n    static constexpr bool value =\n        std::is_constructible<BasicJsonType,\n        typename CompatibleArrayType::value_type>::value;\n};\n\ntemplate <typename BasicJsonType, typename CompatibleArrayType>\nstruct is_compatible_array_type\n    : is_compatible_array_type_impl<BasicJsonType, CompatibleArrayType> {};\n\ntemplate <typename BasicJsonType, typename ConstructibleArrayType, typename = void>\nstruct is_constructible_array_type_impl : std::false_type {};\n\ntemplate <typename BasicJsonType, typename ConstructibleArrayType>\nstruct is_constructible_array_type_impl <\n    BasicJsonType, ConstructibleArrayType,\n    enable_if_t<std::is_same<ConstructibleArrayType,\n    typename BasicJsonType::value_type>::value >>\n            : std::true_type {};\n\ntemplate <typename BasicJsonType, typename ConstructibleArrayType>\nstruct is_constructible_array_type_impl <\n    BasicJsonType, ConstructibleArrayType,\n    enable_if_t<not std::is_same<ConstructibleArrayType,\n    typename BasicJsonType::value_type>::value and\n    is_detected<value_type_t, ConstructibleArrayType>::value and\n    is_detected<iterator_t, ConstructibleArrayType>::value and\n    is_complete_type<\n    detected_t<value_type_t, ConstructibleArrayType>>::value >>\n{\n    static constexpr bool value =\n        // This is needed because json_reverse_iterator has a ::iterator type,\n        // furthermore, std::back_insert_iterator (and other iterators) have a base class `iterator`...\n        // Therefore it is detected as a ConstructibleArrayType.\n        // The real fix would be to have an Iterable concept.\n        not is_iterator_traits <\n        iterator_traits<ConstructibleArrayType >>::value and\n\n        (std::is_same<typename ConstructibleArrayType::value_type, typename BasicJsonType::array_t::value_type>::value or\n         has_from_json<BasicJsonType,\n         typename ConstructibleArrayType::value_type>::value or\n         has_non_default_from_json <\n         BasicJsonType, typename ConstructibleArrayType::value_type >::value);\n};\n\ntemplate <typename BasicJsonType, typename ConstructibleArrayType>\nstruct is_constructible_array_type\n    : is_constructible_array_type_impl<BasicJsonType, ConstructibleArrayType> {};\n\ntemplate <typename RealIntegerType, typename CompatibleNumberIntegerType,\n          typename = void>\nstruct is_compatible_integer_type_impl : std::false_type {};\n\ntemplate <typename RealIntegerType, typename CompatibleNumberIntegerType>\nstruct is_compatible_integer_type_impl <\n    RealIntegerType, CompatibleNumberIntegerType,\n    enable_if_t<std::is_integral<RealIntegerType>::value and\n    std::is_integral<CompatibleNumberIntegerType>::value and\n    not std::is_same<bool, CompatibleNumberIntegerType>::value >>\n{\n    // is there an assert somewhere on overflows?\n    using RealLimits = std::numeric_limits<RealIntegerType>;\n    using CompatibleLimits = std::numeric_limits<CompatibleNumberIntegerType>;\n\n    static constexpr auto value =\n        std::is_constructible<RealIntegerType,\n        CompatibleNumberIntegerType>::value and\n        CompatibleLimits::is_integer and\n        RealLimits::is_signed == CompatibleLimits::is_signed;\n};\n\ntemplate <typename RealIntegerType, typename CompatibleNumberIntegerType>\nstruct is_compatible_integer_type\n    : is_compatible_integer_type_impl<RealIntegerType,\n      CompatibleNumberIntegerType> {};\n\ntemplate <typename BasicJsonType, typename CompatibleType, typename = void>\nstruct is_compatible_type_impl: std::false_type {};\n\ntemplate <typename BasicJsonType, typename CompatibleType>\nstruct is_compatible_type_impl <\n    BasicJsonType, CompatibleType,\n    enable_if_t<is_complete_type<CompatibleType>::value >>\n{\n    static constexpr bool value =\n        has_to_json<BasicJsonType, CompatibleType>::value;\n};\n\ntemplate <typename BasicJsonType, typename CompatibleType>\nstruct is_compatible_type\n    : is_compatible_type_impl<BasicJsonType, CompatibleType> {};\n}  // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/exceptions.hpp>\n\n\n#include <exception> // exception\n#include <stdexcept> // runtime_error\n#include <string> // to_string\n\n// #include <nlohmann/detail/input/position_t.hpp>\n\n\n#include <cstddef> // size_t\n\nnamespace nlohmann\n{\nnamespace detail\n{\n/// struct to capture the start position of the current token\nstruct position_t\n{\n    /// the total number of characters read\n    std::size_t chars_read_total = 0;\n    /// the number of characters read in the current line\n    std::size_t chars_read_current_line = 0;\n    /// the number of lines read\n    std::size_t lines_read = 0;\n\n    /// conversion to size_t to preserve SAX interface\n    constexpr operator size_t() const\n    {\n        return chars_read_total;\n    }\n};\n\n}\n}\n\n\nnamespace nlohmann\n{\nnamespace detail\n{\n////////////////\n// exceptions //\n////////////////\n\n/*!\n@brief general exception of the @ref basic_json class\n\nThis class is an extension of `std::exception` objects with a member @a id for\nexception ids. It is used as the base class for all exceptions thrown by the\n@ref basic_json class. This class can hence be used as \"wildcard\" to catch\nexceptions.\n\nSubclasses:\n- @ref parse_error for exceptions indicating a parse error\n- @ref invalid_iterator for exceptions indicating errors with iterators\n- @ref type_error for exceptions indicating executing a member function with\n                  a wrong type\n- @ref out_of_range for exceptions indicating access out of the defined range\n- @ref other_error for exceptions indicating other library errors\n\n@internal\n@note To have nothrow-copy-constructible exceptions, we internally use\n      `std::runtime_error` which can cope with arbitrary-length error messages.\n      Intermediate strings are built with static functions and then passed to\n      the actual constructor.\n@endinternal\n\n@liveexample{The following code shows how arbitrary library exceptions can be\ncaught.,exception}\n\n@since version 3.0.0\n*/\nclass exception : public std::exception\n{\n  public:\n    /// returns the explanatory string\n    const char* what() const noexcept override\n    {\n        return m.what();\n    }\n\n    /// the id of the exception\n    const int id;\n\n  protected:\n    exception(int id_, const char* what_arg) : id(id_), m(what_arg) {}\n\n    static std::string name(const std::string& ename, int id_)\n    {\n        return \"[json.exception.\" + ename + \".\" + std::to_string(id_) + \"] \";\n    }\n\n  private:\n    /// an exception object as storage for error messages\n    std::runtime_error m;\n};\n\n/*!\n@brief exception indicating a parse error\n\nThis exception is thrown by the library when a parse error occurs. Parse errors\ncan occur during the deserialization of JSON text, CBOR, MessagePack, as well\nas when using JSON Patch.\n\nMember @a byte holds the byte index of the last read character in the input\nfile.\n\nExceptions have ids 1xx.\n\nname / id                      | example message | description\n------------------------------ | --------------- | -------------------------\njson.exception.parse_error.101 | parse error at 2: unexpected end of input; expected string literal | This error indicates a syntax error while deserializing a JSON text. The error message describes that an unexpected token (character) was encountered, and the member @a byte indicates the error position.\njson.exception.parse_error.102 | parse error at 14: missing or wrong low surrogate | JSON uses the `\\uxxxx` format to describe Unicode characters. Code points above above 0xFFFF are split into two `\\uxxxx` entries (\"surrogate pairs\"). This error indicates that the surrogate pair is incomplete or contains an invalid code point.\njson.exception.parse_error.103 | parse error: code points above 0x10FFFF are invalid | Unicode supports code points up to 0x10FFFF. Code points above 0x10FFFF are invalid.\njson.exception.parse_error.104 | parse error: JSON patch must be an array of objects | [RFC 6902](https://tools.ietf.org/html/rfc6902) requires a JSON Patch document to be a JSON document that represents an array of objects.\njson.exception.parse_error.105 | parse error: operation must have string member 'op' | An operation of a JSON Patch document must contain exactly one \"op\" member, whose value indicates the operation to perform. Its value must be one of \"add\", \"remove\", \"replace\", \"move\", \"copy\", or \"test\"; other values are errors.\njson.exception.parse_error.106 | parse error: array index '01' must not begin with '0' | An array index in a JSON Pointer ([RFC 6901](https://tools.ietf.org/html/rfc6901)) may be `0` or any number without a leading `0`.\njson.exception.parse_error.107 | parse error: JSON pointer must be empty or begin with '/' - was: 'foo' | A JSON Pointer must be a Unicode string containing a sequence of zero or more reference tokens, each prefixed by a `/` character.\njson.exception.parse_error.108 | parse error: escape character '~' must be followed with '0' or '1' | In a JSON Pointer, only `~0` and `~1` are valid escape sequences.\njson.exception.parse_error.109 | parse error: array index 'one' is not a number | A JSON Pointer array index must be a number.\njson.exception.parse_error.110 | parse error at 1: cannot read 2 bytes from vector | When parsing CBOR or MessagePack, the byte vector ends before the complete value has been read.\njson.exception.parse_error.112 | parse error at 1: error reading CBOR; last byte: 0xF8 | Not all types of CBOR or MessagePack are supported. This exception occurs if an unsupported byte was read.\njson.exception.parse_error.113 | parse error at 2: expected a CBOR string; last byte: 0x98 | While parsing a map key, a value that is not a string has been read.\njson.exception.parse_error.114 | parse error: Unsupported BSON record type 0x0F | The parsing of the corresponding BSON record type is not implemented (yet).\n\n@note For an input with n bytes, 1 is the index of the first character and n+1\n      is the index of the terminating null byte or the end of file. This also\n      holds true when reading a byte vector (CBOR or MessagePack).\n\n@liveexample{The following code shows how a `parse_error` exception can be\ncaught.,parse_error}\n\n@sa @ref exception for the base class of the library exceptions\n@sa @ref invalid_iterator for exceptions indicating errors with iterators\n@sa @ref type_error for exceptions indicating executing a member function with\n                    a wrong type\n@sa @ref out_of_range for exceptions indicating access out of the defined range\n@sa @ref other_error for exceptions indicating other library errors\n\n@since version 3.0.0\n*/\nclass parse_error : public exception\n{\n  public:\n    /*!\n    @brief create a parse error exception\n    @param[in] id_       the id of the exception\n    @param[in] position  the position where the error occurred (or with\n                         chars_read_total=0 if the position cannot be\n                         determined)\n    @param[in] what_arg  the explanatory string\n    @return parse_error object\n    */\n    static parse_error create(int id_, const position_t& pos, const std::string& what_arg)\n    {\n        std::string w = exception::name(\"parse_error\", id_) + \"parse error\" +\n                        position_string(pos) + \": \" + what_arg;\n        return parse_error(id_, pos.chars_read_total, w.c_str());\n    }\n\n    static parse_error create(int id_, std::size_t byte_, const std::string& what_arg)\n    {\n        std::string w = exception::name(\"parse_error\", id_) + \"parse error\" +\n                        (byte_ != 0 ? (\" at byte \" + std::to_string(byte_)) : \"\") +\n                        \": \" + what_arg;\n        return parse_error(id_, byte_, w.c_str());\n    }\n\n    /*!\n    @brief byte index of the parse error\n\n    The byte index of the last read character in the input file.\n\n    @note For an input with n bytes, 1 is the index of the first character and\n          n+1 is the index of the terminating null byte or the end of file.\n          This also holds true when reading a byte vector (CBOR or MessagePack).\n    */\n    const std::size_t byte;\n\n  private:\n    parse_error(int id_, std::size_t byte_, const char* what_arg)\n        : exception(id_, what_arg), byte(byte_) {}\n\n    static std::string position_string(const position_t& pos)\n    {\n        return \" at line \" + std::to_string(pos.lines_read + 1) +\n               \", column \" + std::to_string(pos.chars_read_current_line);\n    }\n};\n\n/*!\n@brief exception indicating errors with iterators\n\nThis exception is thrown if iterators passed to a library function do not match\nthe expected semantics.\n\nExceptions have ids 2xx.\n\nname / id                           | example message | description\n----------------------------------- | --------------- | -------------------------\njson.exception.invalid_iterator.201 | iterators are not compatible | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid.\njson.exception.invalid_iterator.202 | iterator does not fit current value | In an erase or insert function, the passed iterator @a pos does not belong to the JSON value for which the function was called. It hence does not define a valid position for the deletion/insertion.\njson.exception.invalid_iterator.203 | iterators do not fit current value | Either iterator passed to function @ref erase(IteratorType first, IteratorType last) does not belong to the JSON value from which values shall be erased. It hence does not define a valid range to delete values from.\njson.exception.invalid_iterator.204 | iterators out of range | When an iterator range for a primitive type (number, boolean, or string) is passed to a constructor or an erase function, this range has to be exactly (@ref begin(), @ref end()), because this is the only way the single stored value is expressed. All other ranges are invalid.\njson.exception.invalid_iterator.205 | iterator out of range | When an iterator for a primitive type (number, boolean, or string) is passed to an erase function, the iterator has to be the @ref begin() iterator, because it is the only way to address the stored value. All other iterators are invalid.\njson.exception.invalid_iterator.206 | cannot construct with iterators from null | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) belong to a JSON null value and hence to not define a valid range.\njson.exception.invalid_iterator.207 | cannot use key() for non-object iterators | The key() member function can only be used on iterators belonging to a JSON object, because other types do not have a concept of a key.\njson.exception.invalid_iterator.208 | cannot use operator[] for object iterators | The operator[] to specify a concrete offset cannot be used on iterators belonging to a JSON object, because JSON objects are unordered.\njson.exception.invalid_iterator.209 | cannot use offsets with object iterators | The offset operators (+, -, +=, -=) cannot be used on iterators belonging to a JSON object, because JSON objects are unordered.\njson.exception.invalid_iterator.210 | iterators do not fit | The iterator range passed to the insert function are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid.\njson.exception.invalid_iterator.211 | passed iterators may not belong to container | The iterator range passed to the insert function must not be a subrange of the container to insert to.\njson.exception.invalid_iterator.212 | cannot compare iterators of different containers | When two iterators are compared, they must belong to the same container.\njson.exception.invalid_iterator.213 | cannot compare order of object iterators | The order of object iterators cannot be compared, because JSON objects are unordered.\njson.exception.invalid_iterator.214 | cannot get value | Cannot get value for iterator: Either the iterator belongs to a null value or it is an iterator to a primitive type (number, boolean, or string), but the iterator is different to @ref begin().\n\n@liveexample{The following code shows how an `invalid_iterator` exception can be\ncaught.,invalid_iterator}\n\n@sa @ref exception for the base class of the library exceptions\n@sa @ref parse_error for exceptions indicating a parse error\n@sa @ref type_error for exceptions indicating executing a member function with\n                    a wrong type\n@sa @ref out_of_range for exceptions indicating access out of the defined range\n@sa @ref other_error for exceptions indicating other library errors\n\n@since version 3.0.0\n*/\nclass invalid_iterator : public exception\n{\n  public:\n    static invalid_iterator create(int id_, const std::string& what_arg)\n    {\n        std::string w = exception::name(\"invalid_iterator\", id_) + what_arg;\n        return invalid_iterator(id_, w.c_str());\n    }\n\n  private:\n    invalid_iterator(int id_, const char* what_arg)\n        : exception(id_, what_arg) {}\n};\n\n/*!\n@brief exception indicating executing a member function with a wrong type\n\nThis exception is thrown in case of a type error; that is, a library function is\nexecuted on a JSON value whose type does not match the expected semantics.\n\nExceptions have ids 3xx.\n\nname / id                     | example message | description\n----------------------------- | --------------- | -------------------------\njson.exception.type_error.301 | cannot create object from initializer list | To create an object from an initializer list, the initializer list must consist only of a list of pairs whose first element is a string. When this constraint is violated, an array is created instead.\njson.exception.type_error.302 | type must be object, but is array | During implicit or explicit value conversion, the JSON type must be compatible to the target type. For instance, a JSON string can only be converted into string types, but not into numbers or boolean types.\njson.exception.type_error.303 | incompatible ReferenceType for get_ref, actual type is object | To retrieve a reference to a value stored in a @ref basic_json object with @ref get_ref, the type of the reference must match the value type. For instance, for a JSON array, the @a ReferenceType must be @ref array_t&.\njson.exception.type_error.304 | cannot use at() with string | The @ref at() member functions can only be executed for certain JSON types.\njson.exception.type_error.305 | cannot use operator[] with string | The @ref operator[] member functions can only be executed for certain JSON types.\njson.exception.type_error.306 | cannot use value() with string | The @ref value() member functions can only be executed for certain JSON types.\njson.exception.type_error.307 | cannot use erase() with string | The @ref erase() member functions can only be executed for certain JSON types.\njson.exception.type_error.308 | cannot use push_back() with string | The @ref push_back() and @ref operator+= member functions can only be executed for certain JSON types.\njson.exception.type_error.309 | cannot use insert() with | The @ref insert() member functions can only be executed for certain JSON types.\njson.exception.type_error.310 | cannot use swap() with number | The @ref swap() member functions can only be executed for certain JSON types.\njson.exception.type_error.311 | cannot use emplace_back() with string | The @ref emplace_back() member function can only be executed for certain JSON types.\njson.exception.type_error.312 | cannot use update() with string | The @ref update() member functions can only be executed for certain JSON types.\njson.exception.type_error.313 | invalid value to unflatten | The @ref unflatten function converts an object whose keys are JSON Pointers back into an arbitrary nested JSON value. The JSON Pointers must not overlap, because then the resulting value would not be well defined.\njson.exception.type_error.314 | only objects can be unflattened | The @ref unflatten function only works for an object whose keys are JSON Pointers.\njson.exception.type_error.315 | values in object must be primitive | The @ref unflatten function only works for an object whose keys are JSON Pointers and whose values are primitive.\njson.exception.type_error.316 | invalid UTF-8 byte at index 10: 0x7E | The @ref dump function only works with UTF-8 encoded strings; that is, if you assign a `std::string` to a JSON value, make sure it is UTF-8 encoded. |\njson.exception.type_error.317 | JSON value cannot be serialized to requested format | The dynamic type of the object cannot be represented in the requested serialization format (e.g. a raw `true` or `null` JSON object cannot be serialized to BSON) |\n\n@liveexample{The following code shows how a `type_error` exception can be\ncaught.,type_error}\n\n@sa @ref exception for the base class of the library exceptions\n@sa @ref parse_error for exceptions indicating a parse error\n@sa @ref invalid_iterator for exceptions indicating errors with iterators\n@sa @ref out_of_range for exceptions indicating access out of the defined range\n@sa @ref other_error for exceptions indicating other library errors\n\n@since version 3.0.0\n*/\nclass type_error : public exception\n{\n  public:\n    static type_error create(int id_, const std::string& what_arg)\n    {\n        std::string w = exception::name(\"type_error\", id_) + what_arg;\n        return type_error(id_, w.c_str());\n    }\n\n  private:\n    type_error(int id_, const char* what_arg) : exception(id_, what_arg) {}\n};\n\n/*!\n@brief exception indicating access out of the defined range\n\nThis exception is thrown in case a library function is called on an input\nparameter that exceeds the expected range, for instance in case of array\nindices or nonexisting object keys.\n\nExceptions have ids 4xx.\n\nname / id                       | example message | description\n------------------------------- | --------------- | -------------------------\njson.exception.out_of_range.401 | array index 3 is out of range | The provided array index @a i is larger than @a size-1.\njson.exception.out_of_range.402 | array index '-' (3) is out of range | The special array index `-` in a JSON Pointer never describes a valid element of the array, but the index past the end. That is, it can only be used to add elements at this position, but not to read it.\njson.exception.out_of_range.403 | key 'foo' not found | The provided key was not found in the JSON object.\njson.exception.out_of_range.404 | unresolved reference token 'foo' | A reference token in a JSON Pointer could not be resolved.\njson.exception.out_of_range.405 | JSON pointer has no parent | The JSON Patch operations 'remove' and 'add' can not be applied to the root element of the JSON value.\njson.exception.out_of_range.406 | number overflow parsing '10E1000' | A parsed number could not be stored as without changing it to NaN or INF.\njson.exception.out_of_range.407 | number overflow serializing '9223372036854775808' | UBJSON and BSON only support integer numbers up to 9223372036854775807. |\njson.exception.out_of_range.408 | excessive array size: 8658170730974374167 | The size (following `#`) of an UBJSON array or object exceeds the maximal capacity. |\njson.exception.out_of_range.409 | BSON key cannot contain code point U+0000 (at byte 2) | Key identifiers to be serialized to BSON cannot contain code point U+0000, since the key is stored as zero-terminated c-string |\n\n@liveexample{The following code shows how an `out_of_range` exception can be\ncaught.,out_of_range}\n\n@sa @ref exception for the base class of the library exceptions\n@sa @ref parse_error for exceptions indicating a parse error\n@sa @ref invalid_iterator for exceptions indicating errors with iterators\n@sa @ref type_error for exceptions indicating executing a member function with\n                    a wrong type\n@sa @ref other_error for exceptions indicating other library errors\n\n@since version 3.0.0\n*/\nclass out_of_range : public exception\n{\n  public:\n    static out_of_range create(int id_, const std::string& what_arg)\n    {\n        std::string w = exception::name(\"out_of_range\", id_) + what_arg;\n        return out_of_range(id_, w.c_str());\n    }\n\n  private:\n    out_of_range(int id_, const char* what_arg) : exception(id_, what_arg) {}\n};\n\n/*!\n@brief exception indicating other library errors\n\nThis exception is thrown in case of errors that cannot be classified with the\nother exception types.\n\nExceptions have ids 5xx.\n\nname / id                      | example message | description\n------------------------------ | --------------- | -------------------------\njson.exception.other_error.501 | unsuccessful: {\"op\":\"test\",\"path\":\"/baz\", \"value\":\"bar\"} | A JSON Patch operation 'test' failed. The unsuccessful operation is also printed.\n\n@sa @ref exception for the base class of the library exceptions\n@sa @ref parse_error for exceptions indicating a parse error\n@sa @ref invalid_iterator for exceptions indicating errors with iterators\n@sa @ref type_error for exceptions indicating executing a member function with\n                    a wrong type\n@sa @ref out_of_range for exceptions indicating access out of the defined range\n\n@liveexample{The following code shows how an `other_error` exception can be\ncaught.,other_error}\n\n@since version 3.0.0\n*/\nclass other_error : public exception\n{\n  public:\n    static other_error create(int id_, const std::string& what_arg)\n    {\n        std::string w = exception::name(\"other_error\", id_) + what_arg;\n        return other_error(id_, w.c_str());\n    }\n\n  private:\n    other_error(int id_, const char* what_arg) : exception(id_, what_arg) {}\n};\n}  // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/value_t.hpp>\n\n\n#include <array> // array\n#include <ciso646> // and\n#include <cstddef> // size_t\n#include <cstdint> // uint8_t\n\nnamespace nlohmann\n{\nnamespace detail\n{\n///////////////////////////\n// JSON type enumeration //\n///////////////////////////\n\n/*!\n@brief the JSON type enumeration\n\nThis enumeration collects the different JSON types. It is internally used to\ndistinguish the stored values, and the functions @ref basic_json::is_null(),\n@ref basic_json::is_object(), @ref basic_json::is_array(),\n@ref basic_json::is_string(), @ref basic_json::is_boolean(),\n@ref basic_json::is_number() (with @ref basic_json::is_number_integer(),\n@ref basic_json::is_number_unsigned(), and @ref basic_json::is_number_float()),\n@ref basic_json::is_discarded(), @ref basic_json::is_primitive(), and\n@ref basic_json::is_structured() rely on it.\n\n@note There are three enumeration entries (number_integer, number_unsigned, and\nnumber_float), because the library distinguishes these three types for numbers:\n@ref basic_json::number_unsigned_t is used for unsigned integers,\n@ref basic_json::number_integer_t is used for signed integers, and\n@ref basic_json::number_float_t is used for floating-point numbers or to\napproximate integers which do not fit in the limits of their respective type.\n\n@sa @ref basic_json::basic_json(const value_t value_type) -- create a JSON\nvalue with the default value for a given type\n\n@since version 1.0.0\n*/\nenum class value_t : std::uint8_t\n{\n    null,             ///< null value\n    object,           ///< object (unordered set of name/value pairs)\n    array,            ///< array (ordered collection of values)\n    string,           ///< string value\n    boolean,          ///< boolean value\n    number_integer,   ///< number value (signed integer)\n    number_unsigned,  ///< number value (unsigned integer)\n    number_float,     ///< number value (floating-point)\n    discarded         ///< discarded by the the parser callback function\n};\n\n/*!\n@brief comparison operator for JSON types\n\nReturns an ordering that is similar to Python:\n- order: null < boolean < number < object < array < string\n- furthermore, each type is not smaller than itself\n- discarded values are not comparable\n\n@since version 1.0.0\n*/\ninline bool operator<(const value_t lhs, const value_t rhs) noexcept\n{\n    static constexpr std::array<std::uint8_t, 8> order = {{\n            0 /* null */, 3 /* object */, 4 /* array */, 5 /* string */,\n            1 /* boolean */, 2 /* integer */, 2 /* unsigned */, 2 /* float */\n        }\n    };\n\n    const auto l_index = static_cast<std::size_t>(lhs);\n    const auto r_index = static_cast<std::size_t>(rhs);\n    return l_index < order.size() and r_index < order.size() and order[l_index] < order[r_index];\n}\n}  // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/conversions/from_json.hpp>\n\n\n#include <algorithm> // transform\n#include <array> // array\n#include <ciso646> // and, not\n#include <forward_list> // forward_list\n#include <iterator> // inserter, front_inserter, end\n#include <map> // map\n#include <string> // string\n#include <tuple> // tuple, make_tuple\n#include <type_traits> // is_arithmetic, is_same, is_enum, underlying_type, is_convertible\n#include <unordered_map> // unordered_map\n#include <utility> // pair, declval\n#include <valarray> // valarray\n\n// #include <nlohmann/detail/exceptions.hpp>\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n// #include <nlohmann/detail/meta/cpp_future.hpp>\n\n// #include <nlohmann/detail/meta/type_traits.hpp>\n\n// #include <nlohmann/detail/value_t.hpp>\n\n\nnamespace nlohmann\n{\nnamespace detail\n{\ntemplate<typename BasicJsonType>\nvoid from_json(const BasicJsonType& j, typename std::nullptr_t& n)\n{\n    if (JSON_UNLIKELY(not j.is_null()))\n    {\n        JSON_THROW(type_error::create(302, \"type must be null, but is \" + std::string(j.type_name())));\n    }\n    n = nullptr;\n}\n\n// overloads for basic_json template parameters\ntemplate<typename BasicJsonType, typename ArithmeticType,\n         enable_if_t<std::is_arithmetic<ArithmeticType>::value and\n                     not std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value,\n                     int> = 0>\nvoid get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val)\n{\n    switch (static_cast<value_t>(j))\n    {\n        case value_t::number_unsigned:\n        {\n            val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_unsigned_t*>());\n            break;\n        }\n        case value_t::number_integer:\n        {\n            val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_integer_t*>());\n            break;\n        }\n        case value_t::number_float:\n        {\n            val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_float_t*>());\n            break;\n        }\n\n        default:\n            JSON_THROW(type_error::create(302, \"type must be number, but is \" + std::string(j.type_name())));\n    }\n}\n\ntemplate<typename BasicJsonType>\nvoid from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b)\n{\n    if (JSON_UNLIKELY(not j.is_boolean()))\n    {\n        JSON_THROW(type_error::create(302, \"type must be boolean, but is \" + std::string(j.type_name())));\n    }\n    b = *j.template get_ptr<const typename BasicJsonType::boolean_t*>();\n}\n\ntemplate<typename BasicJsonType>\nvoid from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s)\n{\n    if (JSON_UNLIKELY(not j.is_string()))\n    {\n        JSON_THROW(type_error::create(302, \"type must be string, but is \" + std::string(j.type_name())));\n    }\n    s = *j.template get_ptr<const typename BasicJsonType::string_t*>();\n}\n\ntemplate <\n    typename BasicJsonType, typename ConstructibleStringType,\n    enable_if_t <\n        is_constructible_string_type<BasicJsonType, ConstructibleStringType>::value and\n        not std::is_same<typename BasicJsonType::string_t,\n                         ConstructibleStringType>::value,\n        int > = 0 >\nvoid from_json(const BasicJsonType& j, ConstructibleStringType& s)\n{\n    if (JSON_UNLIKELY(not j.is_string()))\n    {\n        JSON_THROW(type_error::create(302, \"type must be string, but is \" + std::string(j.type_name())));\n    }\n\n    s = *j.template get_ptr<const typename BasicJsonType::string_t*>();\n}\n\ntemplate<typename BasicJsonType>\nvoid from_json(const BasicJsonType& j, typename BasicJsonType::number_float_t& val)\n{\n    get_arithmetic_value(j, val);\n}\n\ntemplate<typename BasicJsonType>\nvoid from_json(const BasicJsonType& j, typename BasicJsonType::number_unsigned_t& val)\n{\n    get_arithmetic_value(j, val);\n}\n\ntemplate<typename BasicJsonType>\nvoid from_json(const BasicJsonType& j, typename BasicJsonType::number_integer_t& val)\n{\n    get_arithmetic_value(j, val);\n}\n\ntemplate<typename BasicJsonType, typename EnumType,\n         enable_if_t<std::is_enum<EnumType>::value, int> = 0>\nvoid from_json(const BasicJsonType& j, EnumType& e)\n{\n    typename std::underlying_type<EnumType>::type val;\n    get_arithmetic_value(j, val);\n    e = static_cast<EnumType>(val);\n}\n\n// forward_list doesn't have an insert method\ntemplate<typename BasicJsonType, typename T, typename Allocator,\n         enable_if_t<std::is_convertible<BasicJsonType, T>::value, int> = 0>\nvoid from_json(const BasicJsonType& j, std::forward_list<T, Allocator>& l)\n{\n    if (JSON_UNLIKELY(not j.is_array()))\n    {\n        JSON_THROW(type_error::create(302, \"type must be array, but is \" + std::string(j.type_name())));\n    }\n    std::transform(j.rbegin(), j.rend(),\n                   std::front_inserter(l), [](const BasicJsonType & i)\n    {\n        return i.template get<T>();\n    });\n}\n\n// valarray doesn't have an insert method\ntemplate<typename BasicJsonType, typename T,\n         enable_if_t<std::is_convertible<BasicJsonType, T>::value, int> = 0>\nvoid from_json(const BasicJsonType& j, std::valarray<T>& l)\n{\n    if (JSON_UNLIKELY(not j.is_array()))\n    {\n        JSON_THROW(type_error::create(302, \"type must be array, but is \" + std::string(j.type_name())));\n    }\n    l.resize(j.size());\n    std::copy(j.m_value.array->begin(), j.m_value.array->end(), std::begin(l));\n}\n\ntemplate<typename BasicJsonType>\nvoid from_json_array_impl(const BasicJsonType& j, typename BasicJsonType::array_t& arr, priority_tag<3> /*unused*/)\n{\n    arr = *j.template get_ptr<const typename BasicJsonType::array_t*>();\n}\n\ntemplate <typename BasicJsonType, typename T, std::size_t N>\nauto from_json_array_impl(const BasicJsonType& j, std::array<T, N>& arr,\n                          priority_tag<2> /*unused*/)\n-> decltype(j.template get<T>(), void())\n{\n    for (std::size_t i = 0; i < N; ++i)\n    {\n        arr[i] = j.at(i).template get<T>();\n    }\n}\n\ntemplate<typename BasicJsonType, typename ConstructibleArrayType>\nauto from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, priority_tag<1> /*unused*/)\n-> decltype(\n    arr.reserve(std::declval<typename ConstructibleArrayType::size_type>()),\n    j.template get<typename ConstructibleArrayType::value_type>(),\n    void())\n{\n    using std::end;\n\n    arr.reserve(j.size());\n    std::transform(j.begin(), j.end(),\n                   std::inserter(arr, end(arr)), [](const BasicJsonType & i)\n    {\n        // get<BasicJsonType>() returns *this, this won't call a from_json\n        // method when value_type is BasicJsonType\n        return i.template get<typename ConstructibleArrayType::value_type>();\n    });\n}\n\ntemplate <typename BasicJsonType, typename ConstructibleArrayType>\nvoid from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr,\n                          priority_tag<0> /*unused*/)\n{\n    using std::end;\n\n    std::transform(\n        j.begin(), j.end(), std::inserter(arr, end(arr)),\n        [](const BasicJsonType & i)\n    {\n        // get<BasicJsonType>() returns *this, this won't call a from_json\n        // method when value_type is BasicJsonType\n        return i.template get<typename ConstructibleArrayType::value_type>();\n    });\n}\n\ntemplate <typename BasicJsonType, typename ConstructibleArrayType,\n          enable_if_t <\n              is_constructible_array_type<BasicJsonType, ConstructibleArrayType>::value and\n              not is_constructible_object_type<BasicJsonType, ConstructibleArrayType>::value and\n              not is_constructible_string_type<BasicJsonType, ConstructibleArrayType>::value and\n              not is_basic_json<ConstructibleArrayType>::value,\n              int > = 0 >\n\nauto from_json(const BasicJsonType& j, ConstructibleArrayType& arr)\n-> decltype(from_json_array_impl(j, arr, priority_tag<3> {}),\nj.template get<typename ConstructibleArrayType::value_type>(),\nvoid())\n{\n    if (JSON_UNLIKELY(not j.is_array()))\n    {\n        JSON_THROW(type_error::create(302, \"type must be array, but is \" +\n                                      std::string(j.type_name())));\n    }\n\n    from_json_array_impl(j, arr, priority_tag<3> {});\n}\n\ntemplate<typename BasicJsonType, typename ConstructibleObjectType,\n         enable_if_t<is_constructible_object_type<BasicJsonType, ConstructibleObjectType>::value, int> = 0>\nvoid from_json(const BasicJsonType& j, ConstructibleObjectType& obj)\n{\n    if (JSON_UNLIKELY(not j.is_object()))\n    {\n        JSON_THROW(type_error::create(302, \"type must be object, but is \" + std::string(j.type_name())));\n    }\n\n    auto inner_object = j.template get_ptr<const typename BasicJsonType::object_t*>();\n    using value_type = typename ConstructibleObjectType::value_type;\n    std::transform(\n        inner_object->begin(), inner_object->end(),\n        std::inserter(obj, obj.begin()),\n        [](typename BasicJsonType::object_t::value_type const & p)\n    {\n        return value_type(p.first, p.second.template get<typename ConstructibleObjectType::mapped_type>());\n    });\n}\n\n// overload for arithmetic types, not chosen for basic_json template arguments\n// (BooleanType, etc..); note: Is it really necessary to provide explicit\n// overloads for boolean_t etc. in case of a custom BooleanType which is not\n// an arithmetic type?\ntemplate<typename BasicJsonType, typename ArithmeticType,\n         enable_if_t <\n             std::is_arithmetic<ArithmeticType>::value and\n             not std::is_same<ArithmeticType, typename BasicJsonType::number_unsigned_t>::value and\n             not std::is_same<ArithmeticType, typename BasicJsonType::number_integer_t>::value and\n             not std::is_same<ArithmeticType, typename BasicJsonType::number_float_t>::value and\n             not std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value,\n             int> = 0>\nvoid from_json(const BasicJsonType& j, ArithmeticType& val)\n{\n    switch (static_cast<value_t>(j))\n    {\n        case value_t::number_unsigned:\n        {\n            val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_unsigned_t*>());\n            break;\n        }\n        case value_t::number_integer:\n        {\n            val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_integer_t*>());\n            break;\n        }\n        case value_t::number_float:\n        {\n            val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_float_t*>());\n            break;\n        }\n        case value_t::boolean:\n        {\n            val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::boolean_t*>());\n            break;\n        }\n\n        default:\n            JSON_THROW(type_error::create(302, \"type must be number, but is \" + std::string(j.type_name())));\n    }\n}\n\ntemplate<typename BasicJsonType, typename A1, typename A2>\nvoid from_json(const BasicJsonType& j, std::pair<A1, A2>& p)\n{\n    p = {j.at(0).template get<A1>(), j.at(1).template get<A2>()};\n}\n\ntemplate<typename BasicJsonType, typename Tuple, std::size_t... Idx>\nvoid from_json_tuple_impl(const BasicJsonType& j, Tuple& t, index_sequence<Idx...> /*unused*/)\n{\n    t = std::make_tuple(j.at(Idx).template get<typename std::tuple_element<Idx, Tuple>::type>()...);\n}\n\ntemplate<typename BasicJsonType, typename... Args>\nvoid from_json(const BasicJsonType& j, std::tuple<Args...>& t)\n{\n    from_json_tuple_impl(j, t, index_sequence_for<Args...> {});\n}\n\ntemplate <typename BasicJsonType, typename Key, typename Value, typename Compare, typename Allocator,\n          typename = enable_if_t<not std::is_constructible<\n                                     typename BasicJsonType::string_t, Key>::value>>\nvoid from_json(const BasicJsonType& j, std::map<Key, Value, Compare, Allocator>& m)\n{\n    if (JSON_UNLIKELY(not j.is_array()))\n    {\n        JSON_THROW(type_error::create(302, \"type must be array, but is \" + std::string(j.type_name())));\n    }\n    for (const auto& p : j)\n    {\n        if (JSON_UNLIKELY(not p.is_array()))\n        {\n            JSON_THROW(type_error::create(302, \"type must be array, but is \" + std::string(p.type_name())));\n        }\n        m.emplace(p.at(0).template get<Key>(), p.at(1).template get<Value>());\n    }\n}\n\ntemplate <typename BasicJsonType, typename Key, typename Value, typename Hash, typename KeyEqual, typename Allocator,\n          typename = enable_if_t<not std::is_constructible<\n                                     typename BasicJsonType::string_t, Key>::value>>\nvoid from_json(const BasicJsonType& j, std::unordered_map<Key, Value, Hash, KeyEqual, Allocator>& m)\n{\n    if (JSON_UNLIKELY(not j.is_array()))\n    {\n        JSON_THROW(type_error::create(302, \"type must be array, but is \" + std::string(j.type_name())));\n    }\n    for (const auto& p : j)\n    {\n        if (JSON_UNLIKELY(not p.is_array()))\n        {\n            JSON_THROW(type_error::create(302, \"type must be array, but is \" + std::string(p.type_name())));\n        }\n        m.emplace(p.at(0).template get<Key>(), p.at(1).template get<Value>());\n    }\n}\n\nstruct from_json_fn\n{\n    template<typename BasicJsonType, typename T>\n    auto operator()(const BasicJsonType& j, T& val) const\n    noexcept(noexcept(from_json(j, val)))\n    -> decltype(from_json(j, val), void())\n    {\n        return from_json(j, val);\n    }\n};\n}  // namespace detail\n\n/// namespace to hold default `from_json` function\n/// to see why this is required:\n/// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html\nnamespace\n{\nconstexpr const auto& from_json = detail::static_const<detail::from_json_fn>::value;\n} // namespace\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/conversions/to_json.hpp>\n\n\n#include <ciso646> // or, and, not\n#include <iterator> // begin, end\n#include <tuple> // tuple, get\n#include <type_traits> // is_same, is_constructible, is_floating_point, is_enum, underlying_type\n#include <utility> // move, forward, declval, pair\n#include <valarray> // valarray\n#include <vector> // vector\n\n// #include <nlohmann/detail/meta/cpp_future.hpp>\n\n// #include <nlohmann/detail/meta/type_traits.hpp>\n\n// #include <nlohmann/detail/value_t.hpp>\n\n// #include <nlohmann/detail/iterators/iteration_proxy.hpp>\n\n\n#include <cstddef> // size_t\n#include <string> // string, to_string\n#include <iterator> // input_iterator_tag\n#include <tuple> // tuple_size, get, tuple_element\n\n// #include <nlohmann/detail/value_t.hpp>\n\n// #include <nlohmann/detail/meta/type_traits.hpp>\n\n\nnamespace nlohmann\n{\nnamespace detail\n{\ntemplate <typename IteratorType> class iteration_proxy_value\n{\n  public:\n    using difference_type = std::ptrdiff_t;\n    using value_type = iteration_proxy_value;\n    using pointer = value_type * ;\n    using reference = value_type & ;\n    using iterator_category = std::input_iterator_tag;\n\n  private:\n    /// the iterator\n    IteratorType anchor;\n    /// an index for arrays (used to create key names)\n    std::size_t array_index = 0;\n    /// last stringified array index\n    mutable std::size_t array_index_last = 0;\n    /// a string representation of the array index\n    mutable std::string array_index_str = \"0\";\n    /// an empty string (to return a reference for primitive values)\n    const std::string empty_str = \"\";\n\n  public:\n    explicit iteration_proxy_value(IteratorType it) noexcept : anchor(it) {}\n\n    /// dereference operator (needed for range-based for)\n    iteration_proxy_value& operator*()\n    {\n        return *this;\n    }\n\n    /// increment operator (needed for range-based for)\n    iteration_proxy_value& operator++()\n    {\n        ++anchor;\n        ++array_index;\n\n        return *this;\n    }\n\n    /// equality operator (needed for InputIterator)\n    bool operator==(const iteration_proxy_value& o) const noexcept\n    {\n        return anchor == o.anchor;\n    }\n\n    /// inequality operator (needed for range-based for)\n    bool operator!=(const iteration_proxy_value& o) const noexcept\n    {\n        return anchor != o.anchor;\n    }\n\n    /// return key of the iterator\n    const std::string& key() const\n    {\n        assert(anchor.m_object != nullptr);\n\n        switch (anchor.m_object->type())\n        {\n            // use integer array index as key\n            case value_t::array:\n            {\n                if (array_index != array_index_last)\n                {\n                    array_index_str = std::to_string(array_index);\n                    array_index_last = array_index;\n                }\n                return array_index_str;\n            }\n\n            // use key from the object\n            case value_t::object:\n                return anchor.key();\n\n            // use an empty key for all primitive types\n            default:\n                return empty_str;\n        }\n    }\n\n    /// return value of the iterator\n    typename IteratorType::reference value() const\n    {\n        return anchor.value();\n    }\n};\n\n/// proxy class for the items() function\ntemplate<typename IteratorType> class iteration_proxy\n{\n  private:\n    /// the container to iterate\n    typename IteratorType::reference container;\n\n  public:\n    /// construct iteration proxy from a container\n    explicit iteration_proxy(typename IteratorType::reference cont) noexcept\n        : container(cont) {}\n\n    /// return iterator begin (needed for range-based for)\n    iteration_proxy_value<IteratorType> begin() noexcept\n    {\n        return iteration_proxy_value<IteratorType>(container.begin());\n    }\n\n    /// return iterator end (needed for range-based for)\n    iteration_proxy_value<IteratorType> end() noexcept\n    {\n        return iteration_proxy_value<IteratorType>(container.end());\n    }\n};\n// Structured Bindings Support\n// For further reference see https://blog.tartanllama.xyz/structured-bindings/\n// And see https://github.com/nlohmann/json/pull/1391\ntemplate <std::size_t N, typename IteratorType, enable_if_t<N == 0, int> = 0>\nauto get(const nlohmann::detail::iteration_proxy_value<IteratorType>& i) -> decltype(i.key())\n{\n    return i.key();\n}\n// Structured Bindings Support\n// For further reference see https://blog.tartanllama.xyz/structured-bindings/\n// And see https://github.com/nlohmann/json/pull/1391\ntemplate <std::size_t N, typename IteratorType, enable_if_t<N == 1, int> = 0>\nauto get(const nlohmann::detail::iteration_proxy_value<IteratorType>& i) -> decltype(i.value())\n{\n    return i.value();\n}\n}  // namespace detail\n}  // namespace nlohmann\n\n// The Addition to the STD Namespace is required to add\n// Structured Bindings Support to the iteration_proxy_value class\n// For further reference see https://blog.tartanllama.xyz/structured-bindings/\n// And see https://github.com/nlohmann/json/pull/1391\nnamespace std\n{\ntemplate <typename IteratorType>\nclass tuple_size<::nlohmann::detail::iteration_proxy_value<IteratorType>>\n            : public std::integral_constant<std::size_t, 2> {};\n\ntemplate <std::size_t N, typename IteratorType>\nclass tuple_element<N, ::nlohmann::detail::iteration_proxy_value<IteratorType >>\n{\n  public:\n    using type = decltype(\n                     get<N>(std::declval <\n                            ::nlohmann::detail::iteration_proxy_value<IteratorType >> ()));\n};\n}\n\nnamespace nlohmann\n{\nnamespace detail\n{\n//////////////////\n// constructors //\n//////////////////\n\ntemplate<value_t> struct external_constructor;\n\ntemplate<>\nstruct external_constructor<value_t::boolean>\n{\n    template<typename BasicJsonType>\n    static void construct(BasicJsonType& j, typename BasicJsonType::boolean_t b) noexcept\n    {\n        j.m_type = value_t::boolean;\n        j.m_value = b;\n        j.assert_invariant();\n    }\n};\n\ntemplate<>\nstruct external_constructor<value_t::string>\n{\n    template<typename BasicJsonType>\n    static void construct(BasicJsonType& j, const typename BasicJsonType::string_t& s)\n    {\n        j.m_type = value_t::string;\n        j.m_value = s;\n        j.assert_invariant();\n    }\n\n    template<typename BasicJsonType>\n    static void construct(BasicJsonType& j, typename BasicJsonType::string_t&& s)\n    {\n        j.m_type = value_t::string;\n        j.m_value = std::move(s);\n        j.assert_invariant();\n    }\n\n    template<typename BasicJsonType, typename CompatibleStringType,\n             enable_if_t<not std::is_same<CompatibleStringType, typename BasicJsonType::string_t>::value,\n                         int> = 0>\n    static void construct(BasicJsonType& j, const CompatibleStringType& str)\n    {\n        j.m_type = value_t::string;\n        j.m_value.string = j.template create<typename BasicJsonType::string_t>(str);\n        j.assert_invariant();\n    }\n};\n\ntemplate<>\nstruct external_constructor<value_t::number_float>\n{\n    template<typename BasicJsonType>\n    static void construct(BasicJsonType& j, typename BasicJsonType::number_float_t val) noexcept\n    {\n        j.m_type = value_t::number_float;\n        j.m_value = val;\n        j.assert_invariant();\n    }\n};\n\ntemplate<>\nstruct external_constructor<value_t::number_unsigned>\n{\n    template<typename BasicJsonType>\n    static void construct(BasicJsonType& j, typename BasicJsonType::number_unsigned_t val) noexcept\n    {\n        j.m_type = value_t::number_unsigned;\n        j.m_value = val;\n        j.assert_invariant();\n    }\n};\n\ntemplate<>\nstruct external_constructor<value_t::number_integer>\n{\n    template<typename BasicJsonType>\n    static void construct(BasicJsonType& j, typename BasicJsonType::number_integer_t val) noexcept\n    {\n        j.m_type = value_t::number_integer;\n        j.m_value = val;\n        j.assert_invariant();\n    }\n};\n\ntemplate<>\nstruct external_constructor<value_t::array>\n{\n    template<typename BasicJsonType>\n    static void construct(BasicJsonType& j, const typename BasicJsonType::array_t& arr)\n    {\n        j.m_type = value_t::array;\n        j.m_value = arr;\n        j.assert_invariant();\n    }\n\n    template<typename BasicJsonType>\n    static void construct(BasicJsonType& j, typename BasicJsonType::array_t&& arr)\n    {\n        j.m_type = value_t::array;\n        j.m_value = std::move(arr);\n        j.assert_invariant();\n    }\n\n    template<typename BasicJsonType, typename CompatibleArrayType,\n             enable_if_t<not std::is_same<CompatibleArrayType, typename BasicJsonType::array_t>::value,\n                         int> = 0>\n    static void construct(BasicJsonType& j, const CompatibleArrayType& arr)\n    {\n        using std::begin;\n        using std::end;\n        j.m_type = value_t::array;\n        j.m_value.array = j.template create<typename BasicJsonType::array_t>(begin(arr), end(arr));\n        j.assert_invariant();\n    }\n\n    template<typename BasicJsonType>\n    static void construct(BasicJsonType& j, const std::vector<bool>& arr)\n    {\n        j.m_type = value_t::array;\n        j.m_value = value_t::array;\n        j.m_value.array->reserve(arr.size());\n        for (const bool x : arr)\n        {\n            j.m_value.array->push_back(x);\n        }\n        j.assert_invariant();\n    }\n\n    template<typename BasicJsonType, typename T,\n             enable_if_t<std::is_convertible<T, BasicJsonType>::value, int> = 0>\n    static void construct(BasicJsonType& j, const std::valarray<T>& arr)\n    {\n        j.m_type = value_t::array;\n        j.m_value = value_t::array;\n        j.m_value.array->resize(arr.size());\n        std::copy(std::begin(arr), std::end(arr), j.m_value.array->begin());\n        j.assert_invariant();\n    }\n};\n\ntemplate<>\nstruct external_constructor<value_t::object>\n{\n    template<typename BasicJsonType>\n    static void construct(BasicJsonType& j, const typename BasicJsonType::object_t& obj)\n    {\n        j.m_type = value_t::object;\n        j.m_value = obj;\n        j.assert_invariant();\n    }\n\n    template<typename BasicJsonType>\n    static void construct(BasicJsonType& j, typename BasicJsonType::object_t&& obj)\n    {\n        j.m_type = value_t::object;\n        j.m_value = std::move(obj);\n        j.assert_invariant();\n    }\n\n    template<typename BasicJsonType, typename CompatibleObjectType,\n             enable_if_t<not std::is_same<CompatibleObjectType, typename BasicJsonType::object_t>::value, int> = 0>\n    static void construct(BasicJsonType& j, const CompatibleObjectType& obj)\n    {\n        using std::begin;\n        using std::end;\n\n        j.m_type = value_t::object;\n        j.m_value.object = j.template create<typename BasicJsonType::object_t>(begin(obj), end(obj));\n        j.assert_invariant();\n    }\n};\n\n/////////////\n// to_json //\n/////////////\n\ntemplate<typename BasicJsonType, typename T,\n         enable_if_t<std::is_same<T, typename BasicJsonType::boolean_t>::value, int> = 0>\nvoid to_json(BasicJsonType& j, T b) noexcept\n{\n    external_constructor<value_t::boolean>::construct(j, b);\n}\n\ntemplate<typename BasicJsonType, typename CompatibleString,\n         enable_if_t<std::is_constructible<typename BasicJsonType::string_t, CompatibleString>::value, int> = 0>\nvoid to_json(BasicJsonType& j, const CompatibleString& s)\n{\n    external_constructor<value_t::string>::construct(j, s);\n}\n\ntemplate<typename BasicJsonType>\nvoid to_json(BasicJsonType& j, typename BasicJsonType::string_t&& s)\n{\n    external_constructor<value_t::string>::construct(j, std::move(s));\n}\n\ntemplate<typename BasicJsonType, typename FloatType,\n         enable_if_t<std::is_floating_point<FloatType>::value, int> = 0>\nvoid to_json(BasicJsonType& j, FloatType val) noexcept\n{\n    external_constructor<value_t::number_float>::construct(j, static_cast<typename BasicJsonType::number_float_t>(val));\n}\n\ntemplate<typename BasicJsonType, typename CompatibleNumberUnsignedType,\n         enable_if_t<is_compatible_integer_type<typename BasicJsonType::number_unsigned_t, CompatibleNumberUnsignedType>::value, int> = 0>\nvoid to_json(BasicJsonType& j, CompatibleNumberUnsignedType val) noexcept\n{\n    external_constructor<value_t::number_unsigned>::construct(j, static_cast<typename BasicJsonType::number_unsigned_t>(val));\n}\n\ntemplate<typename BasicJsonType, typename CompatibleNumberIntegerType,\n         enable_if_t<is_compatible_integer_type<typename BasicJsonType::number_integer_t, CompatibleNumberIntegerType>::value, int> = 0>\nvoid to_json(BasicJsonType& j, CompatibleNumberIntegerType val) noexcept\n{\n    external_constructor<value_t::number_integer>::construct(j, static_cast<typename BasicJsonType::number_integer_t>(val));\n}\n\ntemplate<typename BasicJsonType, typename EnumType,\n         enable_if_t<std::is_enum<EnumType>::value, int> = 0>\nvoid to_json(BasicJsonType& j, EnumType e) noexcept\n{\n    using underlying_type = typename std::underlying_type<EnumType>::type;\n    external_constructor<value_t::number_integer>::construct(j, static_cast<underlying_type>(e));\n}\n\ntemplate<typename BasicJsonType>\nvoid to_json(BasicJsonType& j, const std::vector<bool>& e)\n{\n    external_constructor<value_t::array>::construct(j, e);\n}\n\ntemplate <typename BasicJsonType, typename CompatibleArrayType,\n          enable_if_t<is_compatible_array_type<BasicJsonType,\n                      CompatibleArrayType>::value and\n                      not is_compatible_object_type<\n                          BasicJsonType, CompatibleArrayType>::value and\n                      not is_compatible_string_type<BasicJsonType, CompatibleArrayType>::value and\n                      not is_basic_json<CompatibleArrayType>::value,\n                      int> = 0>\nvoid to_json(BasicJsonType& j, const CompatibleArrayType& arr)\n{\n    external_constructor<value_t::array>::construct(j, arr);\n}\n\ntemplate<typename BasicJsonType, typename T,\n         enable_if_t<std::is_convertible<T, BasicJsonType>::value, int> = 0>\nvoid to_json(BasicJsonType& j, const std::valarray<T>& arr)\n{\n    external_constructor<value_t::array>::construct(j, std::move(arr));\n}\n\ntemplate<typename BasicJsonType>\nvoid to_json(BasicJsonType& j, typename BasicJsonType::array_t&& arr)\n{\n    external_constructor<value_t::array>::construct(j, std::move(arr));\n}\n\ntemplate<typename BasicJsonType, typename CompatibleObjectType,\n         enable_if_t<is_compatible_object_type<BasicJsonType, CompatibleObjectType>::value and not is_basic_json<CompatibleObjectType>::value, int> = 0>\nvoid to_json(BasicJsonType& j, const CompatibleObjectType& obj)\n{\n    external_constructor<value_t::object>::construct(j, obj);\n}\n\ntemplate<typename BasicJsonType>\nvoid to_json(BasicJsonType& j, typename BasicJsonType::object_t&& obj)\n{\n    external_constructor<value_t::object>::construct(j, std::move(obj));\n}\n\ntemplate <\n    typename BasicJsonType, typename T, std::size_t N,\n    enable_if_t<not std::is_constructible<typename BasicJsonType::string_t,\n                const T(&)[N]>::value,\n                int> = 0 >\nvoid to_json(BasicJsonType& j, const T(&arr)[N])\n{\n    external_constructor<value_t::array>::construct(j, arr);\n}\n\ntemplate<typename BasicJsonType, typename... Args>\nvoid to_json(BasicJsonType& j, const std::pair<Args...>& p)\n{\n    j = { p.first, p.second };\n}\n\n// for https://github.com/nlohmann/json/pull/1134\ntemplate < typename BasicJsonType, typename T,\n           enable_if_t<std::is_same<T, iteration_proxy_value<typename BasicJsonType::iterator>>::value, int> = 0>\nvoid to_json(BasicJsonType& j, const T& b)\n{\n    j = { {b.key(), b.value()} };\n}\n\ntemplate<typename BasicJsonType, typename Tuple, std::size_t... Idx>\nvoid to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence<Idx...> /*unused*/)\n{\n    j = { std::get<Idx>(t)... };\n}\n\ntemplate<typename BasicJsonType, typename... Args>\nvoid to_json(BasicJsonType& j, const std::tuple<Args...>& t)\n{\n    to_json_tuple_impl(j, t, index_sequence_for<Args...> {});\n}\n\nstruct to_json_fn\n{\n    template<typename BasicJsonType, typename T>\n    auto operator()(BasicJsonType& j, T&& val) const noexcept(noexcept(to_json(j, std::forward<T>(val))))\n    -> decltype(to_json(j, std::forward<T>(val)), void())\n    {\n        return to_json(j, std::forward<T>(val));\n    }\n};\n}  // namespace detail\n\n/// namespace to hold default `to_json` function\nnamespace\n{\nconstexpr const auto& to_json = detail::static_const<detail::to_json_fn>::value;\n} // namespace\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/input/input_adapters.hpp>\n\n\n#include <cassert> // assert\n#include <cstddef> // size_t\n#include <cstring> // strlen\n#include <istream> // istream\n#include <iterator> // begin, end, iterator_traits, random_access_iterator_tag, distance, next\n#include <memory> // shared_ptr, make_shared, addressof\n#include <numeric> // accumulate\n#include <string> // string, char_traits\n#include <type_traits> // enable_if, is_base_of, is_pointer, is_integral, remove_pointer\n#include <utility> // pair, declval\n#include <cstdio> //FILE *\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n\nnamespace nlohmann\n{\nnamespace detail\n{\n/// the supported input formats\nenum class input_format_t { json, cbor, msgpack, ubjson, bson };\n\n////////////////////\n// input adapters //\n////////////////////\n\n/*!\n@brief abstract input adapter interface\n\nProduces a stream of std::char_traits<char>::int_type characters from a\nstd::istream, a buffer, or some other input type. Accepts the return of\nexactly one non-EOF character for future input. The int_type characters\nreturned consist of all valid char values as positive values (typically\nunsigned char), plus an EOF value outside that range, specified by the value\nof the function std::char_traits<char>::eof(). This value is typically -1, but\ncould be any arbitrary value which is not a valid char value.\n*/\nstruct input_adapter_protocol\n{\n    /// get a character [0,255] or std::char_traits<char>::eof().\n    virtual std::char_traits<char>::int_type get_character() = 0;\n    virtual ~input_adapter_protocol() = default;\n};\n\n/// a type to simplify interfaces\nusing input_adapter_t = std::shared_ptr<input_adapter_protocol>;\n\n/*!\nInput adapter for stdio file access. This adapter read only 1 byte and do not use any\n buffer. This adapter is a very low level adapter.\n*/\nclass file_input_adapter : public input_adapter_protocol\n{\n  public:\n    explicit file_input_adapter(std::FILE* f)  noexcept\n        : m_file(f)\n    {}\n\n    std::char_traits<char>::int_type get_character() noexcept override\n    {\n        return std::fgetc(m_file);\n    }\n  private:\n    /// the file pointer to read from\n    std::FILE* m_file;\n};\n\n\n/*!\nInput adapter for a (caching) istream. Ignores a UFT Byte Order Mark at\nbeginning of input. Does not support changing the underlying std::streambuf\nin mid-input. Maintains underlying std::istream and std::streambuf to support\nsubsequent use of standard std::istream operations to process any input\ncharacters following those used in parsing the JSON input.  Clears the\nstd::istream flags; any input errors (e.g., EOF) will be detected by the first\nsubsequent call for input from the std::istream.\n*/\nclass input_stream_adapter : public input_adapter_protocol\n{\n  public:\n    ~input_stream_adapter() override\n    {\n        // clear stream flags; we use underlying streambuf I/O, do not\n        // maintain ifstream flags, except eof\n        is.clear(is.rdstate() & std::ios::eofbit);\n    }\n\n    explicit input_stream_adapter(std::istream& i)\n        : is(i), sb(*i.rdbuf())\n    {}\n\n    // delete because of pointer members\n    input_stream_adapter(const input_stream_adapter&) = delete;\n    input_stream_adapter& operator=(input_stream_adapter&) = delete;\n    input_stream_adapter(input_stream_adapter&&) = delete;\n    input_stream_adapter& operator=(input_stream_adapter&&) = delete;\n\n    // std::istream/std::streambuf use std::char_traits<char>::to_int_type, to\n    // ensure that std::char_traits<char>::eof() and the character 0xFF do not\n    // end up as the same value, eg. 0xFFFFFFFF.\n    std::char_traits<char>::int_type get_character() override\n    {\n        auto res = sb.sbumpc();\n        // set eof manually, as we don't use the istream interface.\n        if (res == EOF)\n        {\n            is.clear(is.rdstate() | std::ios::eofbit);\n        }\n        return res;\n    }\n\n  private:\n    /// the associated input stream\n    std::istream& is;\n    std::streambuf& sb;\n};\n\n/// input adapter for buffer input\nclass input_buffer_adapter : public input_adapter_protocol\n{\n  public:\n    input_buffer_adapter(const char* b, const std::size_t l) noexcept\n        : cursor(b), limit(b + l)\n    {}\n\n    // delete because of pointer members\n    input_buffer_adapter(const input_buffer_adapter&) = delete;\n    input_buffer_adapter& operator=(input_buffer_adapter&) = delete;\n    input_buffer_adapter(input_buffer_adapter&&) = delete;\n    input_buffer_adapter& operator=(input_buffer_adapter&&) = delete;\n    ~input_buffer_adapter() override = default;\n\n    std::char_traits<char>::int_type get_character() noexcept override\n    {\n        if (JSON_LIKELY(cursor < limit))\n        {\n            return std::char_traits<char>::to_int_type(*(cursor++));\n        }\n\n        return std::char_traits<char>::eof();\n    }\n\n  private:\n    /// pointer to the current character\n    const char* cursor;\n    /// pointer past the last character\n    const char* const limit;\n};\n\ntemplate<typename WideStringType, size_t T>\nstruct wide_string_input_helper\n{\n    // UTF-32\n    static void fill_buffer(const WideStringType& str, size_t& current_wchar, std::array<std::char_traits<char>::int_type, 4>& utf8_bytes, size_t& utf8_bytes_index, size_t& utf8_bytes_filled)\n    {\n        utf8_bytes_index = 0;\n\n        if (current_wchar == str.size())\n        {\n            utf8_bytes[0] = std::char_traits<char>::eof();\n            utf8_bytes_filled = 1;\n        }\n        else\n        {\n            // get the current character\n            const auto wc = static_cast<int>(str[current_wchar++]);\n\n            // UTF-32 to UTF-8 encoding\n            if (wc < 0x80)\n            {\n                utf8_bytes[0] = wc;\n                utf8_bytes_filled = 1;\n            }\n            else if (wc <= 0x7FF)\n            {\n                utf8_bytes[0] = 0xC0 | ((wc >> 6) & 0x1F);\n                utf8_bytes[1] = 0x80 | (wc & 0x3F);\n                utf8_bytes_filled = 2;\n            }\n            else if (wc <= 0xFFFF)\n            {\n                utf8_bytes[0] = 0xE0 | ((wc >> 12) & 0x0F);\n                utf8_bytes[1] = 0x80 | ((wc >> 6) & 0x3F);\n                utf8_bytes[2] = 0x80 | (wc & 0x3F);\n                utf8_bytes_filled = 3;\n            }\n            else if (wc <= 0x10FFFF)\n            {\n                utf8_bytes[0] = 0xF0 | ((wc >> 18) & 0x07);\n                utf8_bytes[1] = 0x80 | ((wc >> 12) & 0x3F);\n                utf8_bytes[2] = 0x80 | ((wc >> 6) & 0x3F);\n                utf8_bytes[3] = 0x80 | (wc & 0x3F);\n                utf8_bytes_filled = 4;\n            }\n            else\n            {\n                // unknown character\n                utf8_bytes[0] = wc;\n                utf8_bytes_filled = 1;\n            }\n        }\n    }\n};\n\ntemplate<typename WideStringType>\nstruct wide_string_input_helper<WideStringType, 2>\n{\n    // UTF-16\n    static void fill_buffer(const WideStringType& str, size_t& current_wchar, std::array<std::char_traits<char>::int_type, 4>& utf8_bytes, size_t& utf8_bytes_index, size_t& utf8_bytes_filled)\n    {\n        utf8_bytes_index = 0;\n\n        if (current_wchar == str.size())\n        {\n            utf8_bytes[0] = std::char_traits<char>::eof();\n            utf8_bytes_filled = 1;\n        }\n        else\n        {\n            // get the current character\n            const auto wc = static_cast<int>(str[current_wchar++]);\n\n            // UTF-16 to UTF-8 encoding\n            if (wc < 0x80)\n            {\n                utf8_bytes[0] = wc;\n                utf8_bytes_filled = 1;\n            }\n            else if (wc <= 0x7FF)\n            {\n                utf8_bytes[0] = 0xC0 | ((wc >> 6));\n                utf8_bytes[1] = 0x80 | (wc & 0x3F);\n                utf8_bytes_filled = 2;\n            }\n            else if (0xD800 > wc or wc >= 0xE000)\n            {\n                utf8_bytes[0] = 0xE0 | ((wc >> 12));\n                utf8_bytes[1] = 0x80 | ((wc >> 6) & 0x3F);\n                utf8_bytes[2] = 0x80 | (wc & 0x3F);\n                utf8_bytes_filled = 3;\n            }\n            else\n            {\n                if (current_wchar < str.size())\n                {\n                    const auto wc2 = static_cast<int>(str[current_wchar++]);\n                    const int charcode = 0x10000 + (((wc & 0x3FF) << 10) | (wc2 & 0x3FF));\n                    utf8_bytes[0] = 0xf0 | (charcode >> 18);\n                    utf8_bytes[1] = 0x80 | ((charcode >> 12) & 0x3F);\n                    utf8_bytes[2] = 0x80 | ((charcode >> 6) & 0x3F);\n                    utf8_bytes[3] = 0x80 | (charcode & 0x3F);\n                    utf8_bytes_filled = 4;\n                }\n                else\n                {\n                    // unknown character\n                    ++current_wchar;\n                    utf8_bytes[0] = wc;\n                    utf8_bytes_filled = 1;\n                }\n            }\n        }\n    }\n};\n\ntemplate<typename WideStringType>\nclass wide_string_input_adapter : public input_adapter_protocol\n{\n  public:\n    explicit wide_string_input_adapter(const WideStringType& w)  noexcept\n        : str(w)\n    {}\n\n    std::char_traits<char>::int_type get_character() noexcept override\n    {\n        // check if buffer needs to be filled\n        if (utf8_bytes_index == utf8_bytes_filled)\n        {\n            fill_buffer<sizeof(typename WideStringType::value_type)>();\n\n            assert(utf8_bytes_filled > 0);\n            assert(utf8_bytes_index == 0);\n        }\n\n        // use buffer\n        assert(utf8_bytes_filled > 0);\n        assert(utf8_bytes_index < utf8_bytes_filled);\n        return utf8_bytes[utf8_bytes_index++];\n    }\n\n  private:\n    template<size_t T>\n    void fill_buffer()\n    {\n        wide_string_input_helper<WideStringType, T>::fill_buffer(str, current_wchar, utf8_bytes, utf8_bytes_index, utf8_bytes_filled);\n    }\n\n    /// the wstring to process\n    const WideStringType& str;\n\n    /// index of the current wchar in str\n    std::size_t current_wchar = 0;\n\n    /// a buffer for UTF-8 bytes\n    std::array<std::char_traits<char>::int_type, 4> utf8_bytes = {{0, 0, 0, 0}};\n\n    /// index to the utf8_codes array for the next valid byte\n    std::size_t utf8_bytes_index = 0;\n    /// number of valid bytes in the utf8_codes array\n    std::size_t utf8_bytes_filled = 0;\n};\n\nclass input_adapter\n{\n  public:\n    // native support\n    input_adapter(std::FILE* file)\n        : ia(std::make_shared<file_input_adapter>(file)) {}\n    /// input adapter for input stream\n    input_adapter(std::istream& i)\n        : ia(std::make_shared<input_stream_adapter>(i)) {}\n\n    /// input adapter for input stream\n    input_adapter(std::istream&& i)\n        : ia(std::make_shared<input_stream_adapter>(i)) {}\n\n    input_adapter(const std::wstring& ws)\n        : ia(std::make_shared<wide_string_input_adapter<std::wstring>>(ws)) {}\n\n    input_adapter(const std::u16string& ws)\n        : ia(std::make_shared<wide_string_input_adapter<std::u16string>>(ws)) {}\n\n    input_adapter(const std::u32string& ws)\n        : ia(std::make_shared<wide_string_input_adapter<std::u32string>>(ws)) {}\n\n    /// input adapter for buffer\n    template<typename CharT,\n             typename std::enable_if<\n                 std::is_pointer<CharT>::value and\n                 std::is_integral<typename std::remove_pointer<CharT>::type>::value and\n                 sizeof(typename std::remove_pointer<CharT>::type) == 1,\n                 int>::type = 0>\n    input_adapter(CharT b, std::size_t l)\n        : ia(std::make_shared<input_buffer_adapter>(reinterpret_cast<const char*>(b), l)) {}\n\n    // derived support\n\n    /// input adapter for string literal\n    template<typename CharT,\n             typename std::enable_if<\n                 std::is_pointer<CharT>::value and\n                 std::is_integral<typename std::remove_pointer<CharT>::type>::value and\n                 sizeof(typename std::remove_pointer<CharT>::type) == 1,\n                 int>::type = 0>\n    input_adapter(CharT b)\n        : input_adapter(reinterpret_cast<const char*>(b),\n                        std::strlen(reinterpret_cast<const char*>(b))) {}\n\n    /// input adapter for iterator range with contiguous storage\n    template<class IteratorType,\n             typename std::enable_if<\n                 std::is_same<typename iterator_traits<IteratorType>::iterator_category, std::random_access_iterator_tag>::value,\n                 int>::type = 0>\n    input_adapter(IteratorType first, IteratorType last)\n    {\n#ifndef NDEBUG\n        // assertion to check that the iterator range is indeed contiguous,\n        // see http://stackoverflow.com/a/35008842/266378 for more discussion\n        const auto is_contiguous = std::accumulate(\n                                       first, last, std::pair<bool, int>(true, 0),\n                                       [&first](std::pair<bool, int> res, decltype(*first) val)\n        {\n            res.first &= (val == *(std::next(std::addressof(*first), res.second++)));\n            return res;\n        }).first;\n        assert(is_contiguous);\n#endif\n\n        // assertion to check that each element is 1 byte long\n        static_assert(\n            sizeof(typename iterator_traits<IteratorType>::value_type) == 1,\n            \"each element in the iterator range must have the size of 1 byte\");\n\n        const auto len = static_cast<size_t>(std::distance(first, last));\n        if (JSON_LIKELY(len > 0))\n        {\n            // there is at least one element: use the address of first\n            ia = std::make_shared<input_buffer_adapter>(reinterpret_cast<const char*>(&(*first)), len);\n        }\n        else\n        {\n            // the address of first cannot be used: use nullptr\n            ia = std::make_shared<input_buffer_adapter>(nullptr, len);\n        }\n    }\n\n    /// input adapter for array\n    template<class T, std::size_t N>\n    input_adapter(T (&array)[N])\n        : input_adapter(std::begin(array), std::end(array)) {}\n\n    /// input adapter for contiguous container\n    template<class ContiguousContainer, typename\n             std::enable_if<not std::is_pointer<ContiguousContainer>::value and\n                            std::is_base_of<std::random_access_iterator_tag, typename iterator_traits<decltype(std::begin(std::declval<ContiguousContainer const>()))>::iterator_category>::value,\n                            int>::type = 0>\n    input_adapter(const ContiguousContainer& c)\n        : input_adapter(std::begin(c), std::end(c)) {}\n\n    operator input_adapter_t()\n    {\n        return ia;\n    }\n\n  private:\n    /// the actual adapter\n    input_adapter_t ia = nullptr;\n};\n}  // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/input/lexer.hpp>\n\n\n#include <clocale> // localeconv\n#include <cstddef> // size_t\n#include <cstdlib> // strtof, strtod, strtold, strtoll, strtoull\n#include <cstdio> // snprintf\n#include <initializer_list> // initializer_list\n#include <string> // char_traits, string\n#include <vector> // vector\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n// #include <nlohmann/detail/input/input_adapters.hpp>\n\n// #include <nlohmann/detail/input/position_t.hpp>\n\n\nnamespace nlohmann\n{\nnamespace detail\n{\n///////////\n// lexer //\n///////////\n\n/*!\n@brief lexical analysis\n\nThis class organizes the lexical analysis during JSON deserialization.\n*/\ntemplate<typename BasicJsonType>\nclass lexer\n{\n    using number_integer_t = typename BasicJsonType::number_integer_t;\n    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n    using number_float_t = typename BasicJsonType::number_float_t;\n    using string_t = typename BasicJsonType::string_t;\n\n  public:\n    /// token types for the parser\n    enum class token_type\n    {\n        uninitialized,    ///< indicating the scanner is uninitialized\n        literal_true,     ///< the `true` literal\n        literal_false,    ///< the `false` literal\n        literal_null,     ///< the `null` literal\n        value_string,     ///< a string -- use get_string() for actual value\n        value_unsigned,   ///< an unsigned integer -- use get_number_unsigned() for actual value\n        value_integer,    ///< a signed integer -- use get_number_integer() for actual value\n        value_float,      ///< an floating point number -- use get_number_float() for actual value\n        begin_array,      ///< the character for array begin `[`\n        begin_object,     ///< the character for object begin `{`\n        end_array,        ///< the character for array end `]`\n        end_object,       ///< the character for object end `}`\n        name_separator,   ///< the name separator `:`\n        value_separator,  ///< the value separator `,`\n        parse_error,      ///< indicating a parse error\n        end_of_input,     ///< indicating the end of the input buffer\n        literal_or_value  ///< a literal or the begin of a value (only for diagnostics)\n    };\n\n    /// return name of values of type token_type (only used for errors)\n    static const char* token_type_name(const token_type t) noexcept\n    {\n        switch (t)\n        {\n            case token_type::uninitialized:\n                return \"<uninitialized>\";\n            case token_type::literal_true:\n                return \"true literal\";\n            case token_type::literal_false:\n                return \"false literal\";\n            case token_type::literal_null:\n                return \"null literal\";\n            case token_type::value_string:\n                return \"string literal\";\n            case lexer::token_type::value_unsigned:\n            case lexer::token_type::value_integer:\n            case lexer::token_type::value_float:\n                return \"number literal\";\n            case token_type::begin_array:\n                return \"'['\";\n            case token_type::begin_object:\n                return \"'{'\";\n            case token_type::end_array:\n                return \"']'\";\n            case token_type::end_object:\n                return \"'}'\";\n            case token_type::name_separator:\n                return \"':'\";\n            case token_type::value_separator:\n                return \"','\";\n            case token_type::parse_error:\n                return \"<parse error>\";\n            case token_type::end_of_input:\n                return \"end of input\";\n            case token_type::literal_or_value:\n                return \"'[', '{', or a literal\";\n            // LCOV_EXCL_START\n            default: // catch non-enum values\n                return \"unknown token\";\n                // LCOV_EXCL_STOP\n        }\n    }\n\n    explicit lexer(detail::input_adapter_t&& adapter)\n        : ia(std::move(adapter)), decimal_point_char(get_decimal_point()) {}\n\n    // delete because of pointer members\n    lexer(const lexer&) = delete;\n    lexer(lexer&&) = delete;\n    lexer& operator=(lexer&) = delete;\n    lexer& operator=(lexer&&) = delete;\n    ~lexer() = default;\n\n  private:\n    /////////////////////\n    // locales\n    /////////////////////\n\n    /// return the locale-dependent decimal point\n    static char get_decimal_point() noexcept\n    {\n        const auto loc = localeconv();\n        assert(loc != nullptr);\n        return (loc->decimal_point == nullptr) ? '.' : *(loc->decimal_point);\n    }\n\n    /////////////////////\n    // scan functions\n    /////////////////////\n\n    /*!\n    @brief get codepoint from 4 hex characters following `\\u`\n\n    For input \"\\u c1 c2 c3 c4\" the codepoint is:\n      (c1 * 0x1000) + (c2 * 0x0100) + (c3 * 0x0010) + c4\n    = (c1 << 12) + (c2 << 8) + (c3 << 4) + (c4 << 0)\n\n    Furthermore, the possible characters '0'..'9', 'A'..'F', and 'a'..'f'\n    must be converted to the integers 0x0..0x9, 0xA..0xF, 0xA..0xF, resp. The\n    conversion is done by subtracting the offset (0x30, 0x37, and 0x57)\n    between the ASCII value of the character and the desired integer value.\n\n    @return codepoint (0x0000..0xFFFF) or -1 in case of an error (e.g. EOF or\n            non-hex character)\n    */\n    int get_codepoint()\n    {\n        // this function only makes sense after reading `\\u`\n        assert(current == 'u');\n        int codepoint = 0;\n\n        const auto factors = { 12, 8, 4, 0 };\n        for (const auto factor : factors)\n        {\n            get();\n\n            if (current >= '0' and current <= '9')\n            {\n                codepoint += ((current - 0x30) << factor);\n            }\n            else if (current >= 'A' and current <= 'F')\n            {\n                codepoint += ((current - 0x37) << factor);\n            }\n            else if (current >= 'a' and current <= 'f')\n            {\n                codepoint += ((current - 0x57) << factor);\n            }\n            else\n            {\n                return -1;\n            }\n        }\n\n        assert(0x0000 <= codepoint and codepoint <= 0xFFFF);\n        return codepoint;\n    }\n\n    /*!\n    @brief check if the next byte(s) are inside a given range\n\n    Adds the current byte and, for each passed range, reads a new byte and\n    checks if it is inside the range. If a violation was detected, set up an\n    error message and return false. Otherwise, return true.\n\n    @param[in] ranges  list of integers; interpreted as list of pairs of\n                       inclusive lower and upper bound, respectively\n\n    @pre The passed list @a ranges must have 2, 4, or 6 elements; that is,\n         1, 2, or 3 pairs. This precondition is enforced by an assertion.\n\n    @return true if and only if no range violation was detected\n    */\n    bool next_byte_in_range(std::initializer_list<int> ranges)\n    {\n        assert(ranges.size() == 2 or ranges.size() == 4 or ranges.size() == 6);\n        add(current);\n\n        for (auto range = ranges.begin(); range != ranges.end(); ++range)\n        {\n            get();\n            if (JSON_LIKELY(*range <= current and current <= *(++range)))\n            {\n                add(current);\n            }\n            else\n            {\n                error_message = \"invalid string: ill-formed UTF-8 byte\";\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    /*!\n    @brief scan a string literal\n\n    This function scans a string according to Sect. 7 of RFC 7159. While\n    scanning, bytes are escaped and copied into buffer token_buffer. Then the\n    function returns successfully, token_buffer is *not* null-terminated (as it\n    may contain \\0 bytes), and token_buffer.size() is the number of bytes in the\n    string.\n\n    @return token_type::value_string if string could be successfully scanned,\n            token_type::parse_error otherwise\n\n    @note In case of errors, variable error_message contains a textual\n          description.\n    */\n    token_type scan_string()\n    {\n        // reset token_buffer (ignore opening quote)\n        reset();\n\n        // we entered the function by reading an open quote\n        assert(current == '\\\"');\n\n        while (true)\n        {\n            // get next character\n            switch (get())\n            {\n                // end of file while parsing string\n                case std::char_traits<char>::eof():\n                {\n                    error_message = \"invalid string: missing closing quote\";\n                    return token_type::parse_error;\n                }\n\n                // closing quote\n                case '\\\"':\n                {\n                    return token_type::value_string;\n                }\n\n                // escapes\n                case '\\\\':\n                {\n                    switch (get())\n                    {\n                        // quotation mark\n                        case '\\\"':\n                            add('\\\"');\n                            break;\n                        // reverse solidus\n                        case '\\\\':\n                            add('\\\\');\n                            break;\n                        // solidus\n                        case '/':\n                            add('/');\n                            break;\n                        // backspace\n                        case 'b':\n                            add('\\b');\n                            break;\n                        // form feed\n                        case 'f':\n                            add('\\f');\n                            break;\n                        // line feed\n                        case 'n':\n                            add('\\n');\n                            break;\n                        // carriage return\n                        case 'r':\n                            add('\\r');\n                            break;\n                        // tab\n                        case 't':\n                            add('\\t');\n                            break;\n\n                        // unicode escapes\n                        case 'u':\n                        {\n                            const int codepoint1 = get_codepoint();\n                            int codepoint = codepoint1; // start with codepoint1\n\n                            if (JSON_UNLIKELY(codepoint1 == -1))\n                            {\n                                error_message = \"invalid string: '\\\\u' must be followed by 4 hex digits\";\n                                return token_type::parse_error;\n                            }\n\n                            // check if code point is a high surrogate\n                            if (0xD800 <= codepoint1 and codepoint1 <= 0xDBFF)\n                            {\n                                // expect next \\uxxxx entry\n                                if (JSON_LIKELY(get() == '\\\\' and get() == 'u'))\n                                {\n                                    const int codepoint2 = get_codepoint();\n\n                                    if (JSON_UNLIKELY(codepoint2 == -1))\n                                    {\n                                        error_message = \"invalid string: '\\\\u' must be followed by 4 hex digits\";\n                                        return token_type::parse_error;\n                                    }\n\n                                    // check if codepoint2 is a low surrogate\n                                    if (JSON_LIKELY(0xDC00 <= codepoint2 and codepoint2 <= 0xDFFF))\n                                    {\n                                        // overwrite codepoint\n                                        codepoint =\n                                            // high surrogate occupies the most significant 22 bits\n                                            (codepoint1 << 10)\n                                            // low surrogate occupies the least significant 15 bits\n                                            + codepoint2\n                                            // there is still the 0xD800, 0xDC00 and 0x10000 noise\n                                            // in the result so we have to subtract with:\n                                            // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00\n                                            - 0x35FDC00;\n                                    }\n                                    else\n                                    {\n                                        error_message = \"invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF\";\n                                        return token_type::parse_error;\n                                    }\n                                }\n                                else\n                                {\n                                    error_message = \"invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF\";\n                                    return token_type::parse_error;\n                                }\n                            }\n                            else\n                            {\n                                if (JSON_UNLIKELY(0xDC00 <= codepoint1 and codepoint1 <= 0xDFFF))\n                                {\n                                    error_message = \"invalid string: surrogate U+DC00..U+DFFF must follow U+D800..U+DBFF\";\n                                    return token_type::parse_error;\n                                }\n                            }\n\n                            // result of the above calculation yields a proper codepoint\n                            assert(0x00 <= codepoint and codepoint <= 0x10FFFF);\n\n                            // translate codepoint into bytes\n                            if (codepoint < 0x80)\n                            {\n                                // 1-byte characters: 0xxxxxxx (ASCII)\n                                add(codepoint);\n                            }\n                            else if (codepoint <= 0x7FF)\n                            {\n                                // 2-byte characters: 110xxxxx 10xxxxxx\n                                add(0xC0 | (codepoint >> 6));\n                                add(0x80 | (codepoint & 0x3F));\n                            }\n                            else if (codepoint <= 0xFFFF)\n                            {\n                                // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx\n                                add(0xE0 | (codepoint >> 12));\n                                add(0x80 | ((codepoint >> 6) & 0x3F));\n                                add(0x80 | (codepoint & 0x3F));\n                            }\n                            else\n                            {\n                                // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx\n                                add(0xF0 | (codepoint >> 18));\n                                add(0x80 | ((codepoint >> 12) & 0x3F));\n                                add(0x80 | ((codepoint >> 6) & 0x3F));\n                                add(0x80 | (codepoint & 0x3F));\n                            }\n\n                            break;\n                        }\n\n                        // other characters after escape\n                        default:\n                            error_message = \"invalid string: forbidden character after backslash\";\n                            return token_type::parse_error;\n                    }\n\n                    break;\n                }\n\n                // invalid control characters\n                case 0x00:\n                {\n                    error_message = \"invalid string: control character U+0000 (NUL) must be escaped to \\\\u0000\";\n                    return token_type::parse_error;\n                }\n\n                case 0x01:\n                {\n                    error_message = \"invalid string: control character U+0001 (SOH) must be escaped to \\\\u0001\";\n                    return token_type::parse_error;\n                }\n\n                case 0x02:\n                {\n                    error_message = \"invalid string: control character U+0002 (STX) must be escaped to \\\\u0002\";\n                    return token_type::parse_error;\n                }\n\n                case 0x03:\n                {\n                    error_message = \"invalid string: control character U+0003 (ETX) must be escaped to \\\\u0003\";\n                    return token_type::parse_error;\n                }\n\n                case 0x04:\n                {\n                    error_message = \"invalid string: control character U+0004 (EOT) must be escaped to \\\\u0004\";\n                    return token_type::parse_error;\n                }\n\n                case 0x05:\n                {\n                    error_message = \"invalid string: control character U+0005 (ENQ) must be escaped to \\\\u0005\";\n                    return token_type::parse_error;\n                }\n\n                case 0x06:\n                {\n                    error_message = \"invalid string: control character U+0006 (ACK) must be escaped to \\\\u0006\";\n                    return token_type::parse_error;\n                }\n\n                case 0x07:\n                {\n                    error_message = \"invalid string: control character U+0007 (BEL) must be escaped to \\\\u0007\";\n                    return token_type::parse_error;\n                }\n\n                case 0x08:\n                {\n                    error_message = \"invalid string: control character U+0008 (BS) must be escaped to \\\\u0008 or \\\\b\";\n                    return token_type::parse_error;\n                }\n\n                case 0x09:\n                {\n                    error_message = \"invalid string: control character U+0009 (HT) must be escaped to \\\\u0009 or \\\\t\";\n                    return token_type::parse_error;\n                }\n\n                case 0x0A:\n                {\n                    error_message = \"invalid string: control character U+000A (LF) must be escaped to \\\\u000A or \\\\n\";\n                    return token_type::parse_error;\n                }\n\n                case 0x0B:\n                {\n                    error_message = \"invalid string: control character U+000B (VT) must be escaped to \\\\u000B\";\n                    return token_type::parse_error;\n                }\n\n                case 0x0C:\n                {\n                    error_message = \"invalid string: control character U+000C (FF) must be escaped to \\\\u000C or \\\\f\";\n                    return token_type::parse_error;\n                }\n\n                case 0x0D:\n                {\n                    error_message = \"invalid string: control character U+000D (CR) must be escaped to \\\\u000D or \\\\r\";\n                    return token_type::parse_error;\n                }\n\n                case 0x0E:\n                {\n                    error_message = \"invalid string: control character U+000E (SO) must be escaped to \\\\u000E\";\n                    return token_type::parse_error;\n                }\n\n                case 0x0F:\n                {\n                    error_message = \"invalid string: control character U+000F (SI) must be escaped to \\\\u000F\";\n                    return token_type::parse_error;\n                }\n\n                case 0x10:\n                {\n                    error_message = \"invalid string: control character U+0010 (DLE) must be escaped to \\\\u0010\";\n                    return token_type::parse_error;\n                }\n\n                case 0x11:\n                {\n                    error_message = \"invalid string: control character U+0011 (DC1) must be escaped to \\\\u0011\";\n                    return token_type::parse_error;\n                }\n\n                case 0x12:\n                {\n                    error_message = \"invalid string: control character U+0012 (DC2) must be escaped to \\\\u0012\";\n                    return token_type::parse_error;\n                }\n\n                case 0x13:\n                {\n                    error_message = \"invalid string: control character U+0013 (DC3) must be escaped to \\\\u0013\";\n                    return token_type::parse_error;\n                }\n\n                case 0x14:\n                {\n                    error_message = \"invalid string: control character U+0014 (DC4) must be escaped to \\\\u0014\";\n                    return token_type::parse_error;\n                }\n\n                case 0x15:\n                {\n                    error_message = \"invalid string: control character U+0015 (NAK) must be escaped to \\\\u0015\";\n                    return token_type::parse_error;\n                }\n\n                case 0x16:\n                {\n                    error_message = \"invalid string: control character U+0016 (SYN) must be escaped to \\\\u0016\";\n                    return token_type::parse_error;\n                }\n\n                case 0x17:\n                {\n                    error_message = \"invalid string: control character U+0017 (ETB) must be escaped to \\\\u0017\";\n                    return token_type::parse_error;\n                }\n\n                case 0x18:\n                {\n                    error_message = \"invalid string: control character U+0018 (CAN) must be escaped to \\\\u0018\";\n                    return token_type::parse_error;\n                }\n\n                case 0x19:\n                {\n                    error_message = \"invalid string: control character U+0019 (EM) must be escaped to \\\\u0019\";\n                    return token_type::parse_error;\n                }\n\n                case 0x1A:\n                {\n                    error_message = \"invalid string: control character U+001A (SUB) must be escaped to \\\\u001A\";\n                    return token_type::parse_error;\n                }\n\n                case 0x1B:\n                {\n                    error_message = \"invalid string: control character U+001B (ESC) must be escaped to \\\\u001B\";\n                    return token_type::parse_error;\n                }\n\n                case 0x1C:\n                {\n                    error_message = \"invalid string: control character U+001C (FS) must be escaped to \\\\u001C\";\n                    return token_type::parse_error;\n                }\n\n                case 0x1D:\n                {\n                    error_message = \"invalid string: control character U+001D (GS) must be escaped to \\\\u001D\";\n                    return token_type::parse_error;\n                }\n\n                case 0x1E:\n                {\n                    error_message = \"invalid string: control character U+001E (RS) must be escaped to \\\\u001E\";\n                    return token_type::parse_error;\n                }\n\n                case 0x1F:\n                {\n                    error_message = \"invalid string: control character U+001F (US) must be escaped to \\\\u001F\";\n                    return token_type::parse_error;\n                }\n\n                // U+0020..U+007F (except U+0022 (quote) and U+005C (backspace))\n                case 0x20:\n                case 0x21:\n                case 0x23:\n                case 0x24:\n                case 0x25:\n                case 0x26:\n                case 0x27:\n                case 0x28:\n                case 0x29:\n                case 0x2A:\n                case 0x2B:\n                case 0x2C:\n                case 0x2D:\n                case 0x2E:\n                case 0x2F:\n                case 0x30:\n                case 0x31:\n                case 0x32:\n                case 0x33:\n                case 0x34:\n                case 0x35:\n                case 0x36:\n                case 0x37:\n                case 0x38:\n                case 0x39:\n                case 0x3A:\n                case 0x3B:\n                case 0x3C:\n                case 0x3D:\n                case 0x3E:\n                case 0x3F:\n                case 0x40:\n                case 0x41:\n                case 0x42:\n                case 0x43:\n                case 0x44:\n                case 0x45:\n                case 0x46:\n                case 0x47:\n                case 0x48:\n                case 0x49:\n                case 0x4A:\n                case 0x4B:\n                case 0x4C:\n                case 0x4D:\n                case 0x4E:\n                case 0x4F:\n                case 0x50:\n                case 0x51:\n                case 0x52:\n                case 0x53:\n                case 0x54:\n                case 0x55:\n                case 0x56:\n                case 0x57:\n                case 0x58:\n                case 0x59:\n                case 0x5A:\n                case 0x5B:\n                case 0x5D:\n                case 0x5E:\n                case 0x5F:\n                case 0x60:\n                case 0x61:\n                case 0x62:\n                case 0x63:\n                case 0x64:\n                case 0x65:\n                case 0x66:\n                case 0x67:\n                case 0x68:\n                case 0x69:\n                case 0x6A:\n                case 0x6B:\n                case 0x6C:\n                case 0x6D:\n                case 0x6E:\n                case 0x6F:\n                case 0x70:\n                case 0x71:\n                case 0x72:\n                case 0x73:\n                case 0x74:\n                case 0x75:\n                case 0x76:\n                case 0x77:\n                case 0x78:\n                case 0x79:\n                case 0x7A:\n                case 0x7B:\n                case 0x7C:\n                case 0x7D:\n                case 0x7E:\n                case 0x7F:\n                {\n                    add(current);\n                    break;\n                }\n\n                // U+0080..U+07FF: bytes C2..DF 80..BF\n                case 0xC2:\n                case 0xC3:\n                case 0xC4:\n                case 0xC5:\n                case 0xC6:\n                case 0xC7:\n                case 0xC8:\n                case 0xC9:\n                case 0xCA:\n                case 0xCB:\n                case 0xCC:\n                case 0xCD:\n                case 0xCE:\n                case 0xCF:\n                case 0xD0:\n                case 0xD1:\n                case 0xD2:\n                case 0xD3:\n                case 0xD4:\n                case 0xD5:\n                case 0xD6:\n                case 0xD7:\n                case 0xD8:\n                case 0xD9:\n                case 0xDA:\n                case 0xDB:\n                case 0xDC:\n                case 0xDD:\n                case 0xDE:\n                case 0xDF:\n                {\n                    if (JSON_UNLIKELY(not next_byte_in_range({0x80, 0xBF})))\n                    {\n                        return token_type::parse_error;\n                    }\n                    break;\n                }\n\n                // U+0800..U+0FFF: bytes E0 A0..BF 80..BF\n                case 0xE0:\n                {\n                    if (JSON_UNLIKELY(not (next_byte_in_range({0xA0, 0xBF, 0x80, 0xBF}))))\n                    {\n                        return token_type::parse_error;\n                    }\n                    break;\n                }\n\n                // U+1000..U+CFFF: bytes E1..EC 80..BF 80..BF\n                // U+E000..U+FFFF: bytes EE..EF 80..BF 80..BF\n                case 0xE1:\n                case 0xE2:\n                case 0xE3:\n                case 0xE4:\n                case 0xE5:\n                case 0xE6:\n                case 0xE7:\n                case 0xE8:\n                case 0xE9:\n                case 0xEA:\n                case 0xEB:\n                case 0xEC:\n                case 0xEE:\n                case 0xEF:\n                {\n                    if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0xBF, 0x80, 0xBF}))))\n                    {\n                        return token_type::parse_error;\n                    }\n                    break;\n                }\n\n                // U+D000..U+D7FF: bytes ED 80..9F 80..BF\n                case 0xED:\n                {\n                    if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0x9F, 0x80, 0xBF}))))\n                    {\n                        return token_type::parse_error;\n                    }\n                    break;\n                }\n\n                // U+10000..U+3FFFF F0 90..BF 80..BF 80..BF\n                case 0xF0:\n                {\n                    if (JSON_UNLIKELY(not (next_byte_in_range({0x90, 0xBF, 0x80, 0xBF, 0x80, 0xBF}))))\n                    {\n                        return token_type::parse_error;\n                    }\n                    break;\n                }\n\n                // U+40000..U+FFFFF F1..F3 80..BF 80..BF 80..BF\n                case 0xF1:\n                case 0xF2:\n                case 0xF3:\n                {\n                    if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF}))))\n                    {\n                        return token_type::parse_error;\n                    }\n                    break;\n                }\n\n                // U+100000..U+10FFFF F4 80..8F 80..BF 80..BF\n                case 0xF4:\n                {\n                    if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0x8F, 0x80, 0xBF, 0x80, 0xBF}))))\n                    {\n                        return token_type::parse_error;\n                    }\n                    break;\n                }\n\n                // remaining bytes (80..C1 and F5..FF) are ill-formed\n                default:\n                {\n                    error_message = \"invalid string: ill-formed UTF-8 byte\";\n                    return token_type::parse_error;\n                }\n            }\n        }\n    }\n\n    static void strtof(float& f, const char* str, char** endptr) noexcept\n    {\n        f = std::strtof(str, endptr);\n    }\n\n    static void strtof(double& f, const char* str, char** endptr) noexcept\n    {\n        f = std::strtod(str, endptr);\n    }\n\n    static void strtof(long double& f, const char* str, char** endptr) noexcept\n    {\n        f = std::strtold(str, endptr);\n    }\n\n    /*!\n    @brief scan a number literal\n\n    This function scans a string according to Sect. 6 of RFC 7159.\n\n    The function is realized with a deterministic finite state machine derived\n    from the grammar described in RFC 7159. Starting in state \"init\", the\n    input is read and used to determined the next state. Only state \"done\"\n    accepts the number. State \"error\" is a trap state to model errors. In the\n    table below, \"anything\" means any character but the ones listed before.\n\n    state    | 0        | 1-9      | e E      | +       | -       | .        | anything\n    ---------|----------|----------|----------|---------|---------|----------|-----------\n    init     | zero     | any1     | [error]  | [error] | minus   | [error]  | [error]\n    minus    | zero     | any1     | [error]  | [error] | [error] | [error]  | [error]\n    zero     | done     | done     | exponent | done    | done    | decimal1 | done\n    any1     | any1     | any1     | exponent | done    | done    | decimal1 | done\n    decimal1 | decimal2 | [error]  | [error]  | [error] | [error] | [error]  | [error]\n    decimal2 | decimal2 | decimal2 | exponent | done    | done    | done     | done\n    exponent | any2     | any2     | [error]  | sign    | sign    | [error]  | [error]\n    sign     | any2     | any2     | [error]  | [error] | [error] | [error]  | [error]\n    any2     | any2     | any2     | done     | done    | done    | done     | done\n\n    The state machine is realized with one label per state (prefixed with\n    \"scan_number_\") and `goto` statements between them. The state machine\n    contains cycles, but any cycle can be left when EOF is read. Therefore,\n    the function is guaranteed to terminate.\n\n    During scanning, the read bytes are stored in token_buffer. This string is\n    then converted to a signed integer, an unsigned integer, or a\n    floating-point number.\n\n    @return token_type::value_unsigned, token_type::value_integer, or\n            token_type::value_float if number could be successfully scanned,\n            token_type::parse_error otherwise\n\n    @note The scanner is independent of the current locale. Internally, the\n          locale's decimal point is used instead of `.` to work with the\n          locale-dependent converters.\n    */\n    token_type scan_number()  // lgtm [cpp/use-of-goto]\n    {\n        // reset token_buffer to store the number's bytes\n        reset();\n\n        // the type of the parsed number; initially set to unsigned; will be\n        // changed if minus sign, decimal point or exponent is read\n        token_type number_type = token_type::value_unsigned;\n\n        // state (init): we just found out we need to scan a number\n        switch (current)\n        {\n            case '-':\n            {\n                add(current);\n                goto scan_number_minus;\n            }\n\n            case '0':\n            {\n                add(current);\n                goto scan_number_zero;\n            }\n\n            case '1':\n            case '2':\n            case '3':\n            case '4':\n            case '5':\n            case '6':\n            case '7':\n            case '8':\n            case '9':\n            {\n                add(current);\n                goto scan_number_any1;\n            }\n\n            // LCOV_EXCL_START\n            default:\n            {\n                // all other characters are rejected outside scan_number()\n                assert(false);\n            }\n                // LCOV_EXCL_STOP\n        }\n\nscan_number_minus:\n        // state: we just parsed a leading minus sign\n        number_type = token_type::value_integer;\n        switch (get())\n        {\n            case '0':\n            {\n                add(current);\n                goto scan_number_zero;\n            }\n\n            case '1':\n            case '2':\n            case '3':\n            case '4':\n            case '5':\n            case '6':\n            case '7':\n            case '8':\n            case '9':\n            {\n                add(current);\n                goto scan_number_any1;\n            }\n\n            default:\n            {\n                error_message = \"invalid number; expected digit after '-'\";\n                return token_type::parse_error;\n            }\n        }\n\nscan_number_zero:\n        // state: we just parse a zero (maybe with a leading minus sign)\n        switch (get())\n        {\n            case '.':\n            {\n                add(decimal_point_char);\n                goto scan_number_decimal1;\n            }\n\n            case 'e':\n            case 'E':\n            {\n                add(current);\n                goto scan_number_exponent;\n            }\n\n            default:\n                goto scan_number_done;\n        }\n\nscan_number_any1:\n        // state: we just parsed a number 0-9 (maybe with a leading minus sign)\n        switch (get())\n        {\n            case '0':\n            case '1':\n            case '2':\n            case '3':\n            case '4':\n            case '5':\n            case '6':\n            case '7':\n            case '8':\n            case '9':\n            {\n                add(current);\n                goto scan_number_any1;\n            }\n\n            case '.':\n            {\n                add(decimal_point_char);\n                goto scan_number_decimal1;\n            }\n\n            case 'e':\n            case 'E':\n            {\n                add(current);\n                goto scan_number_exponent;\n            }\n\n            default:\n                goto scan_number_done;\n        }\n\nscan_number_decimal1:\n        // state: we just parsed a decimal point\n        number_type = token_type::value_float;\n        switch (get())\n        {\n            case '0':\n            case '1':\n            case '2':\n            case '3':\n            case '4':\n            case '5':\n            case '6':\n            case '7':\n            case '8':\n            case '9':\n            {\n                add(current);\n                goto scan_number_decimal2;\n            }\n\n            default:\n            {\n                error_message = \"invalid number; expected digit after '.'\";\n                return token_type::parse_error;\n            }\n        }\n\nscan_number_decimal2:\n        // we just parsed at least one number after a decimal point\n        switch (get())\n        {\n            case '0':\n            case '1':\n            case '2':\n            case '3':\n            case '4':\n            case '5':\n            case '6':\n            case '7':\n            case '8':\n            case '9':\n            {\n                add(current);\n                goto scan_number_decimal2;\n            }\n\n            case 'e':\n            case 'E':\n            {\n                add(current);\n                goto scan_number_exponent;\n            }\n\n            default:\n                goto scan_number_done;\n        }\n\nscan_number_exponent:\n        // we just parsed an exponent\n        number_type = token_type::value_float;\n        switch (get())\n        {\n            case '+':\n            case '-':\n            {\n                add(current);\n                goto scan_number_sign;\n            }\n\n            case '0':\n            case '1':\n            case '2':\n            case '3':\n            case '4':\n            case '5':\n            case '6':\n            case '7':\n            case '8':\n            case '9':\n            {\n                add(current);\n                goto scan_number_any2;\n            }\n\n            default:\n            {\n                error_message =\n                    \"invalid number; expected '+', '-', or digit after exponent\";\n                return token_type::parse_error;\n            }\n        }\n\nscan_number_sign:\n        // we just parsed an exponent sign\n        switch (get())\n        {\n            case '0':\n            case '1':\n            case '2':\n            case '3':\n            case '4':\n            case '5':\n            case '6':\n            case '7':\n            case '8':\n            case '9':\n            {\n                add(current);\n                goto scan_number_any2;\n            }\n\n            default:\n            {\n                error_message = \"invalid number; expected digit after exponent sign\";\n                return token_type::parse_error;\n            }\n        }\n\nscan_number_any2:\n        // we just parsed a number after the exponent or exponent sign\n        switch (get())\n        {\n            case '0':\n            case '1':\n            case '2':\n            case '3':\n            case '4':\n            case '5':\n            case '6':\n            case '7':\n            case '8':\n            case '9':\n            {\n                add(current);\n                goto scan_number_any2;\n            }\n\n            default:\n                goto scan_number_done;\n        }\n\nscan_number_done:\n        // unget the character after the number (we only read it to know that\n        // we are done scanning a number)\n        unget();\n\n        char* endptr = nullptr;\n        errno = 0;\n\n        // try to parse integers first and fall back to floats\n        if (number_type == token_type::value_unsigned)\n        {\n            const auto x = std::strtoull(token_buffer.data(), &endptr, 10);\n\n            // we checked the number format before\n            assert(endptr == token_buffer.data() + token_buffer.size());\n\n            if (errno == 0)\n            {\n                value_unsigned = static_cast<number_unsigned_t>(x);\n                if (value_unsigned == x)\n                {\n                    return token_type::value_unsigned;\n                }\n            }\n        }\n        else if (number_type == token_type::value_integer)\n        {\n            const auto x = std::strtoll(token_buffer.data(), &endptr, 10);\n\n            // we checked the number format before\n            assert(endptr == token_buffer.data() + token_buffer.size());\n\n            if (errno == 0)\n            {\n                value_integer = static_cast<number_integer_t>(x);\n                if (value_integer == x)\n                {\n                    return token_type::value_integer;\n                }\n            }\n        }\n\n        // this code is reached if we parse a floating-point number or if an\n        // integer conversion above failed\n        strtof(value_float, token_buffer.data(), &endptr);\n\n        // we checked the number format before\n        assert(endptr == token_buffer.data() + token_buffer.size());\n\n        return token_type::value_float;\n    }\n\n    /*!\n    @param[in] literal_text  the literal text to expect\n    @param[in] length        the length of the passed literal text\n    @param[in] return_type   the token type to return on success\n    */\n    token_type scan_literal(const char* literal_text, const std::size_t length,\n                            token_type return_type)\n    {\n        assert(current == literal_text[0]);\n        for (std::size_t i = 1; i < length; ++i)\n        {\n            if (JSON_UNLIKELY(get() != literal_text[i]))\n            {\n                error_message = \"invalid literal\";\n                return token_type::parse_error;\n            }\n        }\n        return return_type;\n    }\n\n    /////////////////////\n    // input management\n    /////////////////////\n\n    /// reset token_buffer; current character is beginning of token\n    void reset() noexcept\n    {\n        token_buffer.clear();\n        token_string.clear();\n        token_string.push_back(std::char_traits<char>::to_char_type(current));\n    }\n\n    /*\n    @brief get next character from the input\n\n    This function provides the interface to the used input adapter. It does\n    not throw in case the input reached EOF, but returns a\n    `std::char_traits<char>::eof()` in that case.  Stores the scanned characters\n    for use in error messages.\n\n    @return character read from the input\n    */\n    std::char_traits<char>::int_type get()\n    {\n        ++position.chars_read_total;\n        ++position.chars_read_current_line;\n\n        if (next_unget)\n        {\n            // just reset the next_unget variable and work with current\n            next_unget = false;\n        }\n        else\n        {\n            current = ia->get_character();\n        }\n\n        if (JSON_LIKELY(current != std::char_traits<char>::eof()))\n        {\n            token_string.push_back(std::char_traits<char>::to_char_type(current));\n        }\n\n        if (current == '\\n')\n        {\n            ++position.lines_read;\n            ++position.chars_read_current_line = 0;\n        }\n\n        return current;\n    }\n\n    /*!\n    @brief unget current character (read it again on next get)\n\n    We implement unget by setting variable next_unget to true. The input is not\n    changed - we just simulate ungetting by modifying chars_read_total,\n    chars_read_current_line, and token_string. The next call to get() will\n    behave as if the unget character is read again.\n    */\n    void unget()\n    {\n        next_unget = true;\n\n        --position.chars_read_total;\n\n        // in case we \"unget\" a newline, we have to also decrement the lines_read\n        if (position.chars_read_current_line == 0)\n        {\n            if (position.lines_read > 0)\n            {\n                --position.lines_read;\n            }\n        }\n        else\n        {\n            --position.chars_read_current_line;\n        }\n\n        if (JSON_LIKELY(current != std::char_traits<char>::eof()))\n        {\n            assert(token_string.size() != 0);\n            token_string.pop_back();\n        }\n    }\n\n    /// add a character to token_buffer\n    void add(int c)\n    {\n        token_buffer.push_back(std::char_traits<char>::to_char_type(c));\n    }\n\n  public:\n    /////////////////////\n    // value getters\n    /////////////////////\n\n    /// return integer value\n    constexpr number_integer_t get_number_integer() const noexcept\n    {\n        return value_integer;\n    }\n\n    /// return unsigned integer value\n    constexpr number_unsigned_t get_number_unsigned() const noexcept\n    {\n        return value_unsigned;\n    }\n\n    /// return floating-point value\n    constexpr number_float_t get_number_float() const noexcept\n    {\n        return value_float;\n    }\n\n    /// return current string value (implicitly resets the token; useful only once)\n    string_t& get_string()\n    {\n        return token_buffer;\n    }\n\n    /////////////////////\n    // diagnostics\n    /////////////////////\n\n    /// return position of last read token\n    constexpr position_t get_position() const noexcept\n    {\n        return position;\n    }\n\n    /// return the last read token (for errors only).  Will never contain EOF\n    /// (an arbitrary value that is not a valid char value, often -1), because\n    /// 255 may legitimately occur.  May contain NUL, which should be escaped.\n    std::string get_token_string() const\n    {\n        // escape control characters\n        std::string result;\n        for (const auto c : token_string)\n        {\n            if ('\\x00' <= c and c <= '\\x1F')\n            {\n                // escape control characters\n                char cs[9];\n                (std::snprintf)(cs, 9, \"<U+%.4X>\", static_cast<unsigned char>(c));\n                result += cs;\n            }\n            else\n            {\n                // add character as is\n                result.push_back(c);\n            }\n        }\n\n        return result;\n    }\n\n    /// return syntax error message\n    constexpr const char* get_error_message() const noexcept\n    {\n        return error_message;\n    }\n\n    /////////////////////\n    // actual scanner\n    /////////////////////\n\n    /*!\n    @brief skip the UTF-8 byte order mark\n    @return true iff there is no BOM or the correct BOM has been skipped\n    */\n    bool skip_bom()\n    {\n        if (get() == 0xEF)\n        {\n            // check if we completely parse the BOM\n            return get() == 0xBB and get() == 0xBF;\n        }\n\n        // the first character is not the beginning of the BOM; unget it to\n        // process is later\n        unget();\n        return true;\n    }\n\n    token_type scan()\n    {\n        // initially, skip the BOM\n        if (position.chars_read_total == 0 and not skip_bom())\n        {\n            error_message = \"invalid BOM; must be 0xEF 0xBB 0xBF if given\";\n            return token_type::parse_error;\n        }\n\n        // read next character and ignore whitespace\n        do\n        {\n            get();\n        }\n        while (current == ' ' or current == '\\t' or current == '\\n' or current == '\\r');\n\n        switch (current)\n        {\n            // structural characters\n            case '[':\n                return token_type::begin_array;\n            case ']':\n                return token_type::end_array;\n            case '{':\n                return token_type::begin_object;\n            case '}':\n                return token_type::end_object;\n            case ':':\n                return token_type::name_separator;\n            case ',':\n                return token_type::value_separator;\n\n            // literals\n            case 't':\n                return scan_literal(\"true\", 4, token_type::literal_true);\n            case 'f':\n                return scan_literal(\"false\", 5, token_type::literal_false);\n            case 'n':\n                return scan_literal(\"null\", 4, token_type::literal_null);\n\n            // string\n            case '\\\"':\n                return scan_string();\n\n            // number\n            case '-':\n            case '0':\n            case '1':\n            case '2':\n            case '3':\n            case '4':\n            case '5':\n            case '6':\n            case '7':\n            case '8':\n            case '9':\n                return scan_number();\n\n            // end of input (the null byte is needed when parsing from\n            // string literals)\n            case '\\0':\n            case std::char_traits<char>::eof():\n                return token_type::end_of_input;\n\n            // error\n            default:\n                error_message = \"invalid literal\";\n                return token_type::parse_error;\n        }\n    }\n\n  private:\n    /// input adapter\n    detail::input_adapter_t ia = nullptr;\n\n    /// the current character\n    std::char_traits<char>::int_type current = std::char_traits<char>::eof();\n\n    /// whether the next get() call should just return current\n    bool next_unget = false;\n\n    /// the start position of the current token\n    position_t position;\n\n    /// raw input token string (for error messages)\n    std::vector<char> token_string {};\n\n    /// buffer for variable-length tokens (numbers, strings)\n    string_t token_buffer {};\n\n    /// a description of occurred lexer errors\n    const char* error_message = \"\";\n\n    // number values\n    number_integer_t value_integer = 0;\n    number_unsigned_t value_unsigned = 0;\n    number_float_t value_float = 0;\n\n    /// the decimal point\n    const char decimal_point_char = '.';\n};\n}  // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/input/parser.hpp>\n\n\n#include <cassert> // assert\n#include <cmath> // isfinite\n#include <cstdint> // uint8_t\n#include <functional> // function\n#include <string> // string\n#include <utility> // move\n\n// #include <nlohmann/detail/exceptions.hpp>\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n// #include <nlohmann/detail/meta/is_sax.hpp>\n\n\n#include <cstdint> // size_t\n#include <utility> // declval\n\n// #include <nlohmann/detail/meta/detected.hpp>\n\n// #include <nlohmann/detail/meta/type_traits.hpp>\n\n\nnamespace nlohmann\n{\nnamespace detail\n{\ntemplate <typename T>\nusing null_function_t = decltype(std::declval<T&>().null());\n\ntemplate <typename T>\nusing boolean_function_t =\n    decltype(std::declval<T&>().boolean(std::declval<bool>()));\n\ntemplate <typename T, typename Integer>\nusing number_integer_function_t =\n    decltype(std::declval<T&>().number_integer(std::declval<Integer>()));\n\ntemplate <typename T, typename Unsigned>\nusing number_unsigned_function_t =\n    decltype(std::declval<T&>().number_unsigned(std::declval<Unsigned>()));\n\ntemplate <typename T, typename Float, typename String>\nusing number_float_function_t = decltype(std::declval<T&>().number_float(\n                                    std::declval<Float>(), std::declval<const String&>()));\n\ntemplate <typename T, typename String>\nusing string_function_t =\n    decltype(std::declval<T&>().string(std::declval<String&>()));\n\ntemplate <typename T>\nusing start_object_function_t =\n    decltype(std::declval<T&>().start_object(std::declval<std::size_t>()));\n\ntemplate <typename T, typename String>\nusing key_function_t =\n    decltype(std::declval<T&>().key(std::declval<String&>()));\n\ntemplate <typename T>\nusing end_object_function_t = decltype(std::declval<T&>().end_object());\n\ntemplate <typename T>\nusing start_array_function_t =\n    decltype(std::declval<T&>().start_array(std::declval<std::size_t>()));\n\ntemplate <typename T>\nusing end_array_function_t = decltype(std::declval<T&>().end_array());\n\ntemplate <typename T, typename Exception>\nusing parse_error_function_t = decltype(std::declval<T&>().parse_error(\n        std::declval<std::size_t>(), std::declval<const std::string&>(),\n        std::declval<const Exception&>()));\n\ntemplate <typename SAX, typename BasicJsonType>\nstruct is_sax\n{\n  private:\n    static_assert(is_basic_json<BasicJsonType>::value,\n                  \"BasicJsonType must be of type basic_json<...>\");\n\n    using number_integer_t = typename BasicJsonType::number_integer_t;\n    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n    using number_float_t = typename BasicJsonType::number_float_t;\n    using string_t = typename BasicJsonType::string_t;\n    using exception_t = typename BasicJsonType::exception;\n\n  public:\n    static constexpr bool value =\n        is_detected_exact<bool, null_function_t, SAX>::value &&\n        is_detected_exact<bool, boolean_function_t, SAX>::value &&\n        is_detected_exact<bool, number_integer_function_t, SAX,\n        number_integer_t>::value &&\n        is_detected_exact<bool, number_unsigned_function_t, SAX,\n        number_unsigned_t>::value &&\n        is_detected_exact<bool, number_float_function_t, SAX, number_float_t,\n        string_t>::value &&\n        is_detected_exact<bool, string_function_t, SAX, string_t>::value &&\n        is_detected_exact<bool, start_object_function_t, SAX>::value &&\n        is_detected_exact<bool, key_function_t, SAX, string_t>::value &&\n        is_detected_exact<bool, end_object_function_t, SAX>::value &&\n        is_detected_exact<bool, start_array_function_t, SAX>::value &&\n        is_detected_exact<bool, end_array_function_t, SAX>::value &&\n        is_detected_exact<bool, parse_error_function_t, SAX, exception_t>::value;\n};\n\ntemplate <typename SAX, typename BasicJsonType>\nstruct is_sax_static_asserts\n{\n  private:\n    static_assert(is_basic_json<BasicJsonType>::value,\n                  \"BasicJsonType must be of type basic_json<...>\");\n\n    using number_integer_t = typename BasicJsonType::number_integer_t;\n    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n    using number_float_t = typename BasicJsonType::number_float_t;\n    using string_t = typename BasicJsonType::string_t;\n    using exception_t = typename BasicJsonType::exception;\n\n  public:\n    static_assert(is_detected_exact<bool, null_function_t, SAX>::value,\n                  \"Missing/invalid function: bool null()\");\n    static_assert(is_detected_exact<bool, boolean_function_t, SAX>::value,\n                  \"Missing/invalid function: bool boolean(bool)\");\n    static_assert(is_detected_exact<bool, boolean_function_t, SAX>::value,\n                  \"Missing/invalid function: bool boolean(bool)\");\n    static_assert(\n        is_detected_exact<bool, number_integer_function_t, SAX,\n        number_integer_t>::value,\n        \"Missing/invalid function: bool number_integer(number_integer_t)\");\n    static_assert(\n        is_detected_exact<bool, number_unsigned_function_t, SAX,\n        number_unsigned_t>::value,\n        \"Missing/invalid function: bool number_unsigned(number_unsigned_t)\");\n    static_assert(is_detected_exact<bool, number_float_function_t, SAX,\n                  number_float_t, string_t>::value,\n                  \"Missing/invalid function: bool number_float(number_float_t, const string_t&)\");\n    static_assert(\n        is_detected_exact<bool, string_function_t, SAX, string_t>::value,\n        \"Missing/invalid function: bool string(string_t&)\");\n    static_assert(is_detected_exact<bool, start_object_function_t, SAX>::value,\n                  \"Missing/invalid function: bool start_object(std::size_t)\");\n    static_assert(is_detected_exact<bool, key_function_t, SAX, string_t>::value,\n                  \"Missing/invalid function: bool key(string_t&)\");\n    static_assert(is_detected_exact<bool, end_object_function_t, SAX>::value,\n                  \"Missing/invalid function: bool end_object()\");\n    static_assert(is_detected_exact<bool, start_array_function_t, SAX>::value,\n                  \"Missing/invalid function: bool start_array(std::size_t)\");\n    static_assert(is_detected_exact<bool, end_array_function_t, SAX>::value,\n                  \"Missing/invalid function: bool end_array()\");\n    static_assert(\n        is_detected_exact<bool, parse_error_function_t, SAX, exception_t>::value,\n        \"Missing/invalid function: bool parse_error(std::size_t, const \"\n        \"std::string&, const exception&)\");\n};\n}  // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/input/input_adapters.hpp>\n\n// #include <nlohmann/detail/input/json_sax.hpp>\n\n\n#include <cstddef>\n#include <string>\n#include <vector>\n\n// #include <nlohmann/detail/input/parser.hpp>\n\n// #include <nlohmann/detail/exceptions.hpp>\n\n\nnamespace nlohmann\n{\n\n/*!\n@brief SAX interface\n\nThis class describes the SAX interface used by @ref nlohmann::json::sax_parse.\nEach function is called in different situations while the input is parsed. The\nboolean return value informs the parser whether to continue processing the\ninput.\n*/\ntemplate<typename BasicJsonType>\nstruct json_sax\n{\n    /// type for (signed) integers\n    using number_integer_t = typename BasicJsonType::number_integer_t;\n    /// type for unsigned integers\n    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n    /// type for floating-point numbers\n    using number_float_t = typename BasicJsonType::number_float_t;\n    /// type for strings\n    using string_t = typename BasicJsonType::string_t;\n\n    /*!\n    @brief a null value was read\n    @return whether parsing should proceed\n    */\n    virtual bool null() = 0;\n\n    /*!\n    @brief a boolean value was read\n    @param[in] val  boolean value\n    @return whether parsing should proceed\n    */\n    virtual bool boolean(bool val) = 0;\n\n    /*!\n    @brief an integer number was read\n    @param[in] val  integer value\n    @return whether parsing should proceed\n    */\n    virtual bool number_integer(number_integer_t val) = 0;\n\n    /*!\n    @brief an unsigned integer number was read\n    @param[in] val  unsigned integer value\n    @return whether parsing should proceed\n    */\n    virtual bool number_unsigned(number_unsigned_t val) = 0;\n\n    /*!\n    @brief an floating-point number was read\n    @param[in] val  floating-point value\n    @param[in] s    raw token value\n    @return whether parsing should proceed\n    */\n    virtual bool number_float(number_float_t val, const string_t& s) = 0;\n\n    /*!\n    @brief a string was read\n    @param[in] val  string value\n    @return whether parsing should proceed\n    @note It is safe to move the passed string.\n    */\n    virtual bool string(string_t& val) = 0;\n\n    /*!\n    @brief the beginning of an object was read\n    @param[in] elements  number of object elements or -1 if unknown\n    @return whether parsing should proceed\n    @note binary formats may report the number of elements\n    */\n    virtual bool start_object(std::size_t elements) = 0;\n\n    /*!\n    @brief an object key was read\n    @param[in] val  object key\n    @return whether parsing should proceed\n    @note It is safe to move the passed string.\n    */\n    virtual bool key(string_t& val) = 0;\n\n    /*!\n    @brief the end of an object was read\n    @return whether parsing should proceed\n    */\n    virtual bool end_object() = 0;\n\n    /*!\n    @brief the beginning of an array was read\n    @param[in] elements  number of array elements or -1 if unknown\n    @return whether parsing should proceed\n    @note binary formats may report the number of elements\n    */\n    virtual bool start_array(std::size_t elements) = 0;\n\n    /*!\n    @brief the end of an array was read\n    @return whether parsing should proceed\n    */\n    virtual bool end_array() = 0;\n\n    /*!\n    @brief a parse error occurred\n    @param[in] position    the position in the input where the error occurs\n    @param[in] last_token  the last read token\n    @param[in] ex          an exception object describing the error\n    @return whether parsing should proceed (must return false)\n    */\n    virtual bool parse_error(std::size_t position,\n                             const std::string& last_token,\n                             const detail::exception& ex) = 0;\n\n    virtual ~json_sax() = default;\n};\n\n\nnamespace detail\n{\n/*!\n@brief SAX implementation to create a JSON value from SAX events\n\nThis class implements the @ref json_sax interface and processes the SAX events\nto create a JSON value which makes it basically a DOM parser. The structure or\nhierarchy of the JSON value is managed by the stack `ref_stack` which contains\na pointer to the respective array or object for each recursion depth.\n\nAfter successful parsing, the value that is passed by reference to the\nconstructor contains the parsed value.\n\n@tparam BasicJsonType  the JSON type\n*/\ntemplate<typename BasicJsonType>\nclass json_sax_dom_parser\n{\n  public:\n    using number_integer_t = typename BasicJsonType::number_integer_t;\n    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n    using number_float_t = typename BasicJsonType::number_float_t;\n    using string_t = typename BasicJsonType::string_t;\n\n    /*!\n    @param[in, out] r  reference to a JSON value that is manipulated while\n                       parsing\n    @param[in] allow_exceptions_  whether parse errors yield exceptions\n    */\n    explicit json_sax_dom_parser(BasicJsonType& r, const bool allow_exceptions_ = true)\n        : root(r), allow_exceptions(allow_exceptions_)\n    {}\n\n    bool null()\n    {\n        handle_value(nullptr);\n        return true;\n    }\n\n    bool boolean(bool val)\n    {\n        handle_value(val);\n        return true;\n    }\n\n    bool number_integer(number_integer_t val)\n    {\n        handle_value(val);\n        return true;\n    }\n\n    bool number_unsigned(number_unsigned_t val)\n    {\n        handle_value(val);\n        return true;\n    }\n\n    bool number_float(number_float_t val, const string_t& /*unused*/)\n    {\n        handle_value(val);\n        return true;\n    }\n\n    bool string(string_t& val)\n    {\n        handle_value(val);\n        return true;\n    }\n\n    bool start_object(std::size_t len)\n    {\n        ref_stack.push_back(handle_value(BasicJsonType::value_t::object));\n\n        if (JSON_UNLIKELY(len != std::size_t(-1) and len > ref_stack.back()->max_size()))\n        {\n            JSON_THROW(out_of_range::create(408,\n                                            \"excessive object size: \" + std::to_string(len)));\n        }\n\n        return true;\n    }\n\n    bool key(string_t& val)\n    {\n        // add null at given key and store the reference for later\n        object_element = &(ref_stack.back()->m_value.object->operator[](val));\n        return true;\n    }\n\n    bool end_object()\n    {\n        ref_stack.pop_back();\n        return true;\n    }\n\n    bool start_array(std::size_t len)\n    {\n        ref_stack.push_back(handle_value(BasicJsonType::value_t::array));\n\n        if (JSON_UNLIKELY(len != std::size_t(-1) and len > ref_stack.back()->max_size()))\n        {\n            JSON_THROW(out_of_range::create(408,\n                                            \"excessive array size: \" + std::to_string(len)));\n        }\n\n        return true;\n    }\n\n    bool end_array()\n    {\n        ref_stack.pop_back();\n        return true;\n    }\n\n    bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/,\n                     const detail::exception& ex)\n    {\n        errored = true;\n        if (allow_exceptions)\n        {\n            // determine the proper exception type from the id\n            switch ((ex.id / 100) % 100)\n            {\n                case 1:\n                    JSON_THROW(*reinterpret_cast<const detail::parse_error*>(&ex));\n                case 4:\n                    JSON_THROW(*reinterpret_cast<const detail::out_of_range*>(&ex));\n                // LCOV_EXCL_START\n                case 2:\n                    JSON_THROW(*reinterpret_cast<const detail::invalid_iterator*>(&ex));\n                case 3:\n                    JSON_THROW(*reinterpret_cast<const detail::type_error*>(&ex));\n                case 5:\n                    JSON_THROW(*reinterpret_cast<const detail::other_error*>(&ex));\n                default:\n                    assert(false);\n                    // LCOV_EXCL_STOP\n            }\n        }\n        return false;\n    }\n\n    constexpr bool is_errored() const\n    {\n        return errored;\n    }\n\n  private:\n    /*!\n    @invariant If the ref stack is empty, then the passed value will be the new\n               root.\n    @invariant If the ref stack contains a value, then it is an array or an\n               object to which we can add elements\n    */\n    template<typename Value>\n    BasicJsonType* handle_value(Value&& v)\n    {\n        if (ref_stack.empty())\n        {\n            root = BasicJsonType(std::forward<Value>(v));\n            return &root;\n        }\n\n        assert(ref_stack.back()->is_array() or ref_stack.back()->is_object());\n\n        if (ref_stack.back()->is_array())\n        {\n            ref_stack.back()->m_value.array->emplace_back(std::forward<Value>(v));\n            return &(ref_stack.back()->m_value.array->back());\n        }\n        else\n        {\n            assert(object_element);\n            *object_element = BasicJsonType(std::forward<Value>(v));\n            return object_element;\n        }\n    }\n\n    /// the parsed JSON value\n    BasicJsonType& root;\n    /// stack to model hierarchy of values\n    std::vector<BasicJsonType*> ref_stack;\n    /// helper to hold the reference for the next object element\n    BasicJsonType* object_element = nullptr;\n    /// whether a syntax error occurred\n    bool errored = false;\n    /// whether to throw exceptions in case of errors\n    const bool allow_exceptions = true;\n};\n\ntemplate<typename BasicJsonType>\nclass json_sax_dom_callback_parser\n{\n  public:\n    using number_integer_t = typename BasicJsonType::number_integer_t;\n    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n    using number_float_t = typename BasicJsonType::number_float_t;\n    using string_t = typename BasicJsonType::string_t;\n    using parser_callback_t = typename BasicJsonType::parser_callback_t;\n    using parse_event_t = typename BasicJsonType::parse_event_t;\n\n    json_sax_dom_callback_parser(BasicJsonType& r,\n                                 const parser_callback_t cb,\n                                 const bool allow_exceptions_ = true)\n        : root(r), callback(cb), allow_exceptions(allow_exceptions_)\n    {\n        keep_stack.push_back(true);\n    }\n\n    bool null()\n    {\n        handle_value(nullptr);\n        return true;\n    }\n\n    bool boolean(bool val)\n    {\n        handle_value(val);\n        return true;\n    }\n\n    bool number_integer(number_integer_t val)\n    {\n        handle_value(val);\n        return true;\n    }\n\n    bool number_unsigned(number_unsigned_t val)\n    {\n        handle_value(val);\n        return true;\n    }\n\n    bool number_float(number_float_t val, const string_t& /*unused*/)\n    {\n        handle_value(val);\n        return true;\n    }\n\n    bool string(string_t& val)\n    {\n        handle_value(val);\n        return true;\n    }\n\n    bool start_object(std::size_t len)\n    {\n        // check callback for object start\n        const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::object_start, discarded);\n        keep_stack.push_back(keep);\n\n        auto val = handle_value(BasicJsonType::value_t::object, true);\n        ref_stack.push_back(val.second);\n\n        // check object limit\n        if (ref_stack.back())\n        {\n            if (JSON_UNLIKELY(len != std::size_t(-1) and len > ref_stack.back()->max_size()))\n            {\n                JSON_THROW(out_of_range::create(408,\n                                                \"excessive object size: \" + std::to_string(len)));\n            }\n        }\n\n        return true;\n    }\n\n    bool key(string_t& val)\n    {\n        BasicJsonType k = BasicJsonType(val);\n\n        // check callback for key\n        const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::key, k);\n        key_keep_stack.push_back(keep);\n\n        // add discarded value at given key and store the reference for later\n        if (keep and ref_stack.back())\n        {\n            object_element = &(ref_stack.back()->m_value.object->operator[](val) = discarded);\n        }\n\n        return true;\n    }\n\n    bool end_object()\n    {\n        if (ref_stack.back())\n        {\n            if (not callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::object_end, *ref_stack.back()))\n            {\n                // discard object\n                *ref_stack.back() = discarded;\n            }\n        }\n\n        assert(not ref_stack.empty());\n        assert(not keep_stack.empty());\n        ref_stack.pop_back();\n        keep_stack.pop_back();\n\n        if (not ref_stack.empty() and ref_stack.back())\n        {\n            // remove discarded value\n            if (ref_stack.back()->is_object())\n            {\n                for (auto it = ref_stack.back()->begin(); it != ref_stack.back()->end(); ++it)\n                {\n                    if (it->is_discarded())\n                    {\n                        ref_stack.back()->erase(it);\n                        break;\n                    }\n                }\n            }\n        }\n\n        return true;\n    }\n\n    bool start_array(std::size_t len)\n    {\n        const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::array_start, discarded);\n        keep_stack.push_back(keep);\n\n        auto val = handle_value(BasicJsonType::value_t::array, true);\n        ref_stack.push_back(val.second);\n\n        // check array limit\n        if (ref_stack.back())\n        {\n            if (JSON_UNLIKELY(len != std::size_t(-1) and len > ref_stack.back()->max_size()))\n            {\n                JSON_THROW(out_of_range::create(408,\n                                                \"excessive array size: \" + std::to_string(len)));\n            }\n        }\n\n        return true;\n    }\n\n    bool end_array()\n    {\n        bool keep = true;\n\n        if (ref_stack.back())\n        {\n            keep = callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::array_end, *ref_stack.back());\n            if (not keep)\n            {\n                // discard array\n                *ref_stack.back() = discarded;\n            }\n        }\n\n        assert(not ref_stack.empty());\n        assert(not keep_stack.empty());\n        ref_stack.pop_back();\n        keep_stack.pop_back();\n\n        // remove discarded value\n        if (not keep and not ref_stack.empty())\n        {\n            if (ref_stack.back()->is_array())\n            {\n                ref_stack.back()->m_value.array->pop_back();\n            }\n        }\n\n        return true;\n    }\n\n    bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/,\n                     const detail::exception& ex)\n    {\n        errored = true;\n        if (allow_exceptions)\n        {\n            // determine the proper exception type from the id\n            switch ((ex.id / 100) % 100)\n            {\n                case 1:\n                    JSON_THROW(*reinterpret_cast<const detail::parse_error*>(&ex));\n                case 4:\n                    JSON_THROW(*reinterpret_cast<const detail::out_of_range*>(&ex));\n                // LCOV_EXCL_START\n                case 2:\n                    JSON_THROW(*reinterpret_cast<const detail::invalid_iterator*>(&ex));\n                case 3:\n                    JSON_THROW(*reinterpret_cast<const detail::type_error*>(&ex));\n                case 5:\n                    JSON_THROW(*reinterpret_cast<const detail::other_error*>(&ex));\n                default:\n                    assert(false);\n                    // LCOV_EXCL_STOP\n            }\n        }\n        return false;\n    }\n\n    constexpr bool is_errored() const\n    {\n        return errored;\n    }\n\n  private:\n    /*!\n    @param[in] v  value to add to the JSON value we build during parsing\n    @param[in] skip_callback  whether we should skip calling the callback\n               function; this is required after start_array() and\n               start_object() SAX events, because otherwise we would call the\n               callback function with an empty array or object, respectively.\n\n    @invariant If the ref stack is empty, then the passed value will be the new\n               root.\n    @invariant If the ref stack contains a value, then it is an array or an\n               object to which we can add elements\n\n    @return pair of boolean (whether value should be kept) and pointer (to the\n            passed value in the ref_stack hierarchy; nullptr if not kept)\n    */\n    template<typename Value>\n    std::pair<bool, BasicJsonType*> handle_value(Value&& v, const bool skip_callback = false)\n    {\n        assert(not keep_stack.empty());\n\n        // do not handle this value if we know it would be added to a discarded\n        // container\n        if (not keep_stack.back())\n        {\n            return {false, nullptr};\n        }\n\n        // create value\n        auto value = BasicJsonType(std::forward<Value>(v));\n\n        // check callback\n        const bool keep = skip_callback or callback(static_cast<int>(ref_stack.size()), parse_event_t::value, value);\n\n        // do not handle this value if we just learnt it shall be discarded\n        if (not keep)\n        {\n            return {false, nullptr};\n        }\n\n        if (ref_stack.empty())\n        {\n            root = std::move(value);\n            return {true, &root};\n        }\n\n        // skip this value if we already decided to skip the parent\n        // (https://github.com/nlohmann/json/issues/971#issuecomment-413678360)\n        if (not ref_stack.back())\n        {\n            return {false, nullptr};\n        }\n\n        // we now only expect arrays and objects\n        assert(ref_stack.back()->is_array() or ref_stack.back()->is_object());\n\n        if (ref_stack.back()->is_array())\n        {\n            ref_stack.back()->m_value.array->push_back(std::move(value));\n            return {true, &(ref_stack.back()->m_value.array->back())};\n        }\n        else\n        {\n            // check if we should store an element for the current key\n            assert(not key_keep_stack.empty());\n            const bool store_element = key_keep_stack.back();\n            key_keep_stack.pop_back();\n\n            if (not store_element)\n            {\n                return {false, nullptr};\n            }\n\n            assert(object_element);\n            *object_element = std::move(value);\n            return {true, object_element};\n        }\n    }\n\n    /// the parsed JSON value\n    BasicJsonType& root;\n    /// stack to model hierarchy of values\n    std::vector<BasicJsonType*> ref_stack;\n    /// stack to manage which values to keep\n    std::vector<bool> keep_stack;\n    /// stack to manage which object keys to keep\n    std::vector<bool> key_keep_stack;\n    /// helper to hold the reference for the next object element\n    BasicJsonType* object_element = nullptr;\n    /// whether a syntax error occurred\n    bool errored = false;\n    /// callback function\n    const parser_callback_t callback = nullptr;\n    /// whether to throw exceptions in case of errors\n    const bool allow_exceptions = true;\n    /// a discarded value for the callback\n    BasicJsonType discarded = BasicJsonType::value_t::discarded;\n};\n\ntemplate<typename BasicJsonType>\nclass json_sax_acceptor\n{\n  public:\n    using number_integer_t = typename BasicJsonType::number_integer_t;\n    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n    using number_float_t = typename BasicJsonType::number_float_t;\n    using string_t = typename BasicJsonType::string_t;\n\n    bool null()\n    {\n        return true;\n    }\n\n    bool boolean(bool /*unused*/)\n    {\n        return true;\n    }\n\n    bool number_integer(number_integer_t /*unused*/)\n    {\n        return true;\n    }\n\n    bool number_unsigned(number_unsigned_t /*unused*/)\n    {\n        return true;\n    }\n\n    bool number_float(number_float_t /*unused*/, const string_t& /*unused*/)\n    {\n        return true;\n    }\n\n    bool string(string_t& /*unused*/)\n    {\n        return true;\n    }\n\n    bool start_object(std::size_t  /*unused*/ = std::size_t(-1))\n    {\n        return true;\n    }\n\n    bool key(string_t& /*unused*/)\n    {\n        return true;\n    }\n\n    bool end_object()\n    {\n        return true;\n    }\n\n    bool start_array(std::size_t  /*unused*/ = std::size_t(-1))\n    {\n        return true;\n    }\n\n    bool end_array()\n    {\n        return true;\n    }\n\n    bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const detail::exception& /*unused*/)\n    {\n        return false;\n    }\n};\n}  // namespace detail\n\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/input/lexer.hpp>\n\n// #include <nlohmann/detail/value_t.hpp>\n\n\nnamespace nlohmann\n{\nnamespace detail\n{\n////////////\n// parser //\n////////////\n\n/*!\n@brief syntax analysis\n\nThis class implements a recursive decent parser.\n*/\ntemplate<typename BasicJsonType>\nclass parser\n{\n    using number_integer_t = typename BasicJsonType::number_integer_t;\n    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n    using number_float_t = typename BasicJsonType::number_float_t;\n    using string_t = typename BasicJsonType::string_t;\n    using lexer_t = lexer<BasicJsonType>;\n    using token_type = typename lexer_t::token_type;\n\n  public:\n    enum class parse_event_t : uint8_t\n    {\n        /// the parser read `{` and started to process a JSON object\n        object_start,\n        /// the parser read `}` and finished processing a JSON object\n        object_end,\n        /// the parser read `[` and started to process a JSON array\n        array_start,\n        /// the parser read `]` and finished processing a JSON array\n        array_end,\n        /// the parser read a key of a value in an object\n        key,\n        /// the parser finished reading a JSON value\n        value\n    };\n\n    using parser_callback_t =\n        std::function<bool(int depth, parse_event_t event, BasicJsonType& parsed)>;\n\n    /// a parser reading from an input adapter\n    explicit parser(detail::input_adapter_t&& adapter,\n                    const parser_callback_t cb = nullptr,\n                    const bool allow_exceptions_ = true)\n        : callback(cb), m_lexer(std::move(adapter)), allow_exceptions(allow_exceptions_)\n    {\n        // read first token\n        get_token();\n    }\n\n    /*!\n    @brief public parser interface\n\n    @param[in] strict      whether to expect the last token to be EOF\n    @param[in,out] result  parsed JSON value\n\n    @throw parse_error.101 in case of an unexpected token\n    @throw parse_error.102 if to_unicode fails or surrogate error\n    @throw parse_error.103 if to_unicode fails\n    */\n    void parse(const bool strict, BasicJsonType& result)\n    {\n        if (callback)\n        {\n            json_sax_dom_callback_parser<BasicJsonType> sdp(result, callback, allow_exceptions);\n            sax_parse_internal(&sdp);\n            result.assert_invariant();\n\n            // in strict mode, input must be completely read\n            if (strict and (get_token() != token_type::end_of_input))\n            {\n                sdp.parse_error(m_lexer.get_position(),\n                                m_lexer.get_token_string(),\n                                parse_error::create(101, m_lexer.get_position(),\n                                                    exception_message(token_type::end_of_input, \"value\")));\n            }\n\n            // in case of an error, return discarded value\n            if (sdp.is_errored())\n            {\n                result = value_t::discarded;\n                return;\n            }\n\n            // set top-level value to null if it was discarded by the callback\n            // function\n            if (result.is_discarded())\n            {\n                result = nullptr;\n            }\n        }\n        else\n        {\n            json_sax_dom_parser<BasicJsonType> sdp(result, allow_exceptions);\n            sax_parse_internal(&sdp);\n            result.assert_invariant();\n\n            // in strict mode, input must be completely read\n            if (strict and (get_token() != token_type::end_of_input))\n            {\n                sdp.parse_error(m_lexer.get_position(),\n                                m_lexer.get_token_string(),\n                                parse_error::create(101, m_lexer.get_position(),\n                                                    exception_message(token_type::end_of_input, \"value\")));\n            }\n\n            // in case of an error, return discarded value\n            if (sdp.is_errored())\n            {\n                result = value_t::discarded;\n                return;\n            }\n        }\n    }\n\n    /*!\n    @brief public accept interface\n\n    @param[in] strict  whether to expect the last token to be EOF\n    @return whether the input is a proper JSON text\n    */\n    bool accept(const bool strict = true)\n    {\n        json_sax_acceptor<BasicJsonType> sax_acceptor;\n        return sax_parse(&sax_acceptor, strict);\n    }\n\n    template <typename SAX>\n    bool sax_parse(SAX* sax, const bool strict = true)\n    {\n        (void)detail::is_sax_static_asserts<SAX, BasicJsonType> {};\n        const bool result = sax_parse_internal(sax);\n\n        // strict mode: next byte must be EOF\n        if (result and strict and (get_token() != token_type::end_of_input))\n        {\n            return sax->parse_error(m_lexer.get_position(),\n                                    m_lexer.get_token_string(),\n                                    parse_error::create(101, m_lexer.get_position(),\n                                            exception_message(token_type::end_of_input, \"value\")));\n        }\n\n        return result;\n    }\n\n  private:\n    template <typename SAX>\n    bool sax_parse_internal(SAX* sax)\n    {\n        // stack to remember the hierarchy of structured values we are parsing\n        // true = array; false = object\n        std::vector<bool> states;\n        // value to avoid a goto (see comment where set to true)\n        bool skip_to_state_evaluation = false;\n\n        while (true)\n        {\n            if (not skip_to_state_evaluation)\n            {\n                // invariant: get_token() was called before each iteration\n                switch (last_token)\n                {\n                    case token_type::begin_object:\n                    {\n                        if (JSON_UNLIKELY(not sax->start_object(std::size_t(-1))))\n                        {\n                            return false;\n                        }\n\n                        // closing } -> we are done\n                        if (get_token() == token_type::end_object)\n                        {\n                            if (JSON_UNLIKELY(not sax->end_object()))\n                            {\n                                return false;\n                            }\n                            break;\n                        }\n\n                        // parse key\n                        if (JSON_UNLIKELY(last_token != token_type::value_string))\n                        {\n                            return sax->parse_error(m_lexer.get_position(),\n                                                    m_lexer.get_token_string(),\n                                                    parse_error::create(101, m_lexer.get_position(),\n                                                            exception_message(token_type::value_string, \"object key\")));\n                        }\n                        if (JSON_UNLIKELY(not sax->key(m_lexer.get_string())))\n                        {\n                            return false;\n                        }\n\n                        // parse separator (:)\n                        if (JSON_UNLIKELY(get_token() != token_type::name_separator))\n                        {\n                            return sax->parse_error(m_lexer.get_position(),\n                                                    m_lexer.get_token_string(),\n                                                    parse_error::create(101, m_lexer.get_position(),\n                                                            exception_message(token_type::name_separator, \"object separator\")));\n                        }\n\n                        // remember we are now inside an object\n                        states.push_back(false);\n\n                        // parse values\n                        get_token();\n                        continue;\n                    }\n\n                    case token_type::begin_array:\n                    {\n                        if (JSON_UNLIKELY(not sax->start_array(std::size_t(-1))))\n                        {\n                            return false;\n                        }\n\n                        // closing ] -> we are done\n                        if (get_token() == token_type::end_array)\n                        {\n                            if (JSON_UNLIKELY(not sax->end_array()))\n                            {\n                                return false;\n                            }\n                            break;\n                        }\n\n                        // remember we are now inside an array\n                        states.push_back(true);\n\n                        // parse values (no need to call get_token)\n                        continue;\n                    }\n\n                    case token_type::value_float:\n                    {\n                        const auto res = m_lexer.get_number_float();\n\n                        if (JSON_UNLIKELY(not std::isfinite(res)))\n                        {\n                            return sax->parse_error(m_lexer.get_position(),\n                                                    m_lexer.get_token_string(),\n                                                    out_of_range::create(406, \"number overflow parsing '\" + m_lexer.get_token_string() + \"'\"));\n                        }\n                        else\n                        {\n                            if (JSON_UNLIKELY(not sax->number_float(res, m_lexer.get_string())))\n                            {\n                                return false;\n                            }\n                            break;\n                        }\n                    }\n\n                    case token_type::literal_false:\n                    {\n                        if (JSON_UNLIKELY(not sax->boolean(false)))\n                        {\n                            return false;\n                        }\n                        break;\n                    }\n\n                    case token_type::literal_null:\n                    {\n                        if (JSON_UNLIKELY(not sax->null()))\n                        {\n                            return false;\n                        }\n                        break;\n                    }\n\n                    case token_type::literal_true:\n                    {\n                        if (JSON_UNLIKELY(not sax->boolean(true)))\n                        {\n                            return false;\n                        }\n                        break;\n                    }\n\n                    case token_type::value_integer:\n                    {\n                        if (JSON_UNLIKELY(not sax->number_integer(m_lexer.get_number_integer())))\n                        {\n                            return false;\n                        }\n                        break;\n                    }\n\n                    case token_type::value_string:\n                    {\n                        if (JSON_UNLIKELY(not sax->string(m_lexer.get_string())))\n                        {\n                            return false;\n                        }\n                        break;\n                    }\n\n                    case token_type::value_unsigned:\n                    {\n                        if (JSON_UNLIKELY(not sax->number_unsigned(m_lexer.get_number_unsigned())))\n                        {\n                            return false;\n                        }\n                        break;\n                    }\n\n                    case token_type::parse_error:\n                    {\n                        // using \"uninitialized\" to avoid \"expected\" message\n                        return sax->parse_error(m_lexer.get_position(),\n                                                m_lexer.get_token_string(),\n                                                parse_error::create(101, m_lexer.get_position(),\n                                                        exception_message(token_type::uninitialized, \"value\")));\n                    }\n\n                    default: // the last token was unexpected\n                    {\n                        return sax->parse_error(m_lexer.get_position(),\n                                                m_lexer.get_token_string(),\n                                                parse_error::create(101, m_lexer.get_position(),\n                                                        exception_message(token_type::literal_or_value, \"value\")));\n                    }\n                }\n            }\n            else\n            {\n                skip_to_state_evaluation = false;\n            }\n\n            // we reached this line after we successfully parsed a value\n            if (states.empty())\n            {\n                // empty stack: we reached the end of the hierarchy: done\n                return true;\n            }\n            else\n            {\n                if (states.back())  // array\n                {\n                    // comma -> next value\n                    if (get_token() == token_type::value_separator)\n                    {\n                        // parse a new value\n                        get_token();\n                        continue;\n                    }\n\n                    // closing ]\n                    if (JSON_LIKELY(last_token == token_type::end_array))\n                    {\n                        if (JSON_UNLIKELY(not sax->end_array()))\n                        {\n                            return false;\n                        }\n\n                        // We are done with this array. Before we can parse a\n                        // new value, we need to evaluate the new state first.\n                        // By setting skip_to_state_evaluation to false, we\n                        // are effectively jumping to the beginning of this if.\n                        assert(not states.empty());\n                        states.pop_back();\n                        skip_to_state_evaluation = true;\n                        continue;\n                    }\n                    else\n                    {\n                        return sax->parse_error(m_lexer.get_position(),\n                                                m_lexer.get_token_string(),\n                                                parse_error::create(101, m_lexer.get_position(),\n                                                        exception_message(token_type::end_array, \"array\")));\n                    }\n                }\n                else  // object\n                {\n                    // comma -> next value\n                    if (get_token() == token_type::value_separator)\n                    {\n                        // parse key\n                        if (JSON_UNLIKELY(get_token() != token_type::value_string))\n                        {\n                            return sax->parse_error(m_lexer.get_position(),\n                                                    m_lexer.get_token_string(),\n                                                    parse_error::create(101, m_lexer.get_position(),\n                                                            exception_message(token_type::value_string, \"object key\")));\n                        }\n                        else\n                        {\n                            if (JSON_UNLIKELY(not sax->key(m_lexer.get_string())))\n                            {\n                                return false;\n                            }\n                        }\n\n                        // parse separator (:)\n                        if (JSON_UNLIKELY(get_token() != token_type::name_separator))\n                        {\n                            return sax->parse_error(m_lexer.get_position(),\n                                                    m_lexer.get_token_string(),\n                                                    parse_error::create(101, m_lexer.get_position(),\n                                                            exception_message(token_type::name_separator, \"object separator\")));\n                        }\n\n                        // parse values\n                        get_token();\n                        continue;\n                    }\n\n                    // closing }\n                    if (JSON_LIKELY(last_token == token_type::end_object))\n                    {\n                        if (JSON_UNLIKELY(not sax->end_object()))\n                        {\n                            return false;\n                        }\n\n                        // We are done with this object. Before we can parse a\n                        // new value, we need to evaluate the new state first.\n                        // By setting skip_to_state_evaluation to false, we\n                        // are effectively jumping to the beginning of this if.\n                        assert(not states.empty());\n                        states.pop_back();\n                        skip_to_state_evaluation = true;\n                        continue;\n                    }\n                    else\n                    {\n                        return sax->parse_error(m_lexer.get_position(),\n                                                m_lexer.get_token_string(),\n                                                parse_error::create(101, m_lexer.get_position(),\n                                                        exception_message(token_type::end_object, \"object\")));\n                    }\n                }\n            }\n        }\n    }\n\n    /// get next token from lexer\n    token_type get_token()\n    {\n        return (last_token = m_lexer.scan());\n    }\n\n    std::string exception_message(const token_type expected, const std::string& context)\n    {\n        std::string error_msg = \"syntax error \";\n\n        if (not context.empty())\n        {\n            error_msg += \"while parsing \" + context + \" \";\n        }\n\n        error_msg += \"- \";\n\n        if (last_token == token_type::parse_error)\n        {\n            error_msg += std::string(m_lexer.get_error_message()) + \"; last read: '\" +\n                         m_lexer.get_token_string() + \"'\";\n        }\n        else\n        {\n            error_msg += \"unexpected \" + std::string(lexer_t::token_type_name(last_token));\n        }\n\n        if (expected != token_type::uninitialized)\n        {\n            error_msg += \"; expected \" + std::string(lexer_t::token_type_name(expected));\n        }\n\n        return error_msg;\n    }\n\n  private:\n    /// callback function\n    const parser_callback_t callback = nullptr;\n    /// the type of the last read token\n    token_type last_token = token_type::uninitialized;\n    /// the lexer\n    lexer_t m_lexer;\n    /// whether to throw exceptions in case of errors\n    const bool allow_exceptions = true;\n};\n}  // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/iterators/primitive_iterator.hpp>\n\n\n#include <cstddef> // ptrdiff_t\n#include <limits>  // numeric_limits\n\nnamespace nlohmann\n{\nnamespace detail\n{\n/*\n@brief an iterator for primitive JSON types\n\nThis class models an iterator for primitive JSON types (boolean, number,\nstring). It's only purpose is to allow the iterator/const_iterator classes\nto \"iterate\" over primitive values. Internally, the iterator is modeled by\na `difference_type` variable. Value begin_value (`0`) models the begin,\nend_value (`1`) models past the end.\n*/\nclass primitive_iterator_t\n{\n  private:\n    using difference_type = std::ptrdiff_t;\n    static constexpr difference_type begin_value = 0;\n    static constexpr difference_type end_value = begin_value + 1;\n\n    /// iterator as signed integer type\n    difference_type m_it = (std::numeric_limits<std::ptrdiff_t>::min)();\n\n  public:\n    constexpr difference_type get_value() const noexcept\n    {\n        return m_it;\n    }\n\n    /// set iterator to a defined beginning\n    void set_begin() noexcept\n    {\n        m_it = begin_value;\n    }\n\n    /// set iterator to a defined past the end\n    void set_end() noexcept\n    {\n        m_it = end_value;\n    }\n\n    /// return whether the iterator can be dereferenced\n    constexpr bool is_begin() const noexcept\n    {\n        return m_it == begin_value;\n    }\n\n    /// return whether the iterator is at end\n    constexpr bool is_end() const noexcept\n    {\n        return m_it == end_value;\n    }\n\n    friend constexpr bool operator==(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept\n    {\n        return lhs.m_it == rhs.m_it;\n    }\n\n    friend constexpr bool operator<(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept\n    {\n        return lhs.m_it < rhs.m_it;\n    }\n\n    primitive_iterator_t operator+(difference_type n) noexcept\n    {\n        auto result = *this;\n        result += n;\n        return result;\n    }\n\n    friend constexpr difference_type operator-(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept\n    {\n        return lhs.m_it - rhs.m_it;\n    }\n\n    primitive_iterator_t& operator++() noexcept\n    {\n        ++m_it;\n        return *this;\n    }\n\n    primitive_iterator_t const operator++(int) noexcept\n    {\n        auto result = *this;\n        ++m_it;\n        return result;\n    }\n\n    primitive_iterator_t& operator--() noexcept\n    {\n        --m_it;\n        return *this;\n    }\n\n    primitive_iterator_t const operator--(int) noexcept\n    {\n        auto result = *this;\n        --m_it;\n        return result;\n    }\n\n    primitive_iterator_t& operator+=(difference_type n) noexcept\n    {\n        m_it += n;\n        return *this;\n    }\n\n    primitive_iterator_t& operator-=(difference_type n) noexcept\n    {\n        m_it -= n;\n        return *this;\n    }\n};\n}  // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/iterators/internal_iterator.hpp>\n\n\n// #include <nlohmann/detail/iterators/primitive_iterator.hpp>\n\n\nnamespace nlohmann\n{\nnamespace detail\n{\n/*!\n@brief an iterator value\n\n@note This structure could easily be a union, but MSVC currently does not allow\nunions members with complex constructors, see https://github.com/nlohmann/json/pull/105.\n*/\ntemplate<typename BasicJsonType> struct internal_iterator\n{\n    /// iterator for JSON objects\n    typename BasicJsonType::object_t::iterator object_iterator {};\n    /// iterator for JSON arrays\n    typename BasicJsonType::array_t::iterator array_iterator {};\n    /// generic iterator for all other types\n    primitive_iterator_t primitive_iterator {};\n};\n}  // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/iterators/iter_impl.hpp>\n\n\n#include <ciso646> // not\n#include <iterator> // iterator, random_access_iterator_tag, bidirectional_iterator_tag, advance, next\n#include <type_traits> // conditional, is_const, remove_const\n\n// #include <nlohmann/detail/exceptions.hpp>\n\n// #include <nlohmann/detail/iterators/internal_iterator.hpp>\n\n// #include <nlohmann/detail/iterators/primitive_iterator.hpp>\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n// #include <nlohmann/detail/meta/cpp_future.hpp>\n\n// #include <nlohmann/detail/value_t.hpp>\n\n\nnamespace nlohmann\n{\nnamespace detail\n{\n// forward declare, to be able to friend it later on\ntemplate<typename IteratorType> class iteration_proxy;\ntemplate<typename IteratorType> class iteration_proxy_value;\n\n/*!\n@brief a template for a bidirectional iterator for the @ref basic_json class\nThis class implements a both iterators (iterator and const_iterator) for the\n@ref basic_json class.\n@note An iterator is called *initialized* when a pointer to a JSON value has\n      been set (e.g., by a constructor or a copy assignment). If the iterator is\n      default-constructed, it is *uninitialized* and most methods are undefined.\n      **The library uses assertions to detect calls on uninitialized iterators.**\n@requirement The class satisfies the following concept requirements:\n-\n[BidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator):\n  The iterator that can be moved can be moved in both directions (i.e.\n  incremented and decremented).\n@since version 1.0.0, simplified in version 2.0.9, change to bidirectional\n       iterators in version 3.0.0 (see https://github.com/nlohmann/json/issues/593)\n*/\ntemplate<typename BasicJsonType>\nclass iter_impl\n{\n    /// allow basic_json to access private members\n    friend iter_impl<typename std::conditional<std::is_const<BasicJsonType>::value, typename std::remove_const<BasicJsonType>::type, const BasicJsonType>::type>;\n    friend BasicJsonType;\n    friend iteration_proxy<iter_impl>;\n    friend iteration_proxy_value<iter_impl>;\n\n    using object_t = typename BasicJsonType::object_t;\n    using array_t = typename BasicJsonType::array_t;\n    // make sure BasicJsonType is basic_json or const basic_json\n    static_assert(is_basic_json<typename std::remove_const<BasicJsonType>::type>::value,\n                  \"iter_impl only accepts (const) basic_json\");\n\n  public:\n\n    /// The std::iterator class template (used as a base class to provide typedefs) is deprecated in C++17.\n    /// The C++ Standard has never required user-defined iterators to derive from std::iterator.\n    /// A user-defined iterator should provide publicly accessible typedefs named\n    /// iterator_category, value_type, difference_type, pointer, and reference.\n    /// Note that value_type is required to be non-const, even for constant iterators.\n    using iterator_category = std::bidirectional_iterator_tag;\n\n    /// the type of the values when the iterator is dereferenced\n    using value_type = typename BasicJsonType::value_type;\n    /// a type to represent differences between iterators\n    using difference_type = typename BasicJsonType::difference_type;\n    /// defines a pointer to the type iterated over (value_type)\n    using pointer = typename std::conditional<std::is_const<BasicJsonType>::value,\n          typename BasicJsonType::const_pointer,\n          typename BasicJsonType::pointer>::type;\n    /// defines a reference to the type iterated over (value_type)\n    using reference =\n        typename std::conditional<std::is_const<BasicJsonType>::value,\n        typename BasicJsonType::const_reference,\n        typename BasicJsonType::reference>::type;\n\n    /// default constructor\n    iter_impl() = default;\n\n    /*!\n    @brief constructor for a given JSON instance\n    @param[in] object  pointer to a JSON object for this iterator\n    @pre object != nullptr\n    @post The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    explicit iter_impl(pointer object) noexcept : m_object(object)\n    {\n        assert(m_object != nullptr);\n\n        switch (m_object->m_type)\n        {\n            case value_t::object:\n            {\n                m_it.object_iterator = typename object_t::iterator();\n                break;\n            }\n\n            case value_t::array:\n            {\n                m_it.array_iterator = typename array_t::iterator();\n                break;\n            }\n\n            default:\n            {\n                m_it.primitive_iterator = primitive_iterator_t();\n                break;\n            }\n        }\n    }\n\n    /*!\n    @note The conventional copy constructor and copy assignment are implicitly\n          defined. Combined with the following converting constructor and\n          assignment, they support: (1) copy from iterator to iterator, (2)\n          copy from const iterator to const iterator, and (3) conversion from\n          iterator to const iterator. However conversion from const iterator\n          to iterator is not defined.\n    */\n\n    /*!\n    @brief converting constructor\n    @param[in] other  non-const iterator to copy from\n    @note It is not checked whether @a other is initialized.\n    */\n    iter_impl(const iter_impl<typename std::remove_const<BasicJsonType>::type>& other) noexcept\n        : m_object(other.m_object), m_it(other.m_it) {}\n\n    /*!\n    @brief converting assignment\n    @param[in,out] other  non-const iterator to copy from\n    @return const/non-const iterator\n    @note It is not checked whether @a other is initialized.\n    */\n    iter_impl& operator=(const iter_impl<typename std::remove_const<BasicJsonType>::type>& other) noexcept\n    {\n        m_object = other.m_object;\n        m_it = other.m_it;\n        return *this;\n    }\n\n  private:\n    /*!\n    @brief set the iterator to the first value\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    void set_begin() noexcept\n    {\n        assert(m_object != nullptr);\n\n        switch (m_object->m_type)\n        {\n            case value_t::object:\n            {\n                m_it.object_iterator = m_object->m_value.object->begin();\n                break;\n            }\n\n            case value_t::array:\n            {\n                m_it.array_iterator = m_object->m_value.array->begin();\n                break;\n            }\n\n            case value_t::null:\n            {\n                // set to end so begin()==end() is true: null is empty\n                m_it.primitive_iterator.set_end();\n                break;\n            }\n\n            default:\n            {\n                m_it.primitive_iterator.set_begin();\n                break;\n            }\n        }\n    }\n\n    /*!\n    @brief set the iterator past the last value\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    void set_end() noexcept\n    {\n        assert(m_object != nullptr);\n\n        switch (m_object->m_type)\n        {\n            case value_t::object:\n            {\n                m_it.object_iterator = m_object->m_value.object->end();\n                break;\n            }\n\n            case value_t::array:\n            {\n                m_it.array_iterator = m_object->m_value.array->end();\n                break;\n            }\n\n            default:\n            {\n                m_it.primitive_iterator.set_end();\n                break;\n            }\n        }\n    }\n\n  public:\n    /*!\n    @brief return a reference to the value pointed to by the iterator\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    reference operator*() const\n    {\n        assert(m_object != nullptr);\n\n        switch (m_object->m_type)\n        {\n            case value_t::object:\n            {\n                assert(m_it.object_iterator != m_object->m_value.object->end());\n                return m_it.object_iterator->second;\n            }\n\n            case value_t::array:\n            {\n                assert(m_it.array_iterator != m_object->m_value.array->end());\n                return *m_it.array_iterator;\n            }\n\n            case value_t::null:\n                JSON_THROW(invalid_iterator::create(214, \"cannot get value\"));\n\n            default:\n            {\n                if (JSON_LIKELY(m_it.primitive_iterator.is_begin()))\n                {\n                    return *m_object;\n                }\n\n                JSON_THROW(invalid_iterator::create(214, \"cannot get value\"));\n            }\n        }\n    }\n\n    /*!\n    @brief dereference the iterator\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    pointer operator->() const\n    {\n        assert(m_object != nullptr);\n\n        switch (m_object->m_type)\n        {\n            case value_t::object:\n            {\n                assert(m_it.object_iterator != m_object->m_value.object->end());\n                return &(m_it.object_iterator->second);\n            }\n\n            case value_t::array:\n            {\n                assert(m_it.array_iterator != m_object->m_value.array->end());\n                return &*m_it.array_iterator;\n            }\n\n            default:\n            {\n                if (JSON_LIKELY(m_it.primitive_iterator.is_begin()))\n                {\n                    return m_object;\n                }\n\n                JSON_THROW(invalid_iterator::create(214, \"cannot get value\"));\n            }\n        }\n    }\n\n    /*!\n    @brief post-increment (it++)\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    iter_impl const operator++(int)\n    {\n        auto result = *this;\n        ++(*this);\n        return result;\n    }\n\n    /*!\n    @brief pre-increment (++it)\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    iter_impl& operator++()\n    {\n        assert(m_object != nullptr);\n\n        switch (m_object->m_type)\n        {\n            case value_t::object:\n            {\n                std::advance(m_it.object_iterator, 1);\n                break;\n            }\n\n            case value_t::array:\n            {\n                std::advance(m_it.array_iterator, 1);\n                break;\n            }\n\n            default:\n            {\n                ++m_it.primitive_iterator;\n                break;\n            }\n        }\n\n        return *this;\n    }\n\n    /*!\n    @brief post-decrement (it--)\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    iter_impl const operator--(int)\n    {\n        auto result = *this;\n        --(*this);\n        return result;\n    }\n\n    /*!\n    @brief pre-decrement (--it)\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    iter_impl& operator--()\n    {\n        assert(m_object != nullptr);\n\n        switch (m_object->m_type)\n        {\n            case value_t::object:\n            {\n                std::advance(m_it.object_iterator, -1);\n                break;\n            }\n\n            case value_t::array:\n            {\n                std::advance(m_it.array_iterator, -1);\n                break;\n            }\n\n            default:\n            {\n                --m_it.primitive_iterator;\n                break;\n            }\n        }\n\n        return *this;\n    }\n\n    /*!\n    @brief  comparison: equal\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    bool operator==(const iter_impl& other) const\n    {\n        // if objects are not the same, the comparison is undefined\n        if (JSON_UNLIKELY(m_object != other.m_object))\n        {\n            JSON_THROW(invalid_iterator::create(212, \"cannot compare iterators of different containers\"));\n        }\n\n        assert(m_object != nullptr);\n\n        switch (m_object->m_type)\n        {\n            case value_t::object:\n                return (m_it.object_iterator == other.m_it.object_iterator);\n\n            case value_t::array:\n                return (m_it.array_iterator == other.m_it.array_iterator);\n\n            default:\n                return (m_it.primitive_iterator == other.m_it.primitive_iterator);\n        }\n    }\n\n    /*!\n    @brief  comparison: not equal\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    bool operator!=(const iter_impl& other) const\n    {\n        return not operator==(other);\n    }\n\n    /*!\n    @brief  comparison: smaller\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    bool operator<(const iter_impl& other) const\n    {\n        // if objects are not the same, the comparison is undefined\n        if (JSON_UNLIKELY(m_object != other.m_object))\n        {\n            JSON_THROW(invalid_iterator::create(212, \"cannot compare iterators of different containers\"));\n        }\n\n        assert(m_object != nullptr);\n\n        switch (m_object->m_type)\n        {\n            case value_t::object:\n                JSON_THROW(invalid_iterator::create(213, \"cannot compare order of object iterators\"));\n\n            case value_t::array:\n                return (m_it.array_iterator < other.m_it.array_iterator);\n\n            default:\n                return (m_it.primitive_iterator < other.m_it.primitive_iterator);\n        }\n    }\n\n    /*!\n    @brief  comparison: less than or equal\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    bool operator<=(const iter_impl& other) const\n    {\n        return not other.operator < (*this);\n    }\n\n    /*!\n    @brief  comparison: greater than\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    bool operator>(const iter_impl& other) const\n    {\n        return not operator<=(other);\n    }\n\n    /*!\n    @brief  comparison: greater than or equal\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    bool operator>=(const iter_impl& other) const\n    {\n        return not operator<(other);\n    }\n\n    /*!\n    @brief  add to iterator\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    iter_impl& operator+=(difference_type i)\n    {\n        assert(m_object != nullptr);\n\n        switch (m_object->m_type)\n        {\n            case value_t::object:\n                JSON_THROW(invalid_iterator::create(209, \"cannot use offsets with object iterators\"));\n\n            case value_t::array:\n            {\n                std::advance(m_it.array_iterator, i);\n                break;\n            }\n\n            default:\n            {\n                m_it.primitive_iterator += i;\n                break;\n            }\n        }\n\n        return *this;\n    }\n\n    /*!\n    @brief  subtract from iterator\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    iter_impl& operator-=(difference_type i)\n    {\n        return operator+=(-i);\n    }\n\n    /*!\n    @brief  add to iterator\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    iter_impl operator+(difference_type i) const\n    {\n        auto result = *this;\n        result += i;\n        return result;\n    }\n\n    /*!\n    @brief  addition of distance and iterator\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    friend iter_impl operator+(difference_type i, const iter_impl& it)\n    {\n        auto result = it;\n        result += i;\n        return result;\n    }\n\n    /*!\n    @brief  subtract from iterator\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    iter_impl operator-(difference_type i) const\n    {\n        auto result = *this;\n        result -= i;\n        return result;\n    }\n\n    /*!\n    @brief  return difference\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    difference_type operator-(const iter_impl& other) const\n    {\n        assert(m_object != nullptr);\n\n        switch (m_object->m_type)\n        {\n            case value_t::object:\n                JSON_THROW(invalid_iterator::create(209, \"cannot use offsets with object iterators\"));\n\n            case value_t::array:\n                return m_it.array_iterator - other.m_it.array_iterator;\n\n            default:\n                return m_it.primitive_iterator - other.m_it.primitive_iterator;\n        }\n    }\n\n    /*!\n    @brief  access to successor\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    reference operator[](difference_type n) const\n    {\n        assert(m_object != nullptr);\n\n        switch (m_object->m_type)\n        {\n            case value_t::object:\n                JSON_THROW(invalid_iterator::create(208, \"cannot use operator[] for object iterators\"));\n\n            case value_t::array:\n                return *std::next(m_it.array_iterator, n);\n\n            case value_t::null:\n                JSON_THROW(invalid_iterator::create(214, \"cannot get value\"));\n\n            default:\n            {\n                if (JSON_LIKELY(m_it.primitive_iterator.get_value() == -n))\n                {\n                    return *m_object;\n                }\n\n                JSON_THROW(invalid_iterator::create(214, \"cannot get value\"));\n            }\n        }\n    }\n\n    /*!\n    @brief  return the key of an object iterator\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    const typename object_t::key_type& key() const\n    {\n        assert(m_object != nullptr);\n\n        if (JSON_LIKELY(m_object->is_object()))\n        {\n            return m_it.object_iterator->first;\n        }\n\n        JSON_THROW(invalid_iterator::create(207, \"cannot use key() for non-object iterators\"));\n    }\n\n    /*!\n    @brief  return the value of an iterator\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    reference value() const\n    {\n        return operator*();\n    }\n\n  private:\n    /// associated JSON instance\n    pointer m_object = nullptr;\n    /// the actual iterator of the associated instance\n    internal_iterator<typename std::remove_const<BasicJsonType>::type> m_it;\n};\n}  // namespace detail\n} // namespace nlohmann\n// #include <nlohmann/detail/iterators/iteration_proxy.hpp>\n\n// #include <nlohmann/detail/iterators/json_reverse_iterator.hpp>\n\n\n#include <cstddef> // ptrdiff_t\n#include <iterator> // reverse_iterator\n#include <utility> // declval\n\nnamespace nlohmann\n{\nnamespace detail\n{\n//////////////////////\n// reverse_iterator //\n//////////////////////\n\n/*!\n@brief a template for a reverse iterator class\n\n@tparam Base the base iterator type to reverse. Valid types are @ref\niterator (to create @ref reverse_iterator) and @ref const_iterator (to\ncreate @ref const_reverse_iterator).\n\n@requirement The class satisfies the following concept requirements:\n-\n[BidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator):\n  The iterator that can be moved can be moved in both directions (i.e.\n  incremented and decremented).\n- [OutputIterator](https://en.cppreference.com/w/cpp/named_req/OutputIterator):\n  It is possible to write to the pointed-to element (only if @a Base is\n  @ref iterator).\n\n@since version 1.0.0\n*/\ntemplate<typename Base>\nclass json_reverse_iterator : public std::reverse_iterator<Base>\n{\n  public:\n    using difference_type = std::ptrdiff_t;\n    /// shortcut to the reverse iterator adapter\n    using base_iterator = std::reverse_iterator<Base>;\n    /// the reference type for the pointed-to element\n    using reference = typename Base::reference;\n\n    /// create reverse iterator from iterator\n    explicit json_reverse_iterator(const typename base_iterator::iterator_type& it) noexcept\n        : base_iterator(it) {}\n\n    /// create reverse iterator from base class\n    explicit json_reverse_iterator(const base_iterator& it) noexcept : base_iterator(it) {}\n\n    /// post-increment (it++)\n    json_reverse_iterator const operator++(int)\n    {\n        return static_cast<json_reverse_iterator>(base_iterator::operator++(1));\n    }\n\n    /// pre-increment (++it)\n    json_reverse_iterator& operator++()\n    {\n        return static_cast<json_reverse_iterator&>(base_iterator::operator++());\n    }\n\n    /// post-decrement (it--)\n    json_reverse_iterator const operator--(int)\n    {\n        return static_cast<json_reverse_iterator>(base_iterator::operator--(1));\n    }\n\n    /// pre-decrement (--it)\n    json_reverse_iterator& operator--()\n    {\n        return static_cast<json_reverse_iterator&>(base_iterator::operator--());\n    }\n\n    /// add to iterator\n    json_reverse_iterator& operator+=(difference_type i)\n    {\n        return static_cast<json_reverse_iterator&>(base_iterator::operator+=(i));\n    }\n\n    /// add to iterator\n    json_reverse_iterator operator+(difference_type i) const\n    {\n        return static_cast<json_reverse_iterator>(base_iterator::operator+(i));\n    }\n\n    /// subtract from iterator\n    json_reverse_iterator operator-(difference_type i) const\n    {\n        return static_cast<json_reverse_iterator>(base_iterator::operator-(i));\n    }\n\n    /// return difference\n    difference_type operator-(const json_reverse_iterator& other) const\n    {\n        return base_iterator(*this) - base_iterator(other);\n    }\n\n    /// access to successor\n    reference operator[](difference_type n) const\n    {\n        return *(this->operator+(n));\n    }\n\n    /// return the key of an object iterator\n    auto key() const -> decltype(std::declval<Base>().key())\n    {\n        auto it = --this->base();\n        return it.key();\n    }\n\n    /// return the value of an iterator\n    reference value() const\n    {\n        auto it = --this->base();\n        return it.operator * ();\n    }\n};\n}  // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/output/output_adapters.hpp>\n\n\n#include <algorithm> // copy\n#include <cstddef> // size_t\n#include <ios> // streamsize\n#include <iterator> // back_inserter\n#include <memory> // shared_ptr, make_shared\n#include <ostream> // basic_ostream\n#include <string> // basic_string\n#include <vector> // vector\n\nnamespace nlohmann\n{\nnamespace detail\n{\n/// abstract output adapter interface\ntemplate<typename CharType> struct output_adapter_protocol\n{\n    virtual void write_character(CharType c) = 0;\n    virtual void write_characters(const CharType* s, std::size_t length) = 0;\n    virtual ~output_adapter_protocol() = default;\n};\n\n/// a type to simplify interfaces\ntemplate<typename CharType>\nusing output_adapter_t = std::shared_ptr<output_adapter_protocol<CharType>>;\n\n/// output adapter for byte vectors\ntemplate<typename CharType>\nclass output_vector_adapter : public output_adapter_protocol<CharType>\n{\n  public:\n    explicit output_vector_adapter(std::vector<CharType>& vec) noexcept\n        : v(vec)\n    {}\n\n    void write_character(CharType c) override\n    {\n        v.push_back(c);\n    }\n\n    void write_characters(const CharType* s, std::size_t length) override\n    {\n        std::copy(s, s + length, std::back_inserter(v));\n    }\n\n  private:\n    std::vector<CharType>& v;\n};\n\n/// output adapter for output streams\ntemplate<typename CharType>\nclass output_stream_adapter : public output_adapter_protocol<CharType>\n{\n  public:\n    explicit output_stream_adapter(std::basic_ostream<CharType>& s) noexcept\n        : stream(s)\n    {}\n\n    void write_character(CharType c) override\n    {\n        stream.put(c);\n    }\n\n    void write_characters(const CharType* s, std::size_t length) override\n    {\n        stream.write(s, static_cast<std::streamsize>(length));\n    }\n\n  private:\n    std::basic_ostream<CharType>& stream;\n};\n\n/// output adapter for basic_string\ntemplate<typename CharType, typename StringType = std::basic_string<CharType>>\nclass output_string_adapter : public output_adapter_protocol<CharType>\n{\n  public:\n    explicit output_string_adapter(StringType& s) noexcept\n        : str(s)\n    {}\n\n    void write_character(CharType c) override\n    {\n        str.push_back(c);\n    }\n\n    void write_characters(const CharType* s, std::size_t length) override\n    {\n        str.append(s, length);\n    }\n\n  private:\n    StringType& str;\n};\n\ntemplate<typename CharType, typename StringType = std::basic_string<CharType>>\nclass output_adapter\n{\n  public:\n    output_adapter(std::vector<CharType>& vec)\n        : oa(std::make_shared<output_vector_adapter<CharType>>(vec)) {}\n\n    output_adapter(std::basic_ostream<CharType>& s)\n        : oa(std::make_shared<output_stream_adapter<CharType>>(s)) {}\n\n    output_adapter(StringType& s)\n        : oa(std::make_shared<output_string_adapter<CharType, StringType>>(s)) {}\n\n    operator output_adapter_t<CharType>()\n    {\n        return oa;\n    }\n\n  private:\n    output_adapter_t<CharType> oa = nullptr;\n};\n}  // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/input/binary_reader.hpp>\n\n\n#include <algorithm> // generate_n\n#include <array> // array\n#include <cassert> // assert\n#include <cmath> // ldexp\n#include <cstddef> // size_t\n#include <cstdint> // uint8_t, uint16_t, uint32_t, uint64_t\n#include <cstdio> // snprintf\n#include <cstring> // memcpy\n#include <iterator> // back_inserter\n#include <limits> // numeric_limits\n#include <string> // char_traits, string\n#include <utility> // make_pair, move\n\n// #include <nlohmann/detail/input/input_adapters.hpp>\n\n// #include <nlohmann/detail/input/json_sax.hpp>\n\n// #include <nlohmann/detail/exceptions.hpp>\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n// #include <nlohmann/detail/meta/is_sax.hpp>\n\n// #include <nlohmann/detail/value_t.hpp>\n\n\nnamespace nlohmann\n{\nnamespace detail\n{\n///////////////////\n// binary reader //\n///////////////////\n\n/*!\n@brief deserialization of CBOR, MessagePack, and UBJSON values\n*/\ntemplate<typename BasicJsonType, typename SAX = json_sax_dom_parser<BasicJsonType>>\nclass binary_reader\n{\n    using number_integer_t = typename BasicJsonType::number_integer_t;\n    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n    using number_float_t = typename BasicJsonType::number_float_t;\n    using string_t = typename BasicJsonType::string_t;\n    using json_sax_t = SAX;\n\n  public:\n    /*!\n    @brief create a binary reader\n\n    @param[in] adapter  input adapter to read from\n    */\n    explicit binary_reader(input_adapter_t adapter) : ia(std::move(adapter))\n    {\n        (void)detail::is_sax_static_asserts<SAX, BasicJsonType> {};\n        assert(ia);\n    }\n\n    /*!\n    @param[in] format  the binary format to parse\n    @param[in] sax_    a SAX event processor\n    @param[in] strict  whether to expect the input to be consumed completed\n\n    @return\n    */\n    bool sax_parse(const input_format_t format,\n                   json_sax_t* sax_,\n                   const bool strict = true)\n    {\n        sax = sax_;\n        bool result = false;\n\n        switch (format)\n        {\n            case input_format_t::bson:\n                result = parse_bson_internal();\n                break;\n\n            case input_format_t::cbor:\n                result = parse_cbor_internal();\n                break;\n\n            case input_format_t::msgpack:\n                result = parse_msgpack_internal();\n                break;\n\n            case input_format_t::ubjson:\n                result = parse_ubjson_internal();\n                break;\n\n            // LCOV_EXCL_START\n            default:\n                assert(false);\n                // LCOV_EXCL_STOP\n        }\n\n        // strict mode: next byte must be EOF\n        if (result and strict)\n        {\n            if (format == input_format_t::ubjson)\n            {\n                get_ignore_noop();\n            }\n            else\n            {\n                get();\n            }\n\n            if (JSON_UNLIKELY(current != std::char_traits<char>::eof()))\n            {\n                return sax->parse_error(chars_read, get_token_string(),\n                                        parse_error::create(110, chars_read, exception_message(format, \"expected end of input; last byte: 0x\" + get_token_string(), \"value\")));\n            }\n        }\n\n        return result;\n    }\n\n    /*!\n    @brief determine system byte order\n\n    @return true if and only if system's byte order is little endian\n\n    @note from http://stackoverflow.com/a/1001328/266378\n    */\n    static constexpr bool little_endianess(int num = 1) noexcept\n    {\n        return (*reinterpret_cast<char*>(&num) == 1);\n    }\n\n  private:\n    //////////\n    // BSON //\n    //////////\n\n    /*!\n    @brief Reads in a BSON-object and passes it to the SAX-parser.\n    @return whether a valid BSON-value was passed to the SAX parser\n    */\n    bool parse_bson_internal()\n    {\n        std::int32_t document_size;\n        get_number<std::int32_t, true>(input_format_t::bson, document_size);\n\n        if (JSON_UNLIKELY(not sax->start_object(std::size_t(-1))))\n        {\n            return false;\n        }\n\n        if (JSON_UNLIKELY(not parse_bson_element_list(/*is_array*/false)))\n        {\n            return false;\n        }\n\n        return sax->end_object();\n    }\n\n    /*!\n    @brief Parses a C-style string from the BSON input.\n    @param[in, out] result  A reference to the string variable where the read\n                            string is to be stored.\n    @return `true` if the \\x00-byte indicating the end of the string was\n             encountered before the EOF; false` indicates an unexpected EOF.\n    */\n    bool get_bson_cstr(string_t& result)\n    {\n        auto out = std::back_inserter(result);\n        while (true)\n        {\n            get();\n            if (JSON_UNLIKELY(not unexpect_eof(input_format_t::bson, \"cstring\")))\n            {\n                return false;\n            }\n            if (current == 0x00)\n            {\n                return true;\n            }\n            *out++ = static_cast<char>(current);\n        }\n\n        return true;\n    }\n\n    /*!\n    @brief Parses a zero-terminated string of length @a len from the BSON\n           input.\n    @param[in] len  The length (including the zero-byte at the end) of the\n                    string to be read.\n    @param[in, out] result  A reference to the string variable where the read\n                            string is to be stored.\n    @tparam NumberType The type of the length @a len\n    @pre len >= 1\n    @return `true` if the string was successfully parsed\n    */\n    template<typename NumberType>\n    bool get_bson_string(const NumberType len, string_t& result)\n    {\n        if (JSON_UNLIKELY(len < 1))\n        {\n            auto last_token = get_token_string();\n            return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::bson, \"string length must be at least 1, is \" + std::to_string(len), \"string\")));\n        }\n\n        return get_string(input_format_t::bson, len - static_cast<NumberType>(1), result) and get() != std::char_traits<char>::eof();\n    }\n\n    /*!\n    @brief Read a BSON document element of the given @a element_type.\n    @param[in] element_type The BSON element type, c.f. http://bsonspec.org/spec.html\n    @param[in] element_type_parse_position The position in the input stream,\n               where the `element_type` was read.\n    @warning Not all BSON element types are supported yet. An unsupported\n             @a element_type will give rise to a parse_error.114:\n             Unsupported BSON record type 0x...\n    @return whether a valid BSON-object/array was passed to the SAX parser\n    */\n    bool parse_bson_element_internal(const int element_type,\n                                     const std::size_t element_type_parse_position)\n    {\n        switch (element_type)\n        {\n            case 0x01: // double\n            {\n                double number;\n                return get_number<double, true>(input_format_t::bson, number) and sax->number_float(static_cast<number_float_t>(number), \"\");\n            }\n\n            case 0x02: // string\n            {\n                std::int32_t len;\n                string_t value;\n                return get_number<std::int32_t, true>(input_format_t::bson, len) and get_bson_string(len, value) and sax->string(value);\n            }\n\n            case 0x03: // object\n            {\n                return parse_bson_internal();\n            }\n\n            case 0x04: // array\n            {\n                return parse_bson_array();\n            }\n\n            case 0x08: // boolean\n            {\n                return sax->boolean(get() != 0);\n            }\n\n            case 0x0A: // null\n            {\n                return sax->null();\n            }\n\n            case 0x10: // int32\n            {\n                std::int32_t value;\n                return get_number<std::int32_t, true>(input_format_t::bson, value) and sax->number_integer(value);\n            }\n\n            case 0x12: // int64\n            {\n                std::int64_t value;\n                return get_number<std::int64_t, true>(input_format_t::bson, value) and sax->number_integer(value);\n            }\n\n            default: // anything else not supported (yet)\n            {\n                char cr[3];\n                (std::snprintf)(cr, sizeof(cr), \"%.2hhX\", static_cast<unsigned char>(element_type));\n                return sax->parse_error(element_type_parse_position, std::string(cr), parse_error::create(114, element_type_parse_position, \"Unsupported BSON record type 0x\" + std::string(cr)));\n            }\n        }\n    }\n\n    /*!\n    @brief Read a BSON element list (as specified in the BSON-spec)\n\n    The same binary layout is used for objects and arrays, hence it must be\n    indicated with the argument @a is_array which one is expected\n    (true --> array, false --> object).\n\n    @param[in] is_array Determines if the element list being read is to be\n                        treated as an object (@a is_array == false), or as an\n                        array (@a is_array == true).\n    @return whether a valid BSON-object/array was passed to the SAX parser\n    */\n    bool parse_bson_element_list(const bool is_array)\n    {\n        string_t key;\n        while (int element_type = get())\n        {\n            if (JSON_UNLIKELY(not unexpect_eof(input_format_t::bson, \"element list\")))\n            {\n                return false;\n            }\n\n            const std::size_t element_type_parse_position = chars_read;\n            if (JSON_UNLIKELY(not get_bson_cstr(key)))\n            {\n                return false;\n            }\n\n            if (not is_array)\n            {\n                if (not sax->key(key))\n                {\n                    return false;\n                }\n            }\n\n            if (JSON_UNLIKELY(not parse_bson_element_internal(element_type, element_type_parse_position)))\n            {\n                return false;\n            }\n\n            // get_bson_cstr only appends\n            key.clear();\n        }\n\n        return true;\n    }\n\n    /*!\n    @brief Reads an array from the BSON input and passes it to the SAX-parser.\n    @return whether a valid BSON-array was passed to the SAX parser\n    */\n    bool parse_bson_array()\n    {\n        std::int32_t document_size;\n        get_number<std::int32_t, true>(input_format_t::bson, document_size);\n\n        if (JSON_UNLIKELY(not sax->start_array(std::size_t(-1))))\n        {\n            return false;\n        }\n\n        if (JSON_UNLIKELY(not parse_bson_element_list(/*is_array*/true)))\n        {\n            return false;\n        }\n\n        return sax->end_array();\n    }\n\n    //////////\n    // CBOR //\n    //////////\n\n    /*!\n    @param[in] get_char  whether a new character should be retrieved from the\n                         input (true, default) or whether the last read\n                         character should be considered instead\n\n    @return whether a valid CBOR value was passed to the SAX parser\n    */\n    bool parse_cbor_internal(const bool get_char = true)\n    {\n        switch (get_char ? get() : current)\n        {\n            // EOF\n            case std::char_traits<char>::eof():\n                return unexpect_eof(input_format_t::cbor, \"value\");\n\n            // Integer 0x00..0x17 (0..23)\n            case 0x00:\n            case 0x01:\n            case 0x02:\n            case 0x03:\n            case 0x04:\n            case 0x05:\n            case 0x06:\n            case 0x07:\n            case 0x08:\n            case 0x09:\n            case 0x0A:\n            case 0x0B:\n            case 0x0C:\n            case 0x0D:\n            case 0x0E:\n            case 0x0F:\n            case 0x10:\n            case 0x11:\n            case 0x12:\n            case 0x13:\n            case 0x14:\n            case 0x15:\n            case 0x16:\n            case 0x17:\n                return sax->number_unsigned(static_cast<number_unsigned_t>(current));\n\n            case 0x18: // Unsigned integer (one-byte uint8_t follows)\n            {\n                uint8_t number;\n                return get_number(input_format_t::cbor, number) and sax->number_unsigned(number);\n            }\n\n            case 0x19: // Unsigned integer (two-byte uint16_t follows)\n            {\n                uint16_t number;\n                return get_number(input_format_t::cbor, number) and sax->number_unsigned(number);\n            }\n\n            case 0x1A: // Unsigned integer (four-byte uint32_t follows)\n            {\n                uint32_t number;\n                return get_number(input_format_t::cbor, number) and sax->number_unsigned(number);\n            }\n\n            case 0x1B: // Unsigned integer (eight-byte uint64_t follows)\n            {\n                uint64_t number;\n                return get_number(input_format_t::cbor, number) and sax->number_unsigned(number);\n            }\n\n            // Negative integer -1-0x00..-1-0x17 (-1..-24)\n            case 0x20:\n            case 0x21:\n            case 0x22:\n            case 0x23:\n            case 0x24:\n            case 0x25:\n            case 0x26:\n            case 0x27:\n            case 0x28:\n            case 0x29:\n            case 0x2A:\n            case 0x2B:\n            case 0x2C:\n            case 0x2D:\n            case 0x2E:\n            case 0x2F:\n            case 0x30:\n            case 0x31:\n            case 0x32:\n            case 0x33:\n            case 0x34:\n            case 0x35:\n            case 0x36:\n            case 0x37:\n                return sax->number_integer(static_cast<int8_t>(0x20 - 1 - current));\n\n            case 0x38: // Negative integer (one-byte uint8_t follows)\n            {\n                uint8_t number;\n                return get_number(input_format_t::cbor, number) and sax->number_integer(static_cast<number_integer_t>(-1) - number);\n            }\n\n            case 0x39: // Negative integer -1-n (two-byte uint16_t follows)\n            {\n                uint16_t number;\n                return get_number(input_format_t::cbor, number) and sax->number_integer(static_cast<number_integer_t>(-1) - number);\n            }\n\n            case 0x3A: // Negative integer -1-n (four-byte uint32_t follows)\n            {\n                uint32_t number;\n                return get_number(input_format_t::cbor, number) and sax->number_integer(static_cast<number_integer_t>(-1) - number);\n            }\n\n            case 0x3B: // Negative integer -1-n (eight-byte uint64_t follows)\n            {\n                uint64_t number;\n                return get_number(input_format_t::cbor, number) and sax->number_integer(static_cast<number_integer_t>(-1)\n                        - static_cast<number_integer_t>(number));\n            }\n\n            // UTF-8 string (0x00..0x17 bytes follow)\n            case 0x60:\n            case 0x61:\n            case 0x62:\n            case 0x63:\n            case 0x64:\n            case 0x65:\n            case 0x66:\n            case 0x67:\n            case 0x68:\n            case 0x69:\n            case 0x6A:\n            case 0x6B:\n            case 0x6C:\n            case 0x6D:\n            case 0x6E:\n            case 0x6F:\n            case 0x70:\n            case 0x71:\n            case 0x72:\n            case 0x73:\n            case 0x74:\n            case 0x75:\n            case 0x76:\n            case 0x77:\n            case 0x78: // UTF-8 string (one-byte uint8_t for n follows)\n            case 0x79: // UTF-8 string (two-byte uint16_t for n follow)\n            case 0x7A: // UTF-8 string (four-byte uint32_t for n follow)\n            case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow)\n            case 0x7F: // UTF-8 string (indefinite length)\n            {\n                string_t s;\n                return get_cbor_string(s) and sax->string(s);\n            }\n\n            // array (0x00..0x17 data items follow)\n            case 0x80:\n            case 0x81:\n            case 0x82:\n            case 0x83:\n            case 0x84:\n            case 0x85:\n            case 0x86:\n            case 0x87:\n            case 0x88:\n            case 0x89:\n            case 0x8A:\n            case 0x8B:\n            case 0x8C:\n            case 0x8D:\n            case 0x8E:\n            case 0x8F:\n            case 0x90:\n            case 0x91:\n            case 0x92:\n            case 0x93:\n            case 0x94:\n            case 0x95:\n            case 0x96:\n            case 0x97:\n                return get_cbor_array(static_cast<std::size_t>(current & 0x1F));\n\n            case 0x98: // array (one-byte uint8_t for n follows)\n            {\n                uint8_t len;\n                return get_number(input_format_t::cbor, len) and get_cbor_array(static_cast<std::size_t>(len));\n            }\n\n            case 0x99: // array (two-byte uint16_t for n follow)\n            {\n                uint16_t len;\n                return get_number(input_format_t::cbor, len) and get_cbor_array(static_cast<std::size_t>(len));\n            }\n\n            case 0x9A: // array (four-byte uint32_t for n follow)\n            {\n                uint32_t len;\n                return get_number(input_format_t::cbor, len) and get_cbor_array(static_cast<std::size_t>(len));\n            }\n\n            case 0x9B: // array (eight-byte uint64_t for n follow)\n            {\n                uint64_t len;\n                return get_number(input_format_t::cbor, len) and get_cbor_array(static_cast<std::size_t>(len));\n            }\n\n            case 0x9F: // array (indefinite length)\n                return get_cbor_array(std::size_t(-1));\n\n            // map (0x00..0x17 pairs of data items follow)\n            case 0xA0:\n            case 0xA1:\n            case 0xA2:\n            case 0xA3:\n            case 0xA4:\n            case 0xA5:\n            case 0xA6:\n            case 0xA7:\n            case 0xA8:\n            case 0xA9:\n            case 0xAA:\n            case 0xAB:\n            case 0xAC:\n            case 0xAD:\n            case 0xAE:\n            case 0xAF:\n            case 0xB0:\n            case 0xB1:\n            case 0xB2:\n            case 0xB3:\n            case 0xB4:\n            case 0xB5:\n            case 0xB6:\n            case 0xB7:\n                return get_cbor_object(static_cast<std::size_t>(current & 0x1F));\n\n            case 0xB8: // map (one-byte uint8_t for n follows)\n            {\n                uint8_t len;\n                return get_number(input_format_t::cbor, len) and get_cbor_object(static_cast<std::size_t>(len));\n            }\n\n            case 0xB9: // map (two-byte uint16_t for n follow)\n            {\n                uint16_t len;\n                return get_number(input_format_t::cbor, len) and get_cbor_object(static_cast<std::size_t>(len));\n            }\n\n            case 0xBA: // map (four-byte uint32_t for n follow)\n            {\n                uint32_t len;\n                return get_number(input_format_t::cbor, len) and get_cbor_object(static_cast<std::size_t>(len));\n            }\n\n            case 0xBB: // map (eight-byte uint64_t for n follow)\n            {\n                uint64_t len;\n                return get_number(input_format_t::cbor, len) and get_cbor_object(static_cast<std::size_t>(len));\n            }\n\n            case 0xBF: // map (indefinite length)\n                return get_cbor_object(std::size_t(-1));\n\n            case 0xF4: // false\n                return sax->boolean(false);\n\n            case 0xF5: // true\n                return sax->boolean(true);\n\n            case 0xF6: // null\n                return sax->null();\n\n            case 0xF9: // Half-Precision Float (two-byte IEEE 754)\n            {\n                const int byte1_raw = get();\n                if (JSON_UNLIKELY(not unexpect_eof(input_format_t::cbor, \"number\")))\n                {\n                    return false;\n                }\n                const int byte2_raw = get();\n                if (JSON_UNLIKELY(not unexpect_eof(input_format_t::cbor, \"number\")))\n                {\n                    return false;\n                }\n\n                const auto byte1 = static_cast<unsigned char>(byte1_raw);\n                const auto byte2 = static_cast<unsigned char>(byte2_raw);\n\n                // code from RFC 7049, Appendix D, Figure 3:\n                // As half-precision floating-point numbers were only added\n                // to IEEE 754 in 2008, today's programming platforms often\n                // still only have limited support for them. It is very\n                // easy to include at least decoding support for them even\n                // without such support. An example of a small decoder for\n                // half-precision floating-point numbers in the C language\n                // is shown in Fig. 3.\n                const int half = (byte1 << 8) + byte2;\n                const double val = [&half]\n                {\n                    const int exp = (half >> 10) & 0x1F;\n                    const int mant = half & 0x3FF;\n                    assert(0 <= exp and exp <= 32);\n                    assert(0 <= mant and mant <= 1024);\n                    switch (exp)\n                    {\n                        case 0:\n                            return std::ldexp(mant, -24);\n                        case 31:\n                            return (mant == 0)\n                            ? std::numeric_limits<double>::infinity()\n                            : std::numeric_limits<double>::quiet_NaN();\n                        default:\n                            return std::ldexp(mant + 1024, exp - 25);\n                    }\n                }();\n                return sax->number_float((half & 0x8000) != 0\n                                         ? static_cast<number_float_t>(-val)\n                                         : static_cast<number_float_t>(val), \"\");\n            }\n\n            case 0xFA: // Single-Precision Float (four-byte IEEE 754)\n            {\n                float number;\n                return get_number(input_format_t::cbor, number) and sax->number_float(static_cast<number_float_t>(number), \"\");\n            }\n\n            case 0xFB: // Double-Precision Float (eight-byte IEEE 754)\n            {\n                double number;\n                return get_number(input_format_t::cbor, number) and sax->number_float(static_cast<number_float_t>(number), \"\");\n            }\n\n            default: // anything else (0xFF is handled inside the other types)\n            {\n                auto last_token = get_token_string();\n                return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::cbor, \"invalid byte: 0x\" + last_token, \"value\")));\n            }\n        }\n    }\n\n    /*!\n    @brief reads a CBOR string\n\n    This function first reads starting bytes to determine the expected\n    string length and then copies this number of bytes into a string.\n    Additionally, CBOR's strings with indefinite lengths are supported.\n\n    @param[out] result  created string\n\n    @return whether string creation completed\n    */\n    bool get_cbor_string(string_t& result)\n    {\n        if (JSON_UNLIKELY(not unexpect_eof(input_format_t::cbor, \"string\")))\n        {\n            return false;\n        }\n\n        switch (current)\n        {\n            // UTF-8 string (0x00..0x17 bytes follow)\n            case 0x60:\n            case 0x61:\n            case 0x62:\n            case 0x63:\n            case 0x64:\n            case 0x65:\n            case 0x66:\n            case 0x67:\n            case 0x68:\n            case 0x69:\n            case 0x6A:\n            case 0x6B:\n            case 0x6C:\n            case 0x6D:\n            case 0x6E:\n            case 0x6F:\n            case 0x70:\n            case 0x71:\n            case 0x72:\n            case 0x73:\n            case 0x74:\n            case 0x75:\n            case 0x76:\n            case 0x77:\n            {\n                return get_string(input_format_t::cbor, current & 0x1F, result);\n            }\n\n            case 0x78: // UTF-8 string (one-byte uint8_t for n follows)\n            {\n                uint8_t len;\n                return get_number(input_format_t::cbor, len) and get_string(input_format_t::cbor, len, result);\n            }\n\n            case 0x79: // UTF-8 string (two-byte uint16_t for n follow)\n            {\n                uint16_t len;\n                return get_number(input_format_t::cbor, len) and get_string(input_format_t::cbor, len, result);\n            }\n\n            case 0x7A: // UTF-8 string (four-byte uint32_t for n follow)\n            {\n                uint32_t len;\n                return get_number(input_format_t::cbor, len) and get_string(input_format_t::cbor, len, result);\n            }\n\n            case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow)\n            {\n                uint64_t len;\n                return get_number(input_format_t::cbor, len) and get_string(input_format_t::cbor, len, result);\n            }\n\n            case 0x7F: // UTF-8 string (indefinite length)\n            {\n                while (get() != 0xFF)\n                {\n                    string_t chunk;\n                    if (not get_cbor_string(chunk))\n                    {\n                        return false;\n                    }\n                    result.append(chunk);\n                }\n                return true;\n            }\n\n            default:\n            {\n                auto last_token = get_token_string();\n                return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::cbor, \"expected length specification (0x60-0x7B) or indefinite string type (0x7F); last byte: 0x\" + last_token, \"string\")));\n            }\n        }\n    }\n\n    /*!\n    @param[in] len  the length of the array or std::size_t(-1) for an\n                    array of indefinite size\n    @return whether array creation completed\n    */\n    bool get_cbor_array(const std::size_t len)\n    {\n        if (JSON_UNLIKELY(not sax->start_array(len)))\n        {\n            return false;\n        }\n\n        if (len != std::size_t(-1))\n        {\n            for (std::size_t i = 0; i < len; ++i)\n            {\n                if (JSON_UNLIKELY(not parse_cbor_internal()))\n                {\n                    return false;\n                }\n            }\n        }\n        else\n        {\n            while (get() != 0xFF)\n            {\n                if (JSON_UNLIKELY(not parse_cbor_internal(false)))\n                {\n                    return false;\n                }\n            }\n        }\n\n        return sax->end_array();\n    }\n\n    /*!\n    @param[in] len  the length of the object or std::size_t(-1) for an\n                    object of indefinite size\n    @return whether object creation completed\n    */\n    bool get_cbor_object(const std::size_t len)\n    {\n        if (not JSON_UNLIKELY(sax->start_object(len)))\n        {\n            return false;\n        }\n\n        string_t key;\n        if (len != std::size_t(-1))\n        {\n            for (std::size_t i = 0; i < len; ++i)\n            {\n                get();\n                if (JSON_UNLIKELY(not get_cbor_string(key) or not sax->key(key)))\n                {\n                    return false;\n                }\n\n                if (JSON_UNLIKELY(not parse_cbor_internal()))\n                {\n                    return false;\n                }\n                key.clear();\n            }\n        }\n        else\n        {\n            while (get() != 0xFF)\n            {\n                if (JSON_UNLIKELY(not get_cbor_string(key) or not sax->key(key)))\n                {\n                    return false;\n                }\n\n                if (JSON_UNLIKELY(not parse_cbor_internal()))\n                {\n                    return false;\n                }\n                key.clear();\n            }\n        }\n\n        return sax->end_object();\n    }\n\n    /////////////\n    // MsgPack //\n    /////////////\n\n    /*!\n    @return whether a valid MessagePack value was passed to the SAX parser\n    */\n    bool parse_msgpack_internal()\n    {\n        switch (get())\n        {\n            // EOF\n            case std::char_traits<char>::eof():\n                return unexpect_eof(input_format_t::msgpack, \"value\");\n\n            // positive fixint\n            case 0x00:\n            case 0x01:\n            case 0x02:\n            case 0x03:\n            case 0x04:\n            case 0x05:\n            case 0x06:\n            case 0x07:\n            case 0x08:\n            case 0x09:\n            case 0x0A:\n            case 0x0B:\n            case 0x0C:\n            case 0x0D:\n            case 0x0E:\n            case 0x0F:\n            case 0x10:\n            case 0x11:\n            case 0x12:\n            case 0x13:\n            case 0x14:\n            case 0x15:\n            case 0x16:\n            case 0x17:\n            case 0x18:\n            case 0x19:\n            case 0x1A:\n            case 0x1B:\n            case 0x1C:\n            case 0x1D:\n            case 0x1E:\n            case 0x1F:\n            case 0x20:\n            case 0x21:\n            case 0x22:\n            case 0x23:\n            case 0x24:\n            case 0x25:\n            case 0x26:\n            case 0x27:\n            case 0x28:\n            case 0x29:\n            case 0x2A:\n            case 0x2B:\n            case 0x2C:\n            case 0x2D:\n            case 0x2E:\n            case 0x2F:\n            case 0x30:\n            case 0x31:\n            case 0x32:\n            case 0x33:\n            case 0x34:\n            case 0x35:\n            case 0x36:\n            case 0x37:\n            case 0x38:\n            case 0x39:\n            case 0x3A:\n            case 0x3B:\n            case 0x3C:\n            case 0x3D:\n            case 0x3E:\n            case 0x3F:\n            case 0x40:\n            case 0x41:\n            case 0x42:\n            case 0x43:\n            case 0x44:\n            case 0x45:\n            case 0x46:\n            case 0x47:\n            case 0x48:\n            case 0x49:\n            case 0x4A:\n            case 0x4B:\n            case 0x4C:\n            case 0x4D:\n            case 0x4E:\n            case 0x4F:\n            case 0x50:\n            case 0x51:\n            case 0x52:\n            case 0x53:\n            case 0x54:\n            case 0x55:\n            case 0x56:\n            case 0x57:\n            case 0x58:\n            case 0x59:\n            case 0x5A:\n            case 0x5B:\n            case 0x5C:\n            case 0x5D:\n            case 0x5E:\n            case 0x5F:\n            case 0x60:\n            case 0x61:\n            case 0x62:\n            case 0x63:\n            case 0x64:\n            case 0x65:\n            case 0x66:\n            case 0x67:\n            case 0x68:\n            case 0x69:\n            case 0x6A:\n            case 0x6B:\n            case 0x6C:\n            case 0x6D:\n            case 0x6E:\n            case 0x6F:\n            case 0x70:\n            case 0x71:\n            case 0x72:\n            case 0x73:\n            case 0x74:\n            case 0x75:\n            case 0x76:\n            case 0x77:\n            case 0x78:\n            case 0x79:\n            case 0x7A:\n            case 0x7B:\n            case 0x7C:\n            case 0x7D:\n            case 0x7E:\n            case 0x7F:\n                return sax->number_unsigned(static_cast<number_unsigned_t>(current));\n\n            // fixmap\n            case 0x80:\n            case 0x81:\n            case 0x82:\n            case 0x83:\n            case 0x84:\n            case 0x85:\n            case 0x86:\n            case 0x87:\n            case 0x88:\n            case 0x89:\n            case 0x8A:\n            case 0x8B:\n            case 0x8C:\n            case 0x8D:\n            case 0x8E:\n            case 0x8F:\n                return get_msgpack_object(static_cast<std::size_t>(current & 0x0F));\n\n            // fixarray\n            case 0x90:\n            case 0x91:\n            case 0x92:\n            case 0x93:\n            case 0x94:\n            case 0x95:\n            case 0x96:\n            case 0x97:\n            case 0x98:\n            case 0x99:\n            case 0x9A:\n            case 0x9B:\n            case 0x9C:\n            case 0x9D:\n            case 0x9E:\n            case 0x9F:\n                return get_msgpack_array(static_cast<std::size_t>(current & 0x0F));\n\n            // fixstr\n            case 0xA0:\n            case 0xA1:\n            case 0xA2:\n            case 0xA3:\n            case 0xA4:\n            case 0xA5:\n            case 0xA6:\n            case 0xA7:\n            case 0xA8:\n            case 0xA9:\n            case 0xAA:\n            case 0xAB:\n            case 0xAC:\n            case 0xAD:\n            case 0xAE:\n            case 0xAF:\n            case 0xB0:\n            case 0xB1:\n            case 0xB2:\n            case 0xB3:\n            case 0xB4:\n            case 0xB5:\n            case 0xB6:\n            case 0xB7:\n            case 0xB8:\n            case 0xB9:\n            case 0xBA:\n            case 0xBB:\n            case 0xBC:\n            case 0xBD:\n            case 0xBE:\n            case 0xBF:\n            {\n                string_t s;\n                return get_msgpack_string(s) and sax->string(s);\n            }\n\n            case 0xC0: // nil\n                return sax->null();\n\n            case 0xC2: // false\n                return sax->boolean(false);\n\n            case 0xC3: // true\n                return sax->boolean(true);\n\n            case 0xCA: // float 32\n            {\n                float number;\n                return get_number(input_format_t::msgpack, number) and sax->number_float(static_cast<number_float_t>(number), \"\");\n            }\n\n            case 0xCB: // float 64\n            {\n                double number;\n                return get_number(input_format_t::msgpack, number) and sax->number_float(static_cast<number_float_t>(number), \"\");\n            }\n\n            case 0xCC: // uint 8\n            {\n                uint8_t number;\n                return get_number(input_format_t::msgpack, number) and sax->number_unsigned(number);\n            }\n\n            case 0xCD: // uint 16\n            {\n                uint16_t number;\n                return get_number(input_format_t::msgpack, number) and sax->number_unsigned(number);\n            }\n\n            case 0xCE: // uint 32\n            {\n                uint32_t number;\n                return get_number(input_format_t::msgpack, number) and sax->number_unsigned(number);\n            }\n\n            case 0xCF: // uint 64\n            {\n                uint64_t number;\n                return get_number(input_format_t::msgpack, number) and sax->number_unsigned(number);\n            }\n\n            case 0xD0: // int 8\n            {\n                int8_t number;\n                return get_number(input_format_t::msgpack, number) and sax->number_integer(number);\n            }\n\n            case 0xD1: // int 16\n            {\n                int16_t number;\n                return get_number(input_format_t::msgpack, number) and sax->number_integer(number);\n            }\n\n            case 0xD2: // int 32\n            {\n                int32_t number;\n                return get_number(input_format_t::msgpack, number) and sax->number_integer(number);\n            }\n\n            case 0xD3: // int 64\n            {\n                int64_t number;\n                return get_number(input_format_t::msgpack, number) and sax->number_integer(number);\n            }\n\n            case 0xD9: // str 8\n            case 0xDA: // str 16\n            case 0xDB: // str 32\n            {\n                string_t s;\n                return get_msgpack_string(s) and sax->string(s);\n            }\n\n            case 0xDC: // array 16\n            {\n                uint16_t len;\n                return get_number(input_format_t::msgpack, len) and get_msgpack_array(static_cast<std::size_t>(len));\n            }\n\n            case 0xDD: // array 32\n            {\n                uint32_t len;\n                return get_number(input_format_t::msgpack, len) and get_msgpack_array(static_cast<std::size_t>(len));\n            }\n\n            case 0xDE: // map 16\n            {\n                uint16_t len;\n                return get_number(input_format_t::msgpack, len) and get_msgpack_object(static_cast<std::size_t>(len));\n            }\n\n            case 0xDF: // map 32\n            {\n                uint32_t len;\n                return get_number(input_format_t::msgpack, len) and get_msgpack_object(static_cast<std::size_t>(len));\n            }\n\n            // negative fixint\n            case 0xE0:\n            case 0xE1:\n            case 0xE2:\n            case 0xE3:\n            case 0xE4:\n            case 0xE5:\n            case 0xE6:\n            case 0xE7:\n            case 0xE8:\n            case 0xE9:\n            case 0xEA:\n            case 0xEB:\n            case 0xEC:\n            case 0xED:\n            case 0xEE:\n            case 0xEF:\n            case 0xF0:\n            case 0xF1:\n            case 0xF2:\n            case 0xF3:\n            case 0xF4:\n            case 0xF5:\n            case 0xF6:\n            case 0xF7:\n            case 0xF8:\n            case 0xF9:\n            case 0xFA:\n            case 0xFB:\n            case 0xFC:\n            case 0xFD:\n            case 0xFE:\n            case 0xFF:\n                return sax->number_integer(static_cast<int8_t>(current));\n\n            default: // anything else\n            {\n                auto last_token = get_token_string();\n                return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::msgpack, \"invalid byte: 0x\" + last_token, \"value\")));\n            }\n        }\n    }\n\n    /*!\n    @brief reads a MessagePack string\n\n    This function first reads starting bytes to determine the expected\n    string length and then copies this number of bytes into a string.\n\n    @param[out] result  created string\n\n    @return whether string creation completed\n    */\n    bool get_msgpack_string(string_t& result)\n    {\n        if (JSON_UNLIKELY(not unexpect_eof(input_format_t::msgpack, \"string\")))\n        {\n            return false;\n        }\n\n        switch (current)\n        {\n            // fixstr\n            case 0xA0:\n            case 0xA1:\n            case 0xA2:\n            case 0xA3:\n            case 0xA4:\n            case 0xA5:\n            case 0xA6:\n            case 0xA7:\n            case 0xA8:\n            case 0xA9:\n            case 0xAA:\n            case 0xAB:\n            case 0xAC:\n            case 0xAD:\n            case 0xAE:\n            case 0xAF:\n            case 0xB0:\n            case 0xB1:\n            case 0xB2:\n            case 0xB3:\n            case 0xB4:\n            case 0xB5:\n            case 0xB6:\n            case 0xB7:\n            case 0xB8:\n            case 0xB9:\n            case 0xBA:\n            case 0xBB:\n            case 0xBC:\n            case 0xBD:\n            case 0xBE:\n            case 0xBF:\n            {\n                return get_string(input_format_t::msgpack, current & 0x1F, result);\n            }\n\n            case 0xD9: // str 8\n            {\n                uint8_t len;\n                return get_number(input_format_t::msgpack, len) and get_string(input_format_t::msgpack, len, result);\n            }\n\n            case 0xDA: // str 16\n            {\n                uint16_t len;\n                return get_number(input_format_t::msgpack, len) and get_string(input_format_t::msgpack, len, result);\n            }\n\n            case 0xDB: // str 32\n            {\n                uint32_t len;\n                return get_number(input_format_t::msgpack, len) and get_string(input_format_t::msgpack, len, result);\n            }\n\n            default:\n            {\n                auto last_token = get_token_string();\n                return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::msgpack, \"expected length specification (0xA0-0xBF, 0xD9-0xDB); last byte: 0x\" + last_token, \"string\")));\n            }\n        }\n    }\n\n    /*!\n    @param[in] len  the length of the array\n    @return whether array creation completed\n    */\n    bool get_msgpack_array(const std::size_t len)\n    {\n        if (JSON_UNLIKELY(not sax->start_array(len)))\n        {\n            return false;\n        }\n\n        for (std::size_t i = 0; i < len; ++i)\n        {\n            if (JSON_UNLIKELY(not parse_msgpack_internal()))\n            {\n                return false;\n            }\n        }\n\n        return sax->end_array();\n    }\n\n    /*!\n    @param[in] len  the length of the object\n    @return whether object creation completed\n    */\n    bool get_msgpack_object(const std::size_t len)\n    {\n        if (JSON_UNLIKELY(not sax->start_object(len)))\n        {\n            return false;\n        }\n\n        string_t key;\n        for (std::size_t i = 0; i < len; ++i)\n        {\n            get();\n            if (JSON_UNLIKELY(not get_msgpack_string(key) or not sax->key(key)))\n            {\n                return false;\n            }\n\n            if (JSON_UNLIKELY(not parse_msgpack_internal()))\n            {\n                return false;\n            }\n            key.clear();\n        }\n\n        return sax->end_object();\n    }\n\n    ////////////\n    // UBJSON //\n    ////////////\n\n    /*!\n    @param[in] get_char  whether a new character should be retrieved from the\n                         input (true, default) or whether the last read\n                         character should be considered instead\n\n    @return whether a valid UBJSON value was passed to the SAX parser\n    */\n    bool parse_ubjson_internal(const bool get_char = true)\n    {\n        return get_ubjson_value(get_char ? get_ignore_noop() : current);\n    }\n\n    /*!\n    @brief reads a UBJSON string\n\n    This function is either called after reading the 'S' byte explicitly\n    indicating a string, or in case of an object key where the 'S' byte can be\n    left out.\n\n    @param[out] result   created string\n    @param[in] get_char  whether a new character should be retrieved from the\n                         input (true, default) or whether the last read\n                         character should be considered instead\n\n    @return whether string creation completed\n    */\n    bool get_ubjson_string(string_t& result, const bool get_char = true)\n    {\n        if (get_char)\n        {\n            get();  // TODO: may we ignore N here?\n        }\n\n        if (JSON_UNLIKELY(not unexpect_eof(input_format_t::ubjson, \"value\")))\n        {\n            return false;\n        }\n\n        switch (current)\n        {\n            case 'U':\n            {\n                uint8_t len;\n                return get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result);\n            }\n\n            case 'i':\n            {\n                int8_t len;\n                return get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result);\n            }\n\n            case 'I':\n            {\n                int16_t len;\n                return get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result);\n            }\n\n            case 'l':\n            {\n                int32_t len;\n                return get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result);\n            }\n\n            case 'L':\n            {\n                int64_t len;\n                return get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result);\n            }\n\n            default:\n                auto last_token = get_token_string();\n                return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::ubjson, \"expected length type specification (U, i, I, l, L); last byte: 0x\" + last_token, \"string\")));\n        }\n    }\n\n    /*!\n    @param[out] result  determined size\n    @return whether size determination completed\n    */\n    bool get_ubjson_size_value(std::size_t& result)\n    {\n        switch (get_ignore_noop())\n        {\n            case 'U':\n            {\n                uint8_t number;\n                if (JSON_UNLIKELY(not get_number(input_format_t::ubjson, number)))\n                {\n                    return false;\n                }\n                result = static_cast<std::size_t>(number);\n                return true;\n            }\n\n            case 'i':\n            {\n                int8_t number;\n                if (JSON_UNLIKELY(not get_number(input_format_t::ubjson, number)))\n                {\n                    return false;\n                }\n                result = static_cast<std::size_t>(number);\n                return true;\n            }\n\n            case 'I':\n            {\n                int16_t number;\n                if (JSON_UNLIKELY(not get_number(input_format_t::ubjson, number)))\n                {\n                    return false;\n                }\n                result = static_cast<std::size_t>(number);\n                return true;\n            }\n\n            case 'l':\n            {\n                int32_t number;\n                if (JSON_UNLIKELY(not get_number(input_format_t::ubjson, number)))\n                {\n                    return false;\n                }\n                result = static_cast<std::size_t>(number);\n                return true;\n            }\n\n            case 'L':\n            {\n                int64_t number;\n                if (JSON_UNLIKELY(not get_number(input_format_t::ubjson, number)))\n                {\n                    return false;\n                }\n                result = static_cast<std::size_t>(number);\n                return true;\n            }\n\n            default:\n            {\n                auto last_token = get_token_string();\n                return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::ubjson, \"expected length type specification (U, i, I, l, L) after '#'; last byte: 0x\" + last_token, \"size\")));\n            }\n        }\n    }\n\n    /*!\n    @brief determine the type and size for a container\n\n    In the optimized UBJSON format, a type and a size can be provided to allow\n    for a more compact representation.\n\n    @param[out] result  pair of the size and the type\n\n    @return whether pair creation completed\n    */\n    bool get_ubjson_size_type(std::pair<std::size_t, int>& result)\n    {\n        result.first = string_t::npos; // size\n        result.second = 0; // type\n\n        get_ignore_noop();\n\n        if (current == '$')\n        {\n            result.second = get();  // must not ignore 'N', because 'N' maybe the type\n            if (JSON_UNLIKELY(not unexpect_eof(input_format_t::ubjson, \"type\")))\n            {\n                return false;\n            }\n\n            get_ignore_noop();\n            if (JSON_UNLIKELY(current != '#'))\n            {\n                if (JSON_UNLIKELY(not unexpect_eof(input_format_t::ubjson, \"value\")))\n                {\n                    return false;\n                }\n                auto last_token = get_token_string();\n                return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::ubjson, \"expected '#' after type information; last byte: 0x\" + last_token, \"size\")));\n            }\n\n            return get_ubjson_size_value(result.first);\n        }\n        else if (current == '#')\n        {\n            return get_ubjson_size_value(result.first);\n        }\n        return true;\n    }\n\n    /*!\n    @param prefix  the previously read or set type prefix\n    @return whether value creation completed\n    */\n    bool get_ubjson_value(const int prefix)\n    {\n        switch (prefix)\n        {\n            case std::char_traits<char>::eof():  // EOF\n                return unexpect_eof(input_format_t::ubjson, \"value\");\n\n            case 'T':  // true\n                return sax->boolean(true);\n            case 'F':  // false\n                return sax->boolean(false);\n\n            case 'Z':  // null\n                return sax->null();\n\n            case 'U':\n            {\n                uint8_t number;\n                return get_number(input_format_t::ubjson, number) and sax->number_unsigned(number);\n            }\n\n            case 'i':\n            {\n                int8_t number;\n                return get_number(input_format_t::ubjson, number) and sax->number_integer(number);\n            }\n\n            case 'I':\n            {\n                int16_t number;\n                return get_number(input_format_t::ubjson, number) and sax->number_integer(number);\n            }\n\n            case 'l':\n            {\n                int32_t number;\n                return get_number(input_format_t::ubjson, number) and sax->number_integer(number);\n            }\n\n            case 'L':\n            {\n                int64_t number;\n                return get_number(input_format_t::ubjson, number) and sax->number_integer(number);\n            }\n\n            case 'd':\n            {\n                float number;\n                return get_number(input_format_t::ubjson, number) and sax->number_float(static_cast<number_float_t>(number), \"\");\n            }\n\n            case 'D':\n            {\n                double number;\n                return get_number(input_format_t::ubjson, number) and sax->number_float(static_cast<number_float_t>(number), \"\");\n            }\n\n            case 'C':  // char\n            {\n                get();\n                if (JSON_UNLIKELY(not unexpect_eof(input_format_t::ubjson, \"char\")))\n                {\n                    return false;\n                }\n                if (JSON_UNLIKELY(current > 127))\n                {\n                    auto last_token = get_token_string();\n                    return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format_t::ubjson, \"byte after 'C' must be in range 0x00..0x7F; last byte: 0x\" + last_token, \"char\")));\n                }\n                string_t s(1, static_cast<char>(current));\n                return sax->string(s);\n            }\n\n            case 'S':  // string\n            {\n                string_t s;\n                return get_ubjson_string(s) and sax->string(s);\n            }\n\n            case '[':  // array\n                return get_ubjson_array();\n\n            case '{':  // object\n                return get_ubjson_object();\n\n            default: // anything else\n            {\n                auto last_token = get_token_string();\n                return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format_t::ubjson, \"invalid byte: 0x\" + last_token, \"value\")));\n            }\n        }\n    }\n\n    /*!\n    @return whether array creation completed\n    */\n    bool get_ubjson_array()\n    {\n        std::pair<std::size_t, int> size_and_type;\n        if (JSON_UNLIKELY(not get_ubjson_size_type(size_and_type)))\n        {\n            return false;\n        }\n\n        if (size_and_type.first != string_t::npos)\n        {\n            if (JSON_UNLIKELY(not sax->start_array(size_and_type.first)))\n            {\n                return false;\n            }\n\n            if (size_and_type.second != 0)\n            {\n                if (size_and_type.second != 'N')\n                {\n                    for (std::size_t i = 0; i < size_and_type.first; ++i)\n                    {\n                        if (JSON_UNLIKELY(not get_ubjson_value(size_and_type.second)))\n                        {\n                            return false;\n                        }\n                    }\n                }\n            }\n            else\n            {\n                for (std::size_t i = 0; i < size_and_type.first; ++i)\n                {\n                    if (JSON_UNLIKELY(not parse_ubjson_internal()))\n                    {\n                        return false;\n                    }\n                }\n            }\n        }\n        else\n        {\n            if (JSON_UNLIKELY(not sax->start_array(std::size_t(-1))))\n            {\n                return false;\n            }\n\n            while (current != ']')\n            {\n                if (JSON_UNLIKELY(not parse_ubjson_internal(false)))\n                {\n                    return false;\n                }\n                get_ignore_noop();\n            }\n        }\n\n        return sax->end_array();\n    }\n\n    /*!\n    @return whether object creation completed\n    */\n    bool get_ubjson_object()\n    {\n        std::pair<std::size_t, int> size_and_type;\n        if (JSON_UNLIKELY(not get_ubjson_size_type(size_and_type)))\n        {\n            return false;\n        }\n\n        string_t key;\n        if (size_and_type.first != string_t::npos)\n        {\n            if (JSON_UNLIKELY(not sax->start_object(size_and_type.first)))\n            {\n                return false;\n            }\n\n            if (size_and_type.second != 0)\n            {\n                for (std::size_t i = 0; i < size_and_type.first; ++i)\n                {\n                    if (JSON_UNLIKELY(not get_ubjson_string(key) or not sax->key(key)))\n                    {\n                        return false;\n                    }\n                    if (JSON_UNLIKELY(not get_ubjson_value(size_and_type.second)))\n                    {\n                        return false;\n                    }\n                    key.clear();\n                }\n            }\n            else\n            {\n                for (std::size_t i = 0; i < size_and_type.first; ++i)\n                {\n                    if (JSON_UNLIKELY(not get_ubjson_string(key) or not sax->key(key)))\n                    {\n                        return false;\n                    }\n                    if (JSON_UNLIKELY(not parse_ubjson_internal()))\n                    {\n                        return false;\n                    }\n                    key.clear();\n                }\n            }\n        }\n        else\n        {\n            if (JSON_UNLIKELY(not sax->start_object(std::size_t(-1))))\n            {\n                return false;\n            }\n\n            while (current != '}')\n            {\n                if (JSON_UNLIKELY(not get_ubjson_string(key, false) or not sax->key(key)))\n                {\n                    return false;\n                }\n                if (JSON_UNLIKELY(not parse_ubjson_internal()))\n                {\n                    return false;\n                }\n                get_ignore_noop();\n                key.clear();\n            }\n        }\n\n        return sax->end_object();\n    }\n\n    ///////////////////////\n    // Utility functions //\n    ///////////////////////\n\n    /*!\n    @brief get next character from the input\n\n    This function provides the interface to the used input adapter. It does\n    not throw in case the input reached EOF, but returns a -'ve valued\n    `std::char_traits<char>::eof()` in that case.\n\n    @return character read from the input\n    */\n    int get()\n    {\n        ++chars_read;\n        return (current = ia->get_character());\n    }\n\n    /*!\n    @return character read from the input after ignoring all 'N' entries\n    */\n    int get_ignore_noop()\n    {\n        do\n        {\n            get();\n        }\n        while (current == 'N');\n\n        return current;\n    }\n\n    /*\n    @brief read a number from the input\n\n    @tparam NumberType the type of the number\n    @param[in] format   the current format (for diagnostics)\n    @param[out] result  number of type @a NumberType\n\n    @return whether conversion completed\n\n    @note This function needs to respect the system's endianess, because\n          bytes in CBOR, MessagePack, and UBJSON are stored in network order\n          (big endian) and therefore need reordering on little endian systems.\n    */\n    template<typename NumberType, bool InputIsLittleEndian = false>\n    bool get_number(const input_format_t format, NumberType& result)\n    {\n        // step 1: read input into array with system's byte order\n        std::array<uint8_t, sizeof(NumberType)> vec;\n        for (std::size_t i = 0; i < sizeof(NumberType); ++i)\n        {\n            get();\n            if (JSON_UNLIKELY(not unexpect_eof(format, \"number\")))\n            {\n                return false;\n            }\n\n            // reverse byte order prior to conversion if necessary\n            if (is_little_endian && !InputIsLittleEndian)\n            {\n                vec[sizeof(NumberType) - i - 1] = static_cast<uint8_t>(current);\n            }\n            else\n            {\n                vec[i] = static_cast<uint8_t>(current); // LCOV_EXCL_LINE\n            }\n        }\n\n        // step 2: convert array into number of type T and return\n        std::memcpy(&result, vec.data(), sizeof(NumberType));\n        return true;\n    }\n\n    /*!\n    @brief create a string by reading characters from the input\n\n    @tparam NumberType the type of the number\n    @param[in] format the current format (for diagnostics)\n    @param[in] len number of characters to read\n    @param[out] result string created by reading @a len bytes\n\n    @return whether string creation completed\n\n    @note We can not reserve @a len bytes for the result, because @a len\n          may be too large. Usually, @ref unexpect_eof() detects the end of\n          the input before we run out of string memory.\n    */\n    template<typename NumberType>\n    bool get_string(const input_format_t format,\n                    const NumberType len,\n                    string_t& result)\n    {\n        bool success = true;\n        std::generate_n(std::back_inserter(result), len, [this, &success, &format]()\n        {\n            get();\n            if (JSON_UNLIKELY(not unexpect_eof(format, \"string\")))\n            {\n                success = false;\n            }\n            return static_cast<char>(current);\n        });\n        return success;\n    }\n\n    /*!\n    @param[in] format   the current format (for diagnostics)\n    @param[in] context  further context information (for diagnostics)\n    @return whether the last read character is not EOF\n    */\n    bool unexpect_eof(const input_format_t format, const char* context) const\n    {\n        if (JSON_UNLIKELY(current == std::char_traits<char>::eof()))\n        {\n            return sax->parse_error(chars_read, \"<end of file>\",\n                                    parse_error::create(110, chars_read, exception_message(format, \"unexpected end of input\", context)));\n        }\n        return true;\n    }\n\n    /*!\n    @return a string representation of the last read byte\n    */\n    std::string get_token_string() const\n    {\n        char cr[3];\n        (std::snprintf)(cr, 3, \"%.2hhX\", static_cast<unsigned char>(current));\n        return std::string{cr};\n    }\n\n    /*!\n    @param[in] format   the current format\n    @param[in] detail   a detailed error message\n    @param[in] context  further contect information\n    @return a message string to use in the parse_error exceptions\n    */\n    std::string exception_message(const input_format_t format,\n                                  const std::string& detail,\n                                  const std::string& context) const\n    {\n        std::string error_msg = \"syntax error while parsing \";\n\n        switch (format)\n        {\n            case input_format_t::cbor:\n                error_msg += \"CBOR\";\n                break;\n\n            case input_format_t::msgpack:\n                error_msg += \"MessagePack\";\n                break;\n\n            case input_format_t::ubjson:\n                error_msg += \"UBJSON\";\n                break;\n\n            case input_format_t::bson:\n                error_msg += \"BSON\";\n                break;\n\n            // LCOV_EXCL_START\n            default:\n                assert(false);\n                // LCOV_EXCL_STOP\n        }\n\n        return error_msg + \" \" + context + \": \" + detail;\n    }\n\n  private:\n    /// input adapter\n    input_adapter_t ia = nullptr;\n\n    /// the current character\n    int current = std::char_traits<char>::eof();\n\n    /// the number of characters read\n    std::size_t chars_read = 0;\n\n    /// whether we can assume little endianess\n    const bool is_little_endian = little_endianess();\n\n    /// the SAX parser\n    json_sax_t* sax = nullptr;\n};\n}  // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/output/binary_writer.hpp>\n\n\n#include <algorithm> // reverse\n#include <array> // array\n#include <cstdint> // uint8_t, uint16_t, uint32_t, uint64_t\n#include <cstring> // memcpy\n#include <limits> // numeric_limits\n\n// #include <nlohmann/detail/input/binary_reader.hpp>\n\n// #include <nlohmann/detail/output/output_adapters.hpp>\n\n\nnamespace nlohmann\n{\nnamespace detail\n{\n///////////////////\n// binary writer //\n///////////////////\n\n/*!\n@brief serialization to CBOR and MessagePack values\n*/\ntemplate<typename BasicJsonType, typename CharType>\nclass binary_writer\n{\n    using string_t = typename BasicJsonType::string_t;\n\n  public:\n    /*!\n    @brief create a binary writer\n\n    @param[in] adapter  output adapter to write to\n    */\n    explicit binary_writer(output_adapter_t<CharType> adapter) : oa(adapter)\n    {\n        assert(oa);\n    }\n\n    /*!\n    @param[in] j  JSON value to serialize\n    @pre       j.type() == value_t::object\n    */\n    void write_bson(const BasicJsonType& j)\n    {\n        switch (j.type())\n        {\n            case value_t::object:\n            {\n                write_bson_object(*j.m_value.object);\n                break;\n            }\n\n            default:\n            {\n                JSON_THROW(type_error::create(317, \"to serialize to BSON, top-level type must be object, but is \" + std::string(j.type_name())));\n            }\n        }\n    }\n\n    /*!\n    @param[in] j  JSON value to serialize\n    */\n    void write_cbor(const BasicJsonType& j)\n    {\n        switch (j.type())\n        {\n            case value_t::null:\n            {\n                oa->write_character(to_char_type(0xF6));\n                break;\n            }\n\n            case value_t::boolean:\n            {\n                oa->write_character(j.m_value.boolean\n                                    ? to_char_type(0xF5)\n                                    : to_char_type(0xF4));\n                break;\n            }\n\n            case value_t::number_integer:\n            {\n                if (j.m_value.number_integer >= 0)\n                {\n                    // CBOR does not differentiate between positive signed\n                    // integers and unsigned integers. Therefore, we used the\n                    // code from the value_t::number_unsigned case here.\n                    if (j.m_value.number_integer <= 0x17)\n                    {\n                        write_number(static_cast<uint8_t>(j.m_value.number_integer));\n                    }\n                    else if (j.m_value.number_integer <= (std::numeric_limits<uint8_t>::max)())\n                    {\n                        oa->write_character(to_char_type(0x18));\n                        write_number(static_cast<uint8_t>(j.m_value.number_integer));\n                    }\n                    else if (j.m_value.number_integer <= (std::numeric_limits<uint16_t>::max)())\n                    {\n                        oa->write_character(to_char_type(0x19));\n                        write_number(static_cast<uint16_t>(j.m_value.number_integer));\n                    }\n                    else if (j.m_value.number_integer <= (std::numeric_limits<uint32_t>::max)())\n                    {\n                        oa->write_character(to_char_type(0x1A));\n                        write_number(static_cast<uint32_t>(j.m_value.number_integer));\n                    }\n                    else\n                    {\n                        oa->write_character(to_char_type(0x1B));\n                        write_number(static_cast<uint64_t>(j.m_value.number_integer));\n                    }\n                }\n                else\n                {\n                    // The conversions below encode the sign in the first\n                    // byte, and the value is converted to a positive number.\n                    const auto positive_number = -1 - j.m_value.number_integer;\n                    if (j.m_value.number_integer >= -24)\n                    {\n                        write_number(static_cast<uint8_t>(0x20 + positive_number));\n                    }\n                    else if (positive_number <= (std::numeric_limits<uint8_t>::max)())\n                    {\n                        oa->write_character(to_char_type(0x38));\n                        write_number(static_cast<uint8_t>(positive_number));\n                    }\n                    else if (positive_number <= (std::numeric_limits<uint16_t>::max)())\n                    {\n                        oa->write_character(to_char_type(0x39));\n                        write_number(static_cast<uint16_t>(positive_number));\n                    }\n                    else if (positive_number <= (std::numeric_limits<uint32_t>::max)())\n                    {\n                        oa->write_character(to_char_type(0x3A));\n                        write_number(static_cast<uint32_t>(positive_number));\n                    }\n                    else\n                    {\n                        oa->write_character(to_char_type(0x3B));\n                        write_number(static_cast<uint64_t>(positive_number));\n                    }\n                }\n                break;\n            }\n\n            case value_t::number_unsigned:\n            {\n                if (j.m_value.number_unsigned <= 0x17)\n                {\n                    write_number(static_cast<uint8_t>(j.m_value.number_unsigned));\n                }\n                else if (j.m_value.number_unsigned <= (std::numeric_limits<uint8_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x18));\n                    write_number(static_cast<uint8_t>(j.m_value.number_unsigned));\n                }\n                else if (j.m_value.number_unsigned <= (std::numeric_limits<uint16_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x19));\n                    write_number(static_cast<uint16_t>(j.m_value.number_unsigned));\n                }\n                else if (j.m_value.number_unsigned <= (std::numeric_limits<uint32_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x1A));\n                    write_number(static_cast<uint32_t>(j.m_value.number_unsigned));\n                }\n                else\n                {\n                    oa->write_character(to_char_type(0x1B));\n                    write_number(static_cast<uint64_t>(j.m_value.number_unsigned));\n                }\n                break;\n            }\n\n            case value_t::number_float:\n            {\n                oa->write_character(get_cbor_float_prefix(j.m_value.number_float));\n                write_number(j.m_value.number_float);\n                break;\n            }\n\n            case value_t::string:\n            {\n                // step 1: write control byte and the string length\n                const auto N = j.m_value.string->size();\n                if (N <= 0x17)\n                {\n                    write_number(static_cast<uint8_t>(0x60 + N));\n                }\n                else if (N <= (std::numeric_limits<uint8_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x78));\n                    write_number(static_cast<uint8_t>(N));\n                }\n                else if (N <= (std::numeric_limits<uint16_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x79));\n                    write_number(static_cast<uint16_t>(N));\n                }\n                else if (N <= (std::numeric_limits<uint32_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x7A));\n                    write_number(static_cast<uint32_t>(N));\n                }\n                // LCOV_EXCL_START\n                else if (N <= (std::numeric_limits<uint64_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x7B));\n                    write_number(static_cast<uint64_t>(N));\n                }\n                // LCOV_EXCL_STOP\n\n                // step 2: write the string\n                oa->write_characters(\n                    reinterpret_cast<const CharType*>(j.m_value.string->c_str()),\n                    j.m_value.string->size());\n                break;\n            }\n\n            case value_t::array:\n            {\n                // step 1: write control byte and the array size\n                const auto N = j.m_value.array->size();\n                if (N <= 0x17)\n                {\n                    write_number(static_cast<uint8_t>(0x80 + N));\n                }\n                else if (N <= (std::numeric_limits<uint8_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x98));\n                    write_number(static_cast<uint8_t>(N));\n                }\n                else if (N <= (std::numeric_limits<uint16_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x99));\n                    write_number(static_cast<uint16_t>(N));\n                }\n                else if (N <= (std::numeric_limits<uint32_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x9A));\n                    write_number(static_cast<uint32_t>(N));\n                }\n                // LCOV_EXCL_START\n                else if (N <= (std::numeric_limits<uint64_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x9B));\n                    write_number(static_cast<uint64_t>(N));\n                }\n                // LCOV_EXCL_STOP\n\n                // step 2: write each element\n                for (const auto& el : *j.m_value.array)\n                {\n                    write_cbor(el);\n                }\n                break;\n            }\n\n            case value_t::object:\n            {\n                // step 1: write control byte and the object size\n                const auto N = j.m_value.object->size();\n                if (N <= 0x17)\n                {\n                    write_number(static_cast<uint8_t>(0xA0 + N));\n                }\n                else if (N <= (std::numeric_limits<uint8_t>::max)())\n                {\n                    oa->write_character(to_char_type(0xB8));\n                    write_number(static_cast<uint8_t>(N));\n                }\n                else if (N <= (std::numeric_limits<uint16_t>::max)())\n                {\n                    oa->write_character(to_char_type(0xB9));\n                    write_number(static_cast<uint16_t>(N));\n                }\n                else if (N <= (std::numeric_limits<uint32_t>::max)())\n                {\n                    oa->write_character(to_char_type(0xBA));\n                    write_number(static_cast<uint32_t>(N));\n                }\n                // LCOV_EXCL_START\n                else if (N <= (std::numeric_limits<uint64_t>::max)())\n                {\n                    oa->write_character(to_char_type(0xBB));\n                    write_number(static_cast<uint64_t>(N));\n                }\n                // LCOV_EXCL_STOP\n\n                // step 2: write each element\n                for (const auto& el : *j.m_value.object)\n                {\n                    write_cbor(el.first);\n                    write_cbor(el.second);\n                }\n                break;\n            }\n\n            default:\n                break;\n        }\n    }\n\n    /*!\n    @param[in] j  JSON value to serialize\n    */\n    void write_msgpack(const BasicJsonType& j)\n    {\n        switch (j.type())\n        {\n            case value_t::null: // nil\n            {\n                oa->write_character(to_char_type(0xC0));\n                break;\n            }\n\n            case value_t::boolean: // true and false\n            {\n                oa->write_character(j.m_value.boolean\n                                    ? to_char_type(0xC3)\n                                    : to_char_type(0xC2));\n                break;\n            }\n\n            case value_t::number_integer:\n            {\n                if (j.m_value.number_integer >= 0)\n                {\n                    // MessagePack does not differentiate between positive\n                    // signed integers and unsigned integers. Therefore, we used\n                    // the code from the value_t::number_unsigned case here.\n                    if (j.m_value.number_unsigned < 128)\n                    {\n                        // positive fixnum\n                        write_number(static_cast<uint8_t>(j.m_value.number_integer));\n                    }\n                    else if (j.m_value.number_unsigned <= (std::numeric_limits<uint8_t>::max)())\n                    {\n                        // uint 8\n                        oa->write_character(to_char_type(0xCC));\n                        write_number(static_cast<uint8_t>(j.m_value.number_integer));\n                    }\n                    else if (j.m_value.number_unsigned <= (std::numeric_limits<uint16_t>::max)())\n                    {\n                        // uint 16\n                        oa->write_character(to_char_type(0xCD));\n                        write_number(static_cast<uint16_t>(j.m_value.number_integer));\n                    }\n                    else if (j.m_value.number_unsigned <= (std::numeric_limits<uint32_t>::max)())\n                    {\n                        // uint 32\n                        oa->write_character(to_char_type(0xCE));\n                        write_number(static_cast<uint32_t>(j.m_value.number_integer));\n                    }\n                    else if (j.m_value.number_unsigned <= (std::numeric_limits<uint64_t>::max)())\n                    {\n                        // uint 64\n                        oa->write_character(to_char_type(0xCF));\n                        write_number(static_cast<uint64_t>(j.m_value.number_integer));\n                    }\n                }\n                else\n                {\n                    if (j.m_value.number_integer >= -32)\n                    {\n                        // negative fixnum\n                        write_number(static_cast<int8_t>(j.m_value.number_integer));\n                    }\n                    else if (j.m_value.number_integer >= (std::numeric_limits<int8_t>::min)() and\n                             j.m_value.number_integer <= (std::numeric_limits<int8_t>::max)())\n                    {\n                        // int 8\n                        oa->write_character(to_char_type(0xD0));\n                        write_number(static_cast<int8_t>(j.m_value.number_integer));\n                    }\n                    else if (j.m_value.number_integer >= (std::numeric_limits<int16_t>::min)() and\n                             j.m_value.number_integer <= (std::numeric_limits<int16_t>::max)())\n                    {\n                        // int 16\n                        oa->write_character(to_char_type(0xD1));\n                        write_number(static_cast<int16_t>(j.m_value.number_integer));\n                    }\n                    else if (j.m_value.number_integer >= (std::numeric_limits<int32_t>::min)() and\n                             j.m_value.number_integer <= (std::numeric_limits<int32_t>::max)())\n                    {\n                        // int 32\n                        oa->write_character(to_char_type(0xD2));\n                        write_number(static_cast<int32_t>(j.m_value.number_integer));\n                    }\n                    else if (j.m_value.number_integer >= (std::numeric_limits<int64_t>::min)() and\n                             j.m_value.number_integer <= (std::numeric_limits<int64_t>::max)())\n                    {\n                        // int 64\n                        oa->write_character(to_char_type(0xD3));\n                        write_number(static_cast<int64_t>(j.m_value.number_integer));\n                    }\n                }\n                break;\n            }\n\n            case value_t::number_unsigned:\n            {\n                if (j.m_value.number_unsigned < 128)\n                {\n                    // positive fixnum\n                    write_number(static_cast<uint8_t>(j.m_value.number_integer));\n                }\n                else if (j.m_value.number_unsigned <= (std::numeric_limits<uint8_t>::max)())\n                {\n                    // uint 8\n                    oa->write_character(to_char_type(0xCC));\n                    write_number(static_cast<uint8_t>(j.m_value.number_integer));\n                }\n                else if (j.m_value.number_unsigned <= (std::numeric_limits<uint16_t>::max)())\n                {\n                    // uint 16\n                    oa->write_character(to_char_type(0xCD));\n                    write_number(static_cast<uint16_t>(j.m_value.number_integer));\n                }\n                else if (j.m_value.number_unsigned <= (std::numeric_limits<uint32_t>::max)())\n                {\n                    // uint 32\n                    oa->write_character(to_char_type(0xCE));\n                    write_number(static_cast<uint32_t>(j.m_value.number_integer));\n                }\n                else if (j.m_value.number_unsigned <= (std::numeric_limits<uint64_t>::max)())\n                {\n                    // uint 64\n                    oa->write_character(to_char_type(0xCF));\n                    write_number(static_cast<uint64_t>(j.m_value.number_integer));\n                }\n                break;\n            }\n\n            case value_t::number_float:\n            {\n                oa->write_character(get_msgpack_float_prefix(j.m_value.number_float));\n                write_number(j.m_value.number_float);\n                break;\n            }\n\n            case value_t::string:\n            {\n                // step 1: write control byte and the string length\n                const auto N = j.m_value.string->size();\n                if (N <= 31)\n                {\n                    // fixstr\n                    write_number(static_cast<uint8_t>(0xA0 | N));\n                }\n                else if (N <= (std::numeric_limits<uint8_t>::max)())\n                {\n                    // str 8\n                    oa->write_character(to_char_type(0xD9));\n                    write_number(static_cast<uint8_t>(N));\n                }\n                else if (N <= (std::numeric_limits<uint16_t>::max)())\n                {\n                    // str 16\n                    oa->write_character(to_char_type(0xDA));\n                    write_number(static_cast<uint16_t>(N));\n                }\n                else if (N <= (std::numeric_limits<uint32_t>::max)())\n                {\n                    // str 32\n                    oa->write_character(to_char_type(0xDB));\n                    write_number(static_cast<uint32_t>(N));\n                }\n\n                // step 2: write the string\n                oa->write_characters(\n                    reinterpret_cast<const CharType*>(j.m_value.string->c_str()),\n                    j.m_value.string->size());\n                break;\n            }\n\n            case value_t::array:\n            {\n                // step 1: write control byte and the array size\n                const auto N = j.m_value.array->size();\n                if (N <= 15)\n                {\n                    // fixarray\n                    write_number(static_cast<uint8_t>(0x90 | N));\n                }\n                else if (N <= (std::numeric_limits<uint16_t>::max)())\n                {\n                    // array 16\n                    oa->write_character(to_char_type(0xDC));\n                    write_number(static_cast<uint16_t>(N));\n                }\n                else if (N <= (std::numeric_limits<uint32_t>::max)())\n                {\n                    // array 32\n                    oa->write_character(to_char_type(0xDD));\n                    write_number(static_cast<uint32_t>(N));\n                }\n\n                // step 2: write each element\n                for (const auto& el : *j.m_value.array)\n                {\n                    write_msgpack(el);\n                }\n                break;\n            }\n\n            case value_t::object:\n            {\n                // step 1: write control byte and the object size\n                const auto N = j.m_value.object->size();\n                if (N <= 15)\n                {\n                    // fixmap\n                    write_number(static_cast<uint8_t>(0x80 | (N & 0xF)));\n                }\n                else if (N <= (std::numeric_limits<uint16_t>::max)())\n                {\n                    // map 16\n                    oa->write_character(to_char_type(0xDE));\n                    write_number(static_cast<uint16_t>(N));\n                }\n                else if (N <= (std::numeric_limits<uint32_t>::max)())\n                {\n                    // map 32\n                    oa->write_character(to_char_type(0xDF));\n                    write_number(static_cast<uint32_t>(N));\n                }\n\n                // step 2: write each element\n                for (const auto& el : *j.m_value.object)\n                {\n                    write_msgpack(el.first);\n                    write_msgpack(el.second);\n                }\n                break;\n            }\n\n            default:\n                break;\n        }\n    }\n\n    /*!\n    @param[in] j  JSON value to serialize\n    @param[in] use_count   whether to use '#' prefixes (optimized format)\n    @param[in] use_type    whether to use '$' prefixes (optimized format)\n    @param[in] add_prefix  whether prefixes need to be used for this value\n    */\n    void write_ubjson(const BasicJsonType& j, const bool use_count,\n                      const bool use_type, const bool add_prefix = true)\n    {\n        switch (j.type())\n        {\n            case value_t::null:\n            {\n                if (add_prefix)\n                {\n                    oa->write_character(to_char_type('Z'));\n                }\n                break;\n            }\n\n            case value_t::boolean:\n            {\n                if (add_prefix)\n                {\n                    oa->write_character(j.m_value.boolean\n                                        ? to_char_type('T')\n                                        : to_char_type('F'));\n                }\n                break;\n            }\n\n            case value_t::number_integer:\n            {\n                write_number_with_ubjson_prefix(j.m_value.number_integer, add_prefix);\n                break;\n            }\n\n            case value_t::number_unsigned:\n            {\n                write_number_with_ubjson_prefix(j.m_value.number_unsigned, add_prefix);\n                break;\n            }\n\n            case value_t::number_float:\n            {\n                write_number_with_ubjson_prefix(j.m_value.number_float, add_prefix);\n                break;\n            }\n\n            case value_t::string:\n            {\n                if (add_prefix)\n                {\n                    oa->write_character(to_char_type('S'));\n                }\n                write_number_with_ubjson_prefix(j.m_value.string->size(), true);\n                oa->write_characters(\n                    reinterpret_cast<const CharType*>(j.m_value.string->c_str()),\n                    j.m_value.string->size());\n                break;\n            }\n\n            case value_t::array:\n            {\n                if (add_prefix)\n                {\n                    oa->write_character(to_char_type('['));\n                }\n\n                bool prefix_required = true;\n                if (use_type and not j.m_value.array->empty())\n                {\n                    assert(use_count);\n                    const CharType first_prefix = ubjson_prefix(j.front());\n                    const bool same_prefix = std::all_of(j.begin() + 1, j.end(),\n                                                         [this, first_prefix](const BasicJsonType & v)\n                    {\n                        return ubjson_prefix(v) == first_prefix;\n                    });\n\n                    if (same_prefix)\n                    {\n                        prefix_required = false;\n                        oa->write_character(to_char_type('$'));\n                        oa->write_character(first_prefix);\n                    }\n                }\n\n                if (use_count)\n                {\n                    oa->write_character(to_char_type('#'));\n                    write_number_with_ubjson_prefix(j.m_value.array->size(), true);\n                }\n\n                for (const auto& el : *j.m_value.array)\n                {\n                    write_ubjson(el, use_count, use_type, prefix_required);\n                }\n\n                if (not use_count)\n                {\n                    oa->write_character(to_char_type(']'));\n                }\n\n                break;\n            }\n\n            case value_t::object:\n            {\n                if (add_prefix)\n                {\n                    oa->write_character(to_char_type('{'));\n                }\n\n                bool prefix_required = true;\n                if (use_type and not j.m_value.object->empty())\n                {\n                    assert(use_count);\n                    const CharType first_prefix = ubjson_prefix(j.front());\n                    const bool same_prefix = std::all_of(j.begin(), j.end(),\n                                                         [this, first_prefix](const BasicJsonType & v)\n                    {\n                        return ubjson_prefix(v) == first_prefix;\n                    });\n\n                    if (same_prefix)\n                    {\n                        prefix_required = false;\n                        oa->write_character(to_char_type('$'));\n                        oa->write_character(first_prefix);\n                    }\n                }\n\n                if (use_count)\n                {\n                    oa->write_character(to_char_type('#'));\n                    write_number_with_ubjson_prefix(j.m_value.object->size(), true);\n                }\n\n                for (const auto& el : *j.m_value.object)\n                {\n                    write_number_with_ubjson_prefix(el.first.size(), true);\n                    oa->write_characters(\n                        reinterpret_cast<const CharType*>(el.first.c_str()),\n                        el.first.size());\n                    write_ubjson(el.second, use_count, use_type, prefix_required);\n                }\n\n                if (not use_count)\n                {\n                    oa->write_character(to_char_type('}'));\n                }\n\n                break;\n            }\n\n            default:\n                break;\n        }\n    }\n\n  private:\n    //////////\n    // BSON //\n    //////////\n\n    /*!\n    @return The size of a BSON document entry header, including the id marker\n            and the entry name size (and its null-terminator).\n    */\n    static std::size_t calc_bson_entry_header_size(const string_t& name)\n    {\n        const auto it = name.find(static_cast<typename string_t::value_type>(0));\n        if (JSON_UNLIKELY(it != BasicJsonType::string_t::npos))\n        {\n            JSON_THROW(out_of_range::create(409,\n                                            \"BSON key cannot contain code point U+0000 (at byte \" + std::to_string(it) + \")\"));\n        }\n\n        return /*id*/ 1ul + name.size() + /*zero-terminator*/1u;\n    }\n\n    /*!\n    @brief Writes the given @a element_type and @a name to the output adapter\n    */\n    void write_bson_entry_header(const string_t& name,\n                                 const std::uint8_t element_type)\n    {\n        oa->write_character(to_char_type(element_type)); // boolean\n        oa->write_characters(\n            reinterpret_cast<const CharType*>(name.c_str()),\n            name.size() + 1u);\n    }\n\n    /*!\n    @brief Writes a BSON element with key @a name and boolean value @a value\n    */\n    void write_bson_boolean(const string_t& name,\n                            const bool value)\n    {\n        write_bson_entry_header(name, 0x08);\n        oa->write_character(value ? to_char_type(0x01) : to_char_type(0x00));\n    }\n\n    /*!\n    @brief Writes a BSON element with key @a name and double value @a value\n    */\n    void write_bson_double(const string_t& name,\n                           const double value)\n    {\n        write_bson_entry_header(name, 0x01);\n        write_number<double, true>(value);\n    }\n\n    /*!\n    @return The size of the BSON-encoded string in @a value\n    */\n    static std::size_t calc_bson_string_size(const string_t& value)\n    {\n        return sizeof(std::int32_t) + value.size() + 1ul;\n    }\n\n    /*!\n    @brief Writes a BSON element with key @a name and string value @a value\n    */\n    void write_bson_string(const string_t& name,\n                           const string_t& value)\n    {\n        write_bson_entry_header(name, 0x02);\n\n        write_number<std::int32_t, true>(static_cast<std::int32_t>(value.size() + 1ul));\n        oa->write_characters(\n            reinterpret_cast<const CharType*>(value.c_str()),\n            value.size() + 1);\n    }\n\n    /*!\n    @brief Writes a BSON element with key @a name and null value\n    */\n    void write_bson_null(const string_t& name)\n    {\n        write_bson_entry_header(name, 0x0A);\n    }\n\n    /*!\n    @return The size of the BSON-encoded integer @a value\n    */\n    static std::size_t calc_bson_integer_size(const std::int64_t value)\n    {\n        if ((std::numeric_limits<std::int32_t>::min)() <= value and value <= (std::numeric_limits<std::int32_t>::max)())\n        {\n            return sizeof(std::int32_t);\n        }\n        else\n        {\n            return sizeof(std::int64_t);\n        }\n    }\n\n    /*!\n    @brief Writes a BSON element with key @a name and integer @a value\n    */\n    void write_bson_integer(const string_t& name,\n                            const std::int64_t value)\n    {\n        if ((std::numeric_limits<std::int32_t>::min)() <= value and value <= (std::numeric_limits<std::int32_t>::max)())\n        {\n            write_bson_entry_header(name, 0x10); // int32\n            write_number<std::int32_t, true>(static_cast<std::int32_t>(value));\n        }\n        else\n        {\n            write_bson_entry_header(name, 0x12); // int64\n            write_number<std::int64_t, true>(static_cast<std::int64_t>(value));\n        }\n    }\n\n    /*!\n    @return The size of the BSON-encoded unsigned integer in @a j\n    */\n    static constexpr std::size_t calc_bson_unsigned_size(const std::uint64_t value) noexcept\n    {\n        return (value <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))\n               ? sizeof(std::int32_t)\n               : sizeof(std::int64_t);\n    }\n\n    /*!\n    @brief Writes a BSON element with key @a name and unsigned @a value\n    */\n    void write_bson_unsigned(const string_t& name,\n                             const std::uint64_t value)\n    {\n        if (value <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))\n        {\n            write_bson_entry_header(name, 0x10 /* int32 */);\n            write_number<std::int32_t, true>(static_cast<std::int32_t>(value));\n        }\n        else if (value <= static_cast<std::uint64_t>((std::numeric_limits<std::int64_t>::max)()))\n        {\n            write_bson_entry_header(name, 0x12 /* int64 */);\n            write_number<std::int64_t, true>(static_cast<std::int64_t>(value));\n        }\n        else\n        {\n            JSON_THROW(out_of_range::create(407, \"integer number \" + std::to_string(value) + \" cannot be represented by BSON as it does not fit int64\"));\n        }\n    }\n\n    /*!\n    @brief Writes a BSON element with key @a name and object @a value\n    */\n    void write_bson_object_entry(const string_t& name,\n                                 const typename BasicJsonType::object_t& value)\n    {\n        write_bson_entry_header(name, 0x03); // object\n        write_bson_object(value);\n    }\n\n    /*!\n    @return The size of the BSON-encoded array @a value\n    */\n    static std::size_t calc_bson_array_size(const typename BasicJsonType::array_t& value)\n    {\n        std::size_t embedded_document_size = 0ul;\n        std::size_t array_index = 0ul;\n\n        for (const auto& el : value)\n        {\n            embedded_document_size += calc_bson_element_size(std::to_string(array_index++), el);\n        }\n\n        return sizeof(std::int32_t) + embedded_document_size + 1ul;\n    }\n\n    /*!\n    @brief Writes a BSON element with key @a name and array @a value\n    */\n    void write_bson_array(const string_t& name,\n                          const typename BasicJsonType::array_t& value)\n    {\n        write_bson_entry_header(name, 0x04); // array\n        write_number<std::int32_t, true>(static_cast<std::int32_t>(calc_bson_array_size(value)));\n\n        std::size_t array_index = 0ul;\n\n        for (const auto& el : value)\n        {\n            write_bson_element(std::to_string(array_index++), el);\n        }\n\n        oa->write_character(to_char_type(0x00));\n    }\n\n    /*!\n    @brief Calculates the size necessary to serialize the JSON value @a j with its @a name\n    @return The calculated size for the BSON document entry for @a j with the given @a name.\n    */\n    static std::size_t calc_bson_element_size(const string_t& name,\n            const BasicJsonType& j)\n    {\n        const auto header_size = calc_bson_entry_header_size(name);\n        switch (j.type())\n        {\n            case value_t::object:\n                return header_size + calc_bson_object_size(*j.m_value.object);\n\n            case value_t::array:\n                return header_size + calc_bson_array_size(*j.m_value.array);\n\n            case value_t::boolean:\n                return header_size + 1ul;\n\n            case value_t::number_float:\n                return header_size + 8ul;\n\n            case value_t::number_integer:\n                return header_size + calc_bson_integer_size(j.m_value.number_integer);\n\n            case value_t::number_unsigned:\n                return header_size + calc_bson_unsigned_size(j.m_value.number_unsigned);\n\n            case value_t::string:\n                return header_size + calc_bson_string_size(*j.m_value.string);\n\n            case value_t::null:\n                return header_size + 0ul;\n\n            // LCOV_EXCL_START\n            default:\n                assert(false);\n                return 0ul;\n                // LCOV_EXCL_STOP\n        }\n    }\n\n    /*!\n    @brief Serializes the JSON value @a j to BSON and associates it with the\n           key @a name.\n    @param name The name to associate with the JSON entity @a j within the\n                current BSON document\n    @return The size of the BSON entry\n    */\n    void write_bson_element(const string_t& name,\n                            const BasicJsonType& j)\n    {\n        switch (j.type())\n        {\n            case value_t::object:\n                return write_bson_object_entry(name, *j.m_value.object);\n\n            case value_t::array:\n                return write_bson_array(name, *j.m_value.array);\n\n            case value_t::boolean:\n                return write_bson_boolean(name, j.m_value.boolean);\n\n            case value_t::number_float:\n                return write_bson_double(name, j.m_value.number_float);\n\n            case value_t::number_integer:\n                return write_bson_integer(name, j.m_value.number_integer);\n\n            case value_t::number_unsigned:\n                return write_bson_unsigned(name, j.m_value.number_unsigned);\n\n            case value_t::string:\n                return write_bson_string(name, *j.m_value.string);\n\n            case value_t::null:\n                return write_bson_null(name);\n\n            // LCOV_EXCL_START\n            default:\n                assert(false);\n                return;\n                // LCOV_EXCL_STOP\n        }\n    }\n\n    /*!\n    @brief Calculates the size of the BSON serialization of the given\n           JSON-object @a j.\n    @param[in] j  JSON value to serialize\n    @pre       j.type() == value_t::object\n    */\n    static std::size_t calc_bson_object_size(const typename BasicJsonType::object_t& value)\n    {\n        std::size_t document_size = std::accumulate(value.begin(), value.end(), 0ul,\n                                    [](size_t result, const typename BasicJsonType::object_t::value_type & el)\n        {\n            return result += calc_bson_element_size(el.first, el.second);\n        });\n\n        return sizeof(std::int32_t) + document_size + 1ul;\n    }\n\n    /*!\n    @param[in] j  JSON value to serialize\n    @pre       j.type() == value_t::object\n    */\n    void write_bson_object(const typename BasicJsonType::object_t& value)\n    {\n        write_number<std::int32_t, true>(static_cast<std::int32_t>(calc_bson_object_size(value)));\n\n        for (const auto& el : value)\n        {\n            write_bson_element(el.first, el.second);\n        }\n\n        oa->write_character(to_char_type(0x00));\n    }\n\n    //////////\n    // CBOR //\n    //////////\n\n    static constexpr CharType get_cbor_float_prefix(float /*unused*/)\n    {\n        return to_char_type(0xFA);  // Single-Precision Float\n    }\n\n    static constexpr CharType get_cbor_float_prefix(double /*unused*/)\n    {\n        return to_char_type(0xFB);  // Double-Precision Float\n    }\n\n    /////////////\n    // MsgPack //\n    /////////////\n\n    static constexpr CharType get_msgpack_float_prefix(float /*unused*/)\n    {\n        return to_char_type(0xCA);  // float 32\n    }\n\n    static constexpr CharType get_msgpack_float_prefix(double /*unused*/)\n    {\n        return to_char_type(0xCB);  // float 64\n    }\n\n    ////////////\n    // UBJSON //\n    ////////////\n\n    // UBJSON: write number (floating point)\n    template<typename NumberType, typename std::enable_if<\n                 std::is_floating_point<NumberType>::value, int>::type = 0>\n    void write_number_with_ubjson_prefix(const NumberType n,\n                                         const bool add_prefix)\n    {\n        if (add_prefix)\n        {\n            oa->write_character(get_ubjson_float_prefix(n));\n        }\n        write_number(n);\n    }\n\n    // UBJSON: write number (unsigned integer)\n    template<typename NumberType, typename std::enable_if<\n                 std::is_unsigned<NumberType>::value, int>::type = 0>\n    void write_number_with_ubjson_prefix(const NumberType n,\n                                         const bool add_prefix)\n    {\n        if (n <= static_cast<uint64_t>((std::numeric_limits<int8_t>::max)()))\n        {\n            if (add_prefix)\n            {\n                oa->write_character(to_char_type('i'));  // int8\n            }\n            write_number(static_cast<uint8_t>(n));\n        }\n        else if (n <= (std::numeric_limits<uint8_t>::max)())\n        {\n            if (add_prefix)\n            {\n                oa->write_character(to_char_type('U'));  // uint8\n            }\n            write_number(static_cast<uint8_t>(n));\n        }\n        else if (n <= static_cast<uint64_t>((std::numeric_limits<int16_t>::max)()))\n        {\n            if (add_prefix)\n            {\n                oa->write_character(to_char_type('I'));  // int16\n            }\n            write_number(static_cast<int16_t>(n));\n        }\n        else if (n <= static_cast<uint64_t>((std::numeric_limits<int32_t>::max)()))\n        {\n            if (add_prefix)\n            {\n                oa->write_character(to_char_type('l'));  // int32\n            }\n            write_number(static_cast<int32_t>(n));\n        }\n        else if (n <= static_cast<uint64_t>((std::numeric_limits<int64_t>::max)()))\n        {\n            if (add_prefix)\n            {\n                oa->write_character(to_char_type('L'));  // int64\n            }\n            write_number(static_cast<int64_t>(n));\n        }\n        else\n        {\n            JSON_THROW(out_of_range::create(407, \"integer number \" + std::to_string(n) + \" cannot be represented by UBJSON as it does not fit int64\"));\n        }\n    }\n\n    // UBJSON: write number (signed integer)\n    template<typename NumberType, typename std::enable_if<\n                 std::is_signed<NumberType>::value and\n                 not std::is_floating_point<NumberType>::value, int>::type = 0>\n    void write_number_with_ubjson_prefix(const NumberType n,\n                                         const bool add_prefix)\n    {\n        if ((std::numeric_limits<int8_t>::min)() <= n and n <= (std::numeric_limits<int8_t>::max)())\n        {\n            if (add_prefix)\n            {\n                oa->write_character(to_char_type('i'));  // int8\n            }\n            write_number(static_cast<int8_t>(n));\n        }\n        else if (static_cast<int64_t>((std::numeric_limits<uint8_t>::min)()) <= n and n <= static_cast<int64_t>((std::numeric_limits<uint8_t>::max)()))\n        {\n            if (add_prefix)\n            {\n                oa->write_character(to_char_type('U'));  // uint8\n            }\n            write_number(static_cast<uint8_t>(n));\n        }\n        else if ((std::numeric_limits<int16_t>::min)() <= n and n <= (std::numeric_limits<int16_t>::max)())\n        {\n            if (add_prefix)\n            {\n                oa->write_character(to_char_type('I'));  // int16\n            }\n            write_number(static_cast<int16_t>(n));\n        }\n        else if ((std::numeric_limits<int32_t>::min)() <= n and n <= (std::numeric_limits<int32_t>::max)())\n        {\n            if (add_prefix)\n            {\n                oa->write_character(to_char_type('l'));  // int32\n            }\n            write_number(static_cast<int32_t>(n));\n        }\n        else if ((std::numeric_limits<int64_t>::min)() <= n and n <= (std::numeric_limits<int64_t>::max)())\n        {\n            if (add_prefix)\n            {\n                oa->write_character(to_char_type('L'));  // int64\n            }\n            write_number(static_cast<int64_t>(n));\n        }\n        // LCOV_EXCL_START\n        else\n        {\n            JSON_THROW(out_of_range::create(407, \"integer number \" + std::to_string(n) + \" cannot be represented by UBJSON as it does not fit int64\"));\n        }\n        // LCOV_EXCL_STOP\n    }\n\n    /*!\n    @brief determine the type prefix of container values\n\n    @note This function does not need to be 100% accurate when it comes to\n          integer limits. In case a number exceeds the limits of int64_t,\n          this will be detected by a later call to function\n          write_number_with_ubjson_prefix. Therefore, we return 'L' for any\n          value that does not fit the previous limits.\n    */\n    CharType ubjson_prefix(const BasicJsonType& j) const noexcept\n    {\n        switch (j.type())\n        {\n            case value_t::null:\n                return 'Z';\n\n            case value_t::boolean:\n                return j.m_value.boolean ? 'T' : 'F';\n\n            case value_t::number_integer:\n            {\n                if ((std::numeric_limits<int8_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<int8_t>::max)())\n                {\n                    return 'i';\n                }\n                if ((std::numeric_limits<uint8_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<uint8_t>::max)())\n                {\n                    return 'U';\n                }\n                if ((std::numeric_limits<int16_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<int16_t>::max)())\n                {\n                    return 'I';\n                }\n                if ((std::numeric_limits<int32_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<int32_t>::max)())\n                {\n                    return 'l';\n                }\n                // no check and assume int64_t (see note above)\n                return 'L';\n            }\n\n            case value_t::number_unsigned:\n            {\n                if (j.m_value.number_unsigned <= (std::numeric_limits<int8_t>::max)())\n                {\n                    return 'i';\n                }\n                if (j.m_value.number_unsigned <= (std::numeric_limits<uint8_t>::max)())\n                {\n                    return 'U';\n                }\n                if (j.m_value.number_unsigned <= (std::numeric_limits<int16_t>::max)())\n                {\n                    return 'I';\n                }\n                if (j.m_value.number_unsigned <= (std::numeric_limits<int32_t>::max)())\n                {\n                    return 'l';\n                }\n                // no check and assume int64_t (see note above)\n                return 'L';\n            }\n\n            case value_t::number_float:\n                return get_ubjson_float_prefix(j.m_value.number_float);\n\n            case value_t::string:\n                return 'S';\n\n            case value_t::array:\n                return '[';\n\n            case value_t::object:\n                return '{';\n\n            default:  // discarded values\n                return 'N';\n        }\n    }\n\n    static constexpr CharType get_ubjson_float_prefix(float /*unused*/)\n    {\n        return 'd';  // float 32\n    }\n\n    static constexpr CharType get_ubjson_float_prefix(double /*unused*/)\n    {\n        return 'D';  // float 64\n    }\n\n    ///////////////////////\n    // Utility functions //\n    ///////////////////////\n\n    /*\n    @brief write a number to output input\n    @param[in] n number of type @a NumberType\n    @tparam NumberType the type of the number\n    @tparam OutputIsLittleEndian Set to true if output data is\n                                 required to be little endian\n\n    @note This function needs to respect the system's endianess, because bytes\n          in CBOR, MessagePack, and UBJSON are stored in network order (big\n          endian) and therefore need reordering on little endian systems.\n    */\n    template<typename NumberType, bool OutputIsLittleEndian = false>\n    void write_number(const NumberType n)\n    {\n        // step 1: write number to array of length NumberType\n        std::array<CharType, sizeof(NumberType)> vec;\n        std::memcpy(vec.data(), &n, sizeof(NumberType));\n\n        // step 2: write array to output (with possible reordering)\n        if (is_little_endian and not OutputIsLittleEndian)\n        {\n            // reverse byte order prior to conversion if necessary\n            std::reverse(vec.begin(), vec.end());\n        }\n\n        oa->write_characters(vec.data(), sizeof(NumberType));\n    }\n\n  public:\n    // The following to_char_type functions are implement the conversion\n    // between uint8_t and CharType. In case CharType is not unsigned,\n    // such a conversion is required to allow values greater than 128.\n    // See <https://github.com/nlohmann/json/issues/1286> for a discussion.\n    template < typename C = CharType,\n               enable_if_t < std::is_signed<C>::value and std::is_signed<char>::value > * = nullptr >\n    static constexpr CharType to_char_type(std::uint8_t x) noexcept\n    {\n        return *reinterpret_cast<char*>(&x);\n    }\n\n    template < typename C = CharType,\n               enable_if_t < std::is_signed<C>::value and std::is_unsigned<char>::value > * = nullptr >\n    static CharType to_char_type(std::uint8_t x) noexcept\n    {\n        static_assert(sizeof(std::uint8_t) == sizeof(CharType), \"size of CharType must be equal to std::uint8_t\");\n        static_assert(std::is_pod<CharType>::value, \"CharType must be POD\");\n        CharType result;\n        std::memcpy(&result, &x, sizeof(x));\n        return result;\n    }\n\n    template<typename C = CharType,\n             enable_if_t<std::is_unsigned<C>::value>* = nullptr>\n    static constexpr CharType to_char_type(std::uint8_t x) noexcept\n    {\n        return x;\n    }\n\n    template < typename InputCharType, typename C = CharType,\n               enable_if_t <\n                   std::is_signed<C>::value and\n                   std::is_signed<char>::value and\n                   std::is_same<char, typename std::remove_cv<InputCharType>::type>::value\n                   > * = nullptr >\n    static constexpr CharType to_char_type(InputCharType x) noexcept\n    {\n        return x;\n    }\n\n  private:\n    /// whether we can assume little endianess\n    const bool is_little_endian = binary_reader<BasicJsonType>::little_endianess();\n\n    /// the output\n    output_adapter_t<CharType> oa = nullptr;\n};\n}  // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/output/serializer.hpp>\n\n\n#include <algorithm> // reverse, remove, fill, find, none_of\n#include <array> // array\n#include <cassert> // assert\n#include <ciso646> // and, or\n#include <clocale> // localeconv, lconv\n#include <cmath> // labs, isfinite, isnan, signbit\n#include <cstddef> // size_t, ptrdiff_t\n#include <cstdint> // uint8_t\n#include <cstdio> // snprintf\n#include <limits> // numeric_limits\n#include <string> // string\n#include <type_traits> // is_same\n\n// #include <nlohmann/detail/exceptions.hpp>\n\n// #include <nlohmann/detail/conversions/to_chars.hpp>\n\n\n#include <cassert> // assert\n#include <ciso646> // or, and, not\n#include <cmath>   // signbit, isfinite\n#include <cstdint> // intN_t, uintN_t\n#include <cstring> // memcpy, memmove\n\nnamespace nlohmann\n{\nnamespace detail\n{\n\n/*!\n@brief implements the Grisu2 algorithm for binary to decimal floating-point\nconversion.\n\nThis implementation is a slightly modified version of the reference\nimplementation which may be obtained from\nhttp://florian.loitsch.com/publications (bench.tar.gz).\n\nThe code is distributed under the MIT license, Copyright (c) 2009 Florian Loitsch.\n\nFor a detailed description of the algorithm see:\n\n[1] Loitsch, \"Printing Floating-Point Numbers Quickly and Accurately with\n    Integers\", Proceedings of the ACM SIGPLAN 2010 Conference on Programming\n    Language Design and Implementation, PLDI 2010\n[2] Burger, Dybvig, \"Printing Floating-Point Numbers Quickly and Accurately\",\n    Proceedings of the ACM SIGPLAN 1996 Conference on Programming Language\n    Design and Implementation, PLDI 1996\n*/\nnamespace dtoa_impl\n{\n\ntemplate <typename Target, typename Source>\nTarget reinterpret_bits(const Source source)\n{\n    static_assert(sizeof(Target) == sizeof(Source), \"size mismatch\");\n\n    Target target;\n    std::memcpy(&target, &source, sizeof(Source));\n    return target;\n}\n\nstruct diyfp // f * 2^e\n{\n    static constexpr int kPrecision = 64; // = q\n\n    uint64_t f = 0;\n    int e = 0;\n\n    constexpr diyfp(uint64_t f_, int e_) noexcept : f(f_), e(e_) {}\n\n    /*!\n    @brief returns x - y\n    @pre x.e == y.e and x.f >= y.f\n    */\n    static diyfp sub(const diyfp& x, const diyfp& y) noexcept\n    {\n        assert(x.e == y.e);\n        assert(x.f >= y.f);\n\n        return {x.f - y.f, x.e};\n    }\n\n    /*!\n    @brief returns x * y\n    @note The result is rounded. (Only the upper q bits are returned.)\n    */\n    static diyfp mul(const diyfp& x, const diyfp& y) noexcept\n    {\n        static_assert(kPrecision == 64, \"internal error\");\n\n        // Computes:\n        //  f = round((x.f * y.f) / 2^q)\n        //  e = x.e + y.e + q\n\n        // Emulate the 64-bit * 64-bit multiplication:\n        //\n        // p = u * v\n        //   = (u_lo + 2^32 u_hi) (v_lo + 2^32 v_hi)\n        //   = (u_lo v_lo         ) + 2^32 ((u_lo v_hi         ) + (u_hi v_lo         )) + 2^64 (u_hi v_hi         )\n        //   = (p0                ) + 2^32 ((p1                ) + (p2                )) + 2^64 (p3                )\n        //   = (p0_lo + 2^32 p0_hi) + 2^32 ((p1_lo + 2^32 p1_hi) + (p2_lo + 2^32 p2_hi)) + 2^64 (p3                )\n        //   = (p0_lo             ) + 2^32 (p0_hi + p1_lo + p2_lo                      ) + 2^64 (p1_hi + p2_hi + p3)\n        //   = (p0_lo             ) + 2^32 (Q                                          ) + 2^64 (H                 )\n        //   = (p0_lo             ) + 2^32 (Q_lo + 2^32 Q_hi                           ) + 2^64 (H                 )\n        //\n        // (Since Q might be larger than 2^32 - 1)\n        //\n        //   = (p0_lo + 2^32 Q_lo) + 2^64 (Q_hi + H)\n        //\n        // (Q_hi + H does not overflow a 64-bit int)\n        //\n        //   = p_lo + 2^64 p_hi\n\n        const uint64_t u_lo = x.f & 0xFFFFFFFF;\n        const uint64_t u_hi = x.f >> 32;\n        const uint64_t v_lo = y.f & 0xFFFFFFFF;\n        const uint64_t v_hi = y.f >> 32;\n\n        const uint64_t p0 = u_lo * v_lo;\n        const uint64_t p1 = u_lo * v_hi;\n        const uint64_t p2 = u_hi * v_lo;\n        const uint64_t p3 = u_hi * v_hi;\n\n        const uint64_t p0_hi = p0 >> 32;\n        const uint64_t p1_lo = p1 & 0xFFFFFFFF;\n        const uint64_t p1_hi = p1 >> 32;\n        const uint64_t p2_lo = p2 & 0xFFFFFFFF;\n        const uint64_t p2_hi = p2 >> 32;\n\n        uint64_t Q = p0_hi + p1_lo + p2_lo;\n\n        // The full product might now be computed as\n        //\n        // p_hi = p3 + p2_hi + p1_hi + (Q >> 32)\n        // p_lo = p0_lo + (Q << 32)\n        //\n        // But in this particular case here, the full p_lo is not required.\n        // Effectively we only need to add the highest bit in p_lo to p_hi (and\n        // Q_hi + 1 does not overflow).\n\n        Q += uint64_t{1} << (64 - 32 - 1); // round, ties up\n\n        const uint64_t h = p3 + p2_hi + p1_hi + (Q >> 32);\n\n        return {h, x.e + y.e + 64};\n    }\n\n    /*!\n    @brief normalize x such that the significand is >= 2^(q-1)\n    @pre x.f != 0\n    */\n    static diyfp normalize(diyfp x) noexcept\n    {\n        assert(x.f != 0);\n\n        while ((x.f >> 63) == 0)\n        {\n            x.f <<= 1;\n            x.e--;\n        }\n\n        return x;\n    }\n\n    /*!\n    @brief normalize x such that the result has the exponent E\n    @pre e >= x.e and the upper e - x.e bits of x.f must be zero.\n    */\n    static diyfp normalize_to(const diyfp& x, const int target_exponent) noexcept\n    {\n        const int delta = x.e - target_exponent;\n\n        assert(delta >= 0);\n        assert(((x.f << delta) >> delta) == x.f);\n\n        return {x.f << delta, target_exponent};\n    }\n};\n\nstruct boundaries\n{\n    diyfp w;\n    diyfp minus;\n    diyfp plus;\n};\n\n/*!\nCompute the (normalized) diyfp representing the input number 'value' and its\nboundaries.\n\n@pre value must be finite and positive\n*/\ntemplate <typename FloatType>\nboundaries compute_boundaries(FloatType value)\n{\n    assert(std::isfinite(value));\n    assert(value > 0);\n\n    // Convert the IEEE representation into a diyfp.\n    //\n    // If v is denormal:\n    //      value = 0.F * 2^(1 - bias) = (          F) * 2^(1 - bias - (p-1))\n    // If v is normalized:\n    //      value = 1.F * 2^(E - bias) = (2^(p-1) + F) * 2^(E - bias - (p-1))\n\n    static_assert(std::numeric_limits<FloatType>::is_iec559,\n                  \"internal error: dtoa_short requires an IEEE-754 floating-point implementation\");\n\n    constexpr int      kPrecision = std::numeric_limits<FloatType>::digits; // = p (includes the hidden bit)\n    constexpr int      kBias      = std::numeric_limits<FloatType>::max_exponent - 1 + (kPrecision - 1);\n    constexpr int      kMinExp    = 1 - kBias;\n    constexpr uint64_t kHiddenBit = uint64_t{1} << (kPrecision - 1); // = 2^(p-1)\n\n    using bits_type = typename std::conditional< kPrecision == 24, uint32_t, uint64_t >::type;\n\n    const uint64_t bits = reinterpret_bits<bits_type>(value);\n    const uint64_t E = bits >> (kPrecision - 1);\n    const uint64_t F = bits & (kHiddenBit - 1);\n\n    const bool is_denormal = (E == 0);\n    const diyfp v = is_denormal\n                    ? diyfp(F, kMinExp)\n                    : diyfp(F + kHiddenBit, static_cast<int>(E) - kBias);\n\n    // Compute the boundaries m- and m+ of the floating-point value\n    // v = f * 2^e.\n    //\n    // Determine v- and v+, the floating-point predecessor and successor if v,\n    // respectively.\n    //\n    //      v- = v - 2^e        if f != 2^(p-1) or e == e_min                (A)\n    //         = v - 2^(e-1)    if f == 2^(p-1) and e > e_min                (B)\n    //\n    //      v+ = v + 2^e\n    //\n    // Let m- = (v- + v) / 2 and m+ = (v + v+) / 2. All real numbers _strictly_\n    // between m- and m+ round to v, regardless of how the input rounding\n    // algorithm breaks ties.\n    //\n    //      ---+-------------+-------------+-------------+-------------+---  (A)\n    //         v-            m-            v             m+            v+\n    //\n    //      -----------------+------+------+-------------+-------------+---  (B)\n    //                       v-     m-     v             m+            v+\n\n    const bool lower_boundary_is_closer = (F == 0 and E > 1);\n    const diyfp m_plus = diyfp(2 * v.f + 1, v.e - 1);\n    const diyfp m_minus = lower_boundary_is_closer\n                          ? diyfp(4 * v.f - 1, v.e - 2)  // (B)\n                          : diyfp(2 * v.f - 1, v.e - 1); // (A)\n\n    // Determine the normalized w+ = m+.\n    const diyfp w_plus = diyfp::normalize(m_plus);\n\n    // Determine w- = m- such that e_(w-) = e_(w+).\n    const diyfp w_minus = diyfp::normalize_to(m_minus, w_plus.e);\n\n    return {diyfp::normalize(v), w_minus, w_plus};\n}\n\n// Given normalized diyfp w, Grisu needs to find a (normalized) cached\n// power-of-ten c, such that the exponent of the product c * w = f * 2^e lies\n// within a certain range [alpha, gamma] (Definition 3.2 from [1])\n//\n//      alpha <= e = e_c + e_w + q <= gamma\n//\n// or\n//\n//      f_c * f_w * 2^alpha <= f_c 2^(e_c) * f_w 2^(e_w) * 2^q\n//                          <= f_c * f_w * 2^gamma\n//\n// Since c and w are normalized, i.e. 2^(q-1) <= f < 2^q, this implies\n//\n//      2^(q-1) * 2^(q-1) * 2^alpha <= c * w * 2^q < 2^q * 2^q * 2^gamma\n//\n// or\n//\n//      2^(q - 2 + alpha) <= c * w < 2^(q + gamma)\n//\n// The choice of (alpha,gamma) determines the size of the table and the form of\n// the digit generation procedure. Using (alpha,gamma)=(-60,-32) works out well\n// in practice:\n//\n// The idea is to cut the number c * w = f * 2^e into two parts, which can be\n// processed independently: An integral part p1, and a fractional part p2:\n//\n//      f * 2^e = ( (f div 2^-e) * 2^-e + (f mod 2^-e) ) * 2^e\n//              = (f div 2^-e) + (f mod 2^-e) * 2^e\n//              = p1 + p2 * 2^e\n//\n// The conversion of p1 into decimal form requires a series of divisions and\n// modulos by (a power of) 10. These operations are faster for 32-bit than for\n// 64-bit integers, so p1 should ideally fit into a 32-bit integer. This can be\n// achieved by choosing\n//\n//      -e >= 32   or   e <= -32 := gamma\n//\n// In order to convert the fractional part\n//\n//      p2 * 2^e = p2 / 2^-e = d[-1] / 10^1 + d[-2] / 10^2 + ...\n//\n// into decimal form, the fraction is repeatedly multiplied by 10 and the digits\n// d[-i] are extracted in order:\n//\n//      (10 * p2) div 2^-e = d[-1]\n//      (10 * p2) mod 2^-e = d[-2] / 10^1 + ...\n//\n// The multiplication by 10 must not overflow. It is sufficient to choose\n//\n//      10 * p2 < 16 * p2 = 2^4 * p2 <= 2^64.\n//\n// Since p2 = f mod 2^-e < 2^-e,\n//\n//      -e <= 60   or   e >= -60 := alpha\n\nconstexpr int kAlpha = -60;\nconstexpr int kGamma = -32;\n\nstruct cached_power // c = f * 2^e ~= 10^k\n{\n    uint64_t f;\n    int e;\n    int k;\n};\n\n/*!\nFor a normalized diyfp w = f * 2^e, this function returns a (normalized) cached\npower-of-ten c = f_c * 2^e_c, such that the exponent of the product w * c\nsatisfies (Definition 3.2 from [1])\n\n     alpha <= e_c + e + q <= gamma.\n*/\ninline cached_power get_cached_power_for_binary_exponent(int e)\n{\n    // Now\n    //\n    //      alpha <= e_c + e + q <= gamma                                    (1)\n    //      ==> f_c * 2^alpha <= c * 2^e * 2^q\n    //\n    // and since the c's are normalized, 2^(q-1) <= f_c,\n    //\n    //      ==> 2^(q - 1 + alpha) <= c * 2^(e + q)\n    //      ==> 2^(alpha - e - 1) <= c\n    //\n    // If c were an exakt power of ten, i.e. c = 10^k, one may determine k as\n    //\n    //      k = ceil( log_10( 2^(alpha - e - 1) ) )\n    //        = ceil( (alpha - e - 1) * log_10(2) )\n    //\n    // From the paper:\n    // \"In theory the result of the procedure could be wrong since c is rounded,\n    //  and the computation itself is approximated [...]. In practice, however,\n    //  this simple function is sufficient.\"\n    //\n    // For IEEE double precision floating-point numbers converted into\n    // normalized diyfp's w = f * 2^e, with q = 64,\n    //\n    //      e >= -1022      (min IEEE exponent)\n    //           -52        (p - 1)\n    //           -52        (p - 1, possibly normalize denormal IEEE numbers)\n    //           -11        (normalize the diyfp)\n    //         = -1137\n    //\n    // and\n    //\n    //      e <= +1023      (max IEEE exponent)\n    //           -52        (p - 1)\n    //           -11        (normalize the diyfp)\n    //         = 960\n    //\n    // This binary exponent range [-1137,960] results in a decimal exponent\n    // range [-307,324]. One does not need to store a cached power for each\n    // k in this range. For each such k it suffices to find a cached power\n    // such that the exponent of the product lies in [alpha,gamma].\n    // This implies that the difference of the decimal exponents of adjacent\n    // table entries must be less than or equal to\n    //\n    //      floor( (gamma - alpha) * log_10(2) ) = 8.\n    //\n    // (A smaller distance gamma-alpha would require a larger table.)\n\n    // NB:\n    // Actually this function returns c, such that -60 <= e_c + e + 64 <= -34.\n\n    constexpr int kCachedPowersSize = 79;\n    constexpr int kCachedPowersMinDecExp = -300;\n    constexpr int kCachedPowersDecStep = 8;\n\n    static constexpr cached_power kCachedPowers[] =\n    {\n        { 0xAB70FE17C79AC6CA, -1060, -300 },\n        { 0xFF77B1FCBEBCDC4F, -1034, -292 },\n        { 0xBE5691EF416BD60C, -1007, -284 },\n        { 0x8DD01FAD907FFC3C,  -980, -276 },\n        { 0xD3515C2831559A83,  -954, -268 },\n        { 0x9D71AC8FADA6C9B5,  -927, -260 },\n        { 0xEA9C227723EE8BCB,  -901, -252 },\n        { 0xAECC49914078536D,  -874, -244 },\n        { 0x823C12795DB6CE57,  -847, -236 },\n        { 0xC21094364DFB5637,  -821, -228 },\n        { 0x9096EA6F3848984F,  -794, -220 },\n        { 0xD77485CB25823AC7,  -768, -212 },\n        { 0xA086CFCD97BF97F4,  -741, -204 },\n        { 0xEF340A98172AACE5,  -715, -196 },\n        { 0xB23867FB2A35B28E,  -688, -188 },\n        { 0x84C8D4DFD2C63F3B,  -661, -180 },\n        { 0xC5DD44271AD3CDBA,  -635, -172 },\n        { 0x936B9FCEBB25C996,  -608, -164 },\n        { 0xDBAC6C247D62A584,  -582, -156 },\n        { 0xA3AB66580D5FDAF6,  -555, -148 },\n        { 0xF3E2F893DEC3F126,  -529, -140 },\n        { 0xB5B5ADA8AAFF80B8,  -502, -132 },\n        { 0x87625F056C7C4A8B,  -475, -124 },\n        { 0xC9BCFF6034C13053,  -449, -116 },\n        { 0x964E858C91BA2655,  -422, -108 },\n        { 0xDFF9772470297EBD,  -396, -100 },\n        { 0xA6DFBD9FB8E5B88F,  -369,  -92 },\n        { 0xF8A95FCF88747D94,  -343,  -84 },\n        { 0xB94470938FA89BCF,  -316,  -76 },\n        { 0x8A08F0F8BF0F156B,  -289,  -68 },\n        { 0xCDB02555653131B6,  -263,  -60 },\n        { 0x993FE2C6D07B7FAC,  -236,  -52 },\n        { 0xE45C10C42A2B3B06,  -210,  -44 },\n        { 0xAA242499697392D3,  -183,  -36 },\n        { 0xFD87B5F28300CA0E,  -157,  -28 },\n        { 0xBCE5086492111AEB,  -130,  -20 },\n        { 0x8CBCCC096F5088CC,  -103,  -12 },\n        { 0xD1B71758E219652C,   -77,   -4 },\n        { 0x9C40000000000000,   -50,    4 },\n        { 0xE8D4A51000000000,   -24,   12 },\n        { 0xAD78EBC5AC620000,     3,   20 },\n        { 0x813F3978F8940984,    30,   28 },\n        { 0xC097CE7BC90715B3,    56,   36 },\n        { 0x8F7E32CE7BEA5C70,    83,   44 },\n        { 0xD5D238A4ABE98068,   109,   52 },\n        { 0x9F4F2726179A2245,   136,   60 },\n        { 0xED63A231D4C4FB27,   162,   68 },\n        { 0xB0DE65388CC8ADA8,   189,   76 },\n        { 0x83C7088E1AAB65DB,   216,   84 },\n        { 0xC45D1DF942711D9A,   242,   92 },\n        { 0x924D692CA61BE758,   269,  100 },\n        { 0xDA01EE641A708DEA,   295,  108 },\n        { 0xA26DA3999AEF774A,   322,  116 },\n        { 0xF209787BB47D6B85,   348,  124 },\n        { 0xB454E4A179DD1877,   375,  132 },\n        { 0x865B86925B9BC5C2,   402,  140 },\n        { 0xC83553C5C8965D3D,   428,  148 },\n        { 0x952AB45CFA97A0B3,   455,  156 },\n        { 0xDE469FBD99A05FE3,   481,  164 },\n        { 0xA59BC234DB398C25,   508,  172 },\n        { 0xF6C69A72A3989F5C,   534,  180 },\n        { 0xB7DCBF5354E9BECE,   561,  188 },\n        { 0x88FCF317F22241E2,   588,  196 },\n        { 0xCC20CE9BD35C78A5,   614,  204 },\n        { 0x98165AF37B2153DF,   641,  212 },\n        { 0xE2A0B5DC971F303A,   667,  220 },\n        { 0xA8D9D1535CE3B396,   694,  228 },\n        { 0xFB9B7CD9A4A7443C,   720,  236 },\n        { 0xBB764C4CA7A44410,   747,  244 },\n        { 0x8BAB8EEFB6409C1A,   774,  252 },\n        { 0xD01FEF10A657842C,   800,  260 },\n        { 0x9B10A4E5E9913129,   827,  268 },\n        { 0xE7109BFBA19C0C9D,   853,  276 },\n        { 0xAC2820D9623BF429,   880,  284 },\n        { 0x80444B5E7AA7CF85,   907,  292 },\n        { 0xBF21E44003ACDD2D,   933,  300 },\n        { 0x8E679C2F5E44FF8F,   960,  308 },\n        { 0xD433179D9C8CB841,   986,  316 },\n        { 0x9E19DB92B4E31BA9,  1013,  324 },\n    };\n\n    // This computation gives exactly the same results for k as\n    //      k = ceil((kAlpha - e - 1) * 0.30102999566398114)\n    // for |e| <= 1500, but doesn't require floating-point operations.\n    // NB: log_10(2) ~= 78913 / 2^18\n    assert(e >= -1500);\n    assert(e <=  1500);\n    const int f = kAlpha - e - 1;\n    const int k = (f * 78913) / (1 << 18) + static_cast<int>(f > 0);\n\n    const int index = (-kCachedPowersMinDecExp + k + (kCachedPowersDecStep - 1)) / kCachedPowersDecStep;\n    assert(index >= 0);\n    assert(index < kCachedPowersSize);\n    static_cast<void>(kCachedPowersSize); // Fix warning.\n\n    const cached_power cached = kCachedPowers[index];\n    assert(kAlpha <= cached.e + e + 64);\n    assert(kGamma >= cached.e + e + 64);\n\n    return cached;\n}\n\n/*!\nFor n != 0, returns k, such that pow10 := 10^(k-1) <= n < 10^k.\nFor n == 0, returns 1 and sets pow10 := 1.\n*/\ninline int find_largest_pow10(const uint32_t n, uint32_t& pow10)\n{\n    // LCOV_EXCL_START\n    if (n >= 1000000000)\n    {\n        pow10 = 1000000000;\n        return 10;\n    }\n    // LCOV_EXCL_STOP\n    else if (n >= 100000000)\n    {\n        pow10 = 100000000;\n        return  9;\n    }\n    else if (n >= 10000000)\n    {\n        pow10 = 10000000;\n        return  8;\n    }\n    else if (n >= 1000000)\n    {\n        pow10 = 1000000;\n        return  7;\n    }\n    else if (n >= 100000)\n    {\n        pow10 = 100000;\n        return  6;\n    }\n    else if (n >= 10000)\n    {\n        pow10 = 10000;\n        return  5;\n    }\n    else if (n >= 1000)\n    {\n        pow10 = 1000;\n        return  4;\n    }\n    else if (n >= 100)\n    {\n        pow10 = 100;\n        return  3;\n    }\n    else if (n >= 10)\n    {\n        pow10 = 10;\n        return  2;\n    }\n    else\n    {\n        pow10 = 1;\n        return 1;\n    }\n}\n\ninline void grisu2_round(char* buf, int len, uint64_t dist, uint64_t delta,\n                         uint64_t rest, uint64_t ten_k)\n{\n    assert(len >= 1);\n    assert(dist <= delta);\n    assert(rest <= delta);\n    assert(ten_k > 0);\n\n    //               <--------------------------- delta ---->\n    //                                  <---- dist --------->\n    // --------------[------------------+-------------------]--------------\n    //               M-                 w                   M+\n    //\n    //                                  ten_k\n    //                                <------>\n    //                                       <---- rest ---->\n    // --------------[------------------+----+--------------]--------------\n    //                                  w    V\n    //                                       = buf * 10^k\n    //\n    // ten_k represents a unit-in-the-last-place in the decimal representation\n    // stored in buf.\n    // Decrement buf by ten_k while this takes buf closer to w.\n\n    // The tests are written in this order to avoid overflow in unsigned\n    // integer arithmetic.\n\n    while (rest < dist\n            and delta - rest >= ten_k\n            and (rest + ten_k < dist or dist - rest > rest + ten_k - dist))\n    {\n        assert(buf[len - 1] != '0');\n        buf[len - 1]--;\n        rest += ten_k;\n    }\n}\n\n/*!\nGenerates V = buffer * 10^decimal_exponent, such that M- <= V <= M+.\nM- and M+ must be normalized and share the same exponent -60 <= e <= -32.\n*/\ninline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent,\n                             diyfp M_minus, diyfp w, diyfp M_plus)\n{\n    static_assert(kAlpha >= -60, \"internal error\");\n    static_assert(kGamma <= -32, \"internal error\");\n\n    // Generates the digits (and the exponent) of a decimal floating-point\n    // number V = buffer * 10^decimal_exponent in the range [M-, M+]. The diyfp's\n    // w, M- and M+ share the same exponent e, which satisfies alpha <= e <= gamma.\n    //\n    //               <--------------------------- delta ---->\n    //                                  <---- dist --------->\n    // --------------[------------------+-------------------]--------------\n    //               M-                 w                   M+\n    //\n    // Grisu2 generates the digits of M+ from left to right and stops as soon as\n    // V is in [M-,M+].\n\n    assert(M_plus.e >= kAlpha);\n    assert(M_plus.e <= kGamma);\n\n    uint64_t delta = diyfp::sub(M_plus, M_minus).f; // (significand of (M+ - M-), implicit exponent is e)\n    uint64_t dist  = diyfp::sub(M_plus, w      ).f; // (significand of (M+ - w ), implicit exponent is e)\n\n    // Split M+ = f * 2^e into two parts p1 and p2 (note: e < 0):\n    //\n    //      M+ = f * 2^e\n    //         = ((f div 2^-e) * 2^-e + (f mod 2^-e)) * 2^e\n    //         = ((p1        ) * 2^-e + (p2        )) * 2^e\n    //         = p1 + p2 * 2^e\n\n    const diyfp one(uint64_t{1} << -M_plus.e, M_plus.e);\n\n    auto p1 = static_cast<uint32_t>(M_plus.f >> -one.e); // p1 = f div 2^-e (Since -e >= 32, p1 fits into a 32-bit int.)\n    uint64_t p2 = M_plus.f & (one.f - 1);                    // p2 = f mod 2^-e\n\n    // 1)\n    //\n    // Generate the digits of the integral part p1 = d[n-1]...d[1]d[0]\n\n    assert(p1 > 0);\n\n    uint32_t pow10;\n    const int k = find_largest_pow10(p1, pow10);\n\n    //      10^(k-1) <= p1 < 10^k, pow10 = 10^(k-1)\n    //\n    //      p1 = (p1 div 10^(k-1)) * 10^(k-1) + (p1 mod 10^(k-1))\n    //         = (d[k-1]         ) * 10^(k-1) + (p1 mod 10^(k-1))\n    //\n    //      M+ = p1                                             + p2 * 2^e\n    //         = d[k-1] * 10^(k-1) + (p1 mod 10^(k-1))          + p2 * 2^e\n    //         = d[k-1] * 10^(k-1) + ((p1 mod 10^(k-1)) * 2^-e + p2) * 2^e\n    //         = d[k-1] * 10^(k-1) + (                         rest) * 2^e\n    //\n    // Now generate the digits d[n] of p1 from left to right (n = k-1,...,0)\n    //\n    //      p1 = d[k-1]...d[n] * 10^n + d[n-1]...d[0]\n    //\n    // but stop as soon as\n    //\n    //      rest * 2^e = (d[n-1]...d[0] * 2^-e + p2) * 2^e <= delta * 2^e\n\n    int n = k;\n    while (n > 0)\n    {\n        // Invariants:\n        //      M+ = buffer * 10^n + (p1 + p2 * 2^e)    (buffer = 0 for n = k)\n        //      pow10 = 10^(n-1) <= p1 < 10^n\n        //\n        const uint32_t d = p1 / pow10;  // d = p1 div 10^(n-1)\n        const uint32_t r = p1 % pow10;  // r = p1 mod 10^(n-1)\n        //\n        //      M+ = buffer * 10^n + (d * 10^(n-1) + r) + p2 * 2^e\n        //         = (buffer * 10 + d) * 10^(n-1) + (r + p2 * 2^e)\n        //\n        assert(d <= 9);\n        buffer[length++] = static_cast<char>('0' + d); // buffer := buffer * 10 + d\n        //\n        //      M+ = buffer * 10^(n-1) + (r + p2 * 2^e)\n        //\n        p1 = r;\n        n--;\n        //\n        //      M+ = buffer * 10^n + (p1 + p2 * 2^e)\n        //      pow10 = 10^n\n        //\n\n        // Now check if enough digits have been generated.\n        // Compute\n        //\n        //      p1 + p2 * 2^e = (p1 * 2^-e + p2) * 2^e = rest * 2^e\n        //\n        // Note:\n        // Since rest and delta share the same exponent e, it suffices to\n        // compare the significands.\n        const uint64_t rest = (uint64_t{p1} << -one.e) + p2;\n        if (rest <= delta)\n        {\n            // V = buffer * 10^n, with M- <= V <= M+.\n\n            decimal_exponent += n;\n\n            // We may now just stop. But instead look if the buffer could be\n            // decremented to bring V closer to w.\n            //\n            // pow10 = 10^n is now 1 ulp in the decimal representation V.\n            // The rounding procedure works with diyfp's with an implicit\n            // exponent of e.\n            //\n            //      10^n = (10^n * 2^-e) * 2^e = ulp * 2^e\n            //\n            const uint64_t ten_n = uint64_t{pow10} << -one.e;\n            grisu2_round(buffer, length, dist, delta, rest, ten_n);\n\n            return;\n        }\n\n        pow10 /= 10;\n        //\n        //      pow10 = 10^(n-1) <= p1 < 10^n\n        // Invariants restored.\n    }\n\n    // 2)\n    //\n    // The digits of the integral part have been generated:\n    //\n    //      M+ = d[k-1]...d[1]d[0] + p2 * 2^e\n    //         = buffer            + p2 * 2^e\n    //\n    // Now generate the digits of the fractional part p2 * 2^e.\n    //\n    // Note:\n    // No decimal point is generated: the exponent is adjusted instead.\n    //\n    // p2 actually represents the fraction\n    //\n    //      p2 * 2^e\n    //          = p2 / 2^-e\n    //          = d[-1] / 10^1 + d[-2] / 10^2 + ...\n    //\n    // Now generate the digits d[-m] of p1 from left to right (m = 1,2,...)\n    //\n    //      p2 * 2^e = d[-1]d[-2]...d[-m] * 10^-m\n    //                      + 10^-m * (d[-m-1] / 10^1 + d[-m-2] / 10^2 + ...)\n    //\n    // using\n    //\n    //      10^m * p2 = ((10^m * p2) div 2^-e) * 2^-e + ((10^m * p2) mod 2^-e)\n    //                = (                   d) * 2^-e + (                   r)\n    //\n    // or\n    //      10^m * p2 * 2^e = d + r * 2^e\n    //\n    // i.e.\n    //\n    //      M+ = buffer + p2 * 2^e\n    //         = buffer + 10^-m * (d + r * 2^e)\n    //         = (buffer * 10^m + d) * 10^-m + 10^-m * r * 2^e\n    //\n    // and stop as soon as 10^-m * r * 2^e <= delta * 2^e\n\n    assert(p2 > delta);\n\n    int m = 0;\n    for (;;)\n    {\n        // Invariant:\n        //      M+ = buffer * 10^-m + 10^-m * (d[-m-1] / 10 + d[-m-2] / 10^2 + ...) * 2^e\n        //         = buffer * 10^-m + 10^-m * (p2                                 ) * 2^e\n        //         = buffer * 10^-m + 10^-m * (1/10 * (10 * p2)                   ) * 2^e\n        //         = buffer * 10^-m + 10^-m * (1/10 * ((10*p2 div 2^-e) * 2^-e + (10*p2 mod 2^-e)) * 2^e\n        //\n        assert(p2 <= UINT64_MAX / 10);\n        p2 *= 10;\n        const uint64_t d = p2 >> -one.e;     // d = (10 * p2) div 2^-e\n        const uint64_t r = p2 & (one.f - 1); // r = (10 * p2) mod 2^-e\n        //\n        //      M+ = buffer * 10^-m + 10^-m * (1/10 * (d * 2^-e + r) * 2^e\n        //         = buffer * 10^-m + 10^-m * (1/10 * (d + r * 2^e))\n        //         = (buffer * 10 + d) * 10^(-m-1) + 10^(-m-1) * r * 2^e\n        //\n        assert(d <= 9);\n        buffer[length++] = static_cast<char>('0' + d); // buffer := buffer * 10 + d\n        //\n        //      M+ = buffer * 10^(-m-1) + 10^(-m-1) * r * 2^e\n        //\n        p2 = r;\n        m++;\n        //\n        //      M+ = buffer * 10^-m + 10^-m * p2 * 2^e\n        // Invariant restored.\n\n        // Check if enough digits have been generated.\n        //\n        //      10^-m * p2 * 2^e <= delta * 2^e\n        //              p2 * 2^e <= 10^m * delta * 2^e\n        //                    p2 <= 10^m * delta\n        delta *= 10;\n        dist  *= 10;\n        if (p2 <= delta)\n        {\n            break;\n        }\n    }\n\n    // V = buffer * 10^-m, with M- <= V <= M+.\n\n    decimal_exponent -= m;\n\n    // 1 ulp in the decimal representation is now 10^-m.\n    // Since delta and dist are now scaled by 10^m, we need to do the\n    // same with ulp in order to keep the units in sync.\n    //\n    //      10^m * 10^-m = 1 = 2^-e * 2^e = ten_m * 2^e\n    //\n    const uint64_t ten_m = one.f;\n    grisu2_round(buffer, length, dist, delta, p2, ten_m);\n\n    // By construction this algorithm generates the shortest possible decimal\n    // number (Loitsch, Theorem 6.2) which rounds back to w.\n    // For an input number of precision p, at least\n    //\n    //      N = 1 + ceil(p * log_10(2))\n    //\n    // decimal digits are sufficient to identify all binary floating-point\n    // numbers (Matula, \"In-and-Out conversions\").\n    // This implies that the algorithm does not produce more than N decimal\n    // digits.\n    //\n    //      N = 17 for p = 53 (IEEE double precision)\n    //      N = 9  for p = 24 (IEEE single precision)\n}\n\n/*!\nv = buf * 10^decimal_exponent\nlen is the length of the buffer (number of decimal digits)\nThe buffer must be large enough, i.e. >= max_digits10.\n*/\ninline void grisu2(char* buf, int& len, int& decimal_exponent,\n                   diyfp m_minus, diyfp v, diyfp m_plus)\n{\n    assert(m_plus.e == m_minus.e);\n    assert(m_plus.e == v.e);\n\n    //  --------(-----------------------+-----------------------)--------    (A)\n    //          m-                      v                       m+\n    //\n    //  --------------------(-----------+-----------------------)--------    (B)\n    //                      m-          v                       m+\n    //\n    // First scale v (and m- and m+) such that the exponent is in the range\n    // [alpha, gamma].\n\n    const cached_power cached = get_cached_power_for_binary_exponent(m_plus.e);\n\n    const diyfp c_minus_k(cached.f, cached.e); // = c ~= 10^-k\n\n    // The exponent of the products is = v.e + c_minus_k.e + q and is in the range [alpha,gamma]\n    const diyfp w       = diyfp::mul(v,       c_minus_k);\n    const diyfp w_minus = diyfp::mul(m_minus, c_minus_k);\n    const diyfp w_plus  = diyfp::mul(m_plus,  c_minus_k);\n\n    //  ----(---+---)---------------(---+---)---------------(---+---)----\n    //          w-                      w                       w+\n    //          = c*m-                  = c*v                   = c*m+\n    //\n    // diyfp::mul rounds its result and c_minus_k is approximated too. w, w- and\n    // w+ are now off by a small amount.\n    // In fact:\n    //\n    //      w - v * 10^k < 1 ulp\n    //\n    // To account for this inaccuracy, add resp. subtract 1 ulp.\n    //\n    //  --------+---[---------------(---+---)---------------]---+--------\n    //          w-  M-                  w                   M+  w+\n    //\n    // Now any number in [M-, M+] (bounds included) will round to w when input,\n    // regardless of how the input rounding algorithm breaks ties.\n    //\n    // And digit_gen generates the shortest possible such number in [M-, M+].\n    // Note that this does not mean that Grisu2 always generates the shortest\n    // possible number in the interval (m-, m+).\n    const diyfp M_minus(w_minus.f + 1, w_minus.e);\n    const diyfp M_plus (w_plus.f  - 1, w_plus.e );\n\n    decimal_exponent = -cached.k; // = -(-k) = k\n\n    grisu2_digit_gen(buf, len, decimal_exponent, M_minus, w, M_plus);\n}\n\n/*!\nv = buf * 10^decimal_exponent\nlen is the length of the buffer (number of decimal digits)\nThe buffer must be large enough, i.e. >= max_digits10.\n*/\ntemplate <typename FloatType>\nvoid grisu2(char* buf, int& len, int& decimal_exponent, FloatType value)\n{\n    static_assert(diyfp::kPrecision >= std::numeric_limits<FloatType>::digits + 3,\n                  \"internal error: not enough precision\");\n\n    assert(std::isfinite(value));\n    assert(value > 0);\n\n    // If the neighbors (and boundaries) of 'value' are always computed for double-precision\n    // numbers, all float's can be recovered using strtod (and strtof). However, the resulting\n    // decimal representations are not exactly \"short\".\n    //\n    // The documentation for 'std::to_chars' (https://en.cppreference.com/w/cpp/utility/to_chars)\n    // says \"value is converted to a string as if by std::sprintf in the default (\"C\") locale\"\n    // and since sprintf promotes float's to double's, I think this is exactly what 'std::to_chars'\n    // does.\n    // On the other hand, the documentation for 'std::to_chars' requires that \"parsing the\n    // representation using the corresponding std::from_chars function recovers value exactly\". That\n    // indicates that single precision floating-point numbers should be recovered using\n    // 'std::strtof'.\n    //\n    // NB: If the neighbors are computed for single-precision numbers, there is a single float\n    //     (7.0385307e-26f) which can't be recovered using strtod. The resulting double precision\n    //     value is off by 1 ulp.\n#if 0\n    const boundaries w = compute_boundaries(static_cast<double>(value));\n#else\n    const boundaries w = compute_boundaries(value);\n#endif\n\n    grisu2(buf, len, decimal_exponent, w.minus, w.w, w.plus);\n}\n\n/*!\n@brief appends a decimal representation of e to buf\n@return a pointer to the element following the exponent.\n@pre -1000 < e < 1000\n*/\ninline char* append_exponent(char* buf, int e)\n{\n    assert(e > -1000);\n    assert(e <  1000);\n\n    if (e < 0)\n    {\n        e = -e;\n        *buf++ = '-';\n    }\n    else\n    {\n        *buf++ = '+';\n    }\n\n    auto k = static_cast<uint32_t>(e);\n    if (k < 10)\n    {\n        // Always print at least two digits in the exponent.\n        // This is for compatibility with printf(\"%g\").\n        *buf++ = '0';\n        *buf++ = static_cast<char>('0' + k);\n    }\n    else if (k < 100)\n    {\n        *buf++ = static_cast<char>('0' + k / 10);\n        k %= 10;\n        *buf++ = static_cast<char>('0' + k);\n    }\n    else\n    {\n        *buf++ = static_cast<char>('0' + k / 100);\n        k %= 100;\n        *buf++ = static_cast<char>('0' + k / 10);\n        k %= 10;\n        *buf++ = static_cast<char>('0' + k);\n    }\n\n    return buf;\n}\n\n/*!\n@brief prettify v = buf * 10^decimal_exponent\n\nIf v is in the range [10^min_exp, 10^max_exp) it will be printed in fixed-point\nnotation. Otherwise it will be printed in exponential notation.\n\n@pre min_exp < 0\n@pre max_exp > 0\n*/\ninline char* format_buffer(char* buf, int len, int decimal_exponent,\n                           int min_exp, int max_exp)\n{\n    assert(min_exp < 0);\n    assert(max_exp > 0);\n\n    const int k = len;\n    const int n = len + decimal_exponent;\n\n    // v = buf * 10^(n-k)\n    // k is the length of the buffer (number of decimal digits)\n    // n is the position of the decimal point relative to the start of the buffer.\n\n    if (k <= n and n <= max_exp)\n    {\n        // digits[000]\n        // len <= max_exp + 2\n\n        std::memset(buf + k, '0', static_cast<size_t>(n - k));\n        // Make it look like a floating-point number (#362, #378)\n        buf[n + 0] = '.';\n        buf[n + 1] = '0';\n        return buf + (n + 2);\n    }\n\n    if (0 < n and n <= max_exp)\n    {\n        // dig.its\n        // len <= max_digits10 + 1\n\n        assert(k > n);\n\n        std::memmove(buf + (n + 1), buf + n, static_cast<size_t>(k - n));\n        buf[n] = '.';\n        return buf + (k + 1);\n    }\n\n    if (min_exp < n and n <= 0)\n    {\n        // 0.[000]digits\n        // len <= 2 + (-min_exp - 1) + max_digits10\n\n        std::memmove(buf + (2 + -n), buf, static_cast<size_t>(k));\n        buf[0] = '0';\n        buf[1] = '.';\n        std::memset(buf + 2, '0', static_cast<size_t>(-n));\n        return buf + (2 + (-n) + k);\n    }\n\n    if (k == 1)\n    {\n        // dE+123\n        // len <= 1 + 5\n\n        buf += 1;\n    }\n    else\n    {\n        // d.igitsE+123\n        // len <= max_digits10 + 1 + 5\n\n        std::memmove(buf + 2, buf + 1, static_cast<size_t>(k - 1));\n        buf[1] = '.';\n        buf += 1 + k;\n    }\n\n    *buf++ = 'e';\n    return append_exponent(buf, n - 1);\n}\n\n} // namespace dtoa_impl\n\n/*!\n@brief generates a decimal representation of the floating-point number value in [first, last).\n\nThe format of the resulting decimal representation is similar to printf's %g\nformat. Returns an iterator pointing past-the-end of the decimal representation.\n\n@note The input number must be finite, i.e. NaN's and Inf's are not supported.\n@note The buffer must be large enough.\n@note The result is NOT null-terminated.\n*/\ntemplate <typename FloatType>\nchar* to_chars(char* first, const char* last, FloatType value)\n{\n    static_cast<void>(last); // maybe unused - fix warning\n    assert(std::isfinite(value));\n\n    // Use signbit(value) instead of (value < 0) since signbit works for -0.\n    if (std::signbit(value))\n    {\n        value = -value;\n        *first++ = '-';\n    }\n\n    if (value == 0) // +-0\n    {\n        *first++ = '0';\n        // Make it look like a floating-point number (#362, #378)\n        *first++ = '.';\n        *first++ = '0';\n        return first;\n    }\n\n    assert(last - first >= std::numeric_limits<FloatType>::max_digits10);\n\n    // Compute v = buffer * 10^decimal_exponent.\n    // The decimal digits are stored in the buffer, which needs to be interpreted\n    // as an unsigned decimal integer.\n    // len is the length of the buffer, i.e. the number of decimal digits.\n    int len = 0;\n    int decimal_exponent = 0;\n    dtoa_impl::grisu2(first, len, decimal_exponent, value);\n\n    assert(len <= std::numeric_limits<FloatType>::max_digits10);\n\n    // Format the buffer like printf(\"%.*g\", prec, value)\n    constexpr int kMinExp = -4;\n    // Use digits10 here to increase compatibility with version 2.\n    constexpr int kMaxExp = std::numeric_limits<FloatType>::digits10;\n\n    assert(last - first >= kMaxExp + 2);\n    assert(last - first >= 2 + (-kMinExp - 1) + std::numeric_limits<FloatType>::max_digits10);\n    assert(last - first >= std::numeric_limits<FloatType>::max_digits10 + 6);\n\n    return dtoa_impl::format_buffer(first, len, decimal_exponent, kMinExp, kMaxExp);\n}\n\n} // namespace detail\n} // namespace nlohmann\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n// #include <nlohmann/detail/meta/cpp_future.hpp>\n\n// #include <nlohmann/detail/output/binary_writer.hpp>\n\n// #include <nlohmann/detail/output/output_adapters.hpp>\n\n// #include <nlohmann/detail/value_t.hpp>\n\n\nnamespace nlohmann\n{\nnamespace detail\n{\n///////////////////\n// serialization //\n///////////////////\n\n/// how to treat decoding errors\nenum class error_handler_t\n{\n    strict,  ///< throw a type_error exception in case of invalid UTF-8\n    replace, ///< replace invalid UTF-8 sequences with U+FFFD\n    ignore   ///< ignore invalid UTF-8 sequences\n};\n\ntemplate<typename BasicJsonType>\nclass serializer\n{\n    using string_t = typename BasicJsonType::string_t;\n    using number_float_t = typename BasicJsonType::number_float_t;\n    using number_integer_t = typename BasicJsonType::number_integer_t;\n    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n    static constexpr uint8_t UTF8_ACCEPT = 0;\n    static constexpr uint8_t UTF8_REJECT = 1;\n\n  public:\n    /*!\n    @param[in] s  output stream to serialize to\n    @param[in] ichar  indentation character to use\n    @param[in] error_handler_  how to react on decoding errors\n    */\n    serializer(output_adapter_t<char> s, const char ichar,\n               error_handler_t error_handler_ = error_handler_t::strict)\n        : o(std::move(s))\n        , loc(std::localeconv())\n        , thousands_sep(loc->thousands_sep == nullptr ? '\\0' : * (loc->thousands_sep))\n        , decimal_point(loc->decimal_point == nullptr ? '\\0' : * (loc->decimal_point))\n        , indent_char(ichar)\n        , indent_string(512, indent_char)\n        , error_handler(error_handler_)\n    {}\n\n    // delete because of pointer members\n    serializer(const serializer&) = delete;\n    serializer& operator=(const serializer&) = delete;\n    serializer(serializer&&) = delete;\n    serializer& operator=(serializer&&) = delete;\n    ~serializer() = default;\n\n    /*!\n    @brief internal implementation of the serialization function\n\n    This function is called by the public member function dump and organizes\n    the serialization internally. The indentation level is propagated as\n    additional parameter. In case of arrays and objects, the function is\n    called recursively.\n\n    - strings and object keys are escaped using `escape_string()`\n    - integer numbers are converted implicitly via `operator<<`\n    - floating-point numbers are converted to a string using `\"%g\"` format\n\n    @param[in] val             value to serialize\n    @param[in] pretty_print    whether the output shall be pretty-printed\n    @param[in] indent_step     the indent level\n    @param[in] current_indent  the current indent level (only used internally)\n    */\n    void dump(const BasicJsonType& val, const bool pretty_print,\n              const bool ensure_ascii,\n              const unsigned int indent_step,\n              const unsigned int current_indent = 0)\n    {\n        switch (val.m_type)\n        {\n            case value_t::object:\n            {\n                if (val.m_value.object->empty())\n                {\n                    o->write_characters(\"{}\", 2);\n                    return;\n                }\n\n                if (pretty_print)\n                {\n                    o->write_characters(\"{\\n\", 2);\n\n                    // variable to hold indentation for recursive calls\n                    const auto new_indent = current_indent + indent_step;\n                    if (JSON_UNLIKELY(indent_string.size() < new_indent))\n                    {\n                        indent_string.resize(indent_string.size() * 2, ' ');\n                    }\n\n                    // first n-1 elements\n                    auto i = val.m_value.object->cbegin();\n                    for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i)\n                    {\n                        o->write_characters(indent_string.c_str(), new_indent);\n                        o->write_character('\\\"');\n                        dump_escaped(i->first, ensure_ascii);\n                        o->write_characters(\"\\\": \", 3);\n                        dump(i->second, true, ensure_ascii, indent_step, new_indent);\n                        o->write_characters(\",\\n\", 2);\n                    }\n\n                    // last element\n                    assert(i != val.m_value.object->cend());\n                    assert(std::next(i) == val.m_value.object->cend());\n                    o->write_characters(indent_string.c_str(), new_indent);\n                    o->write_character('\\\"');\n                    dump_escaped(i->first, ensure_ascii);\n                    o->write_characters(\"\\\": \", 3);\n                    dump(i->second, true, ensure_ascii, indent_step, new_indent);\n\n                    o->write_character('\\n');\n                    o->write_characters(indent_string.c_str(), current_indent);\n                    o->write_character('}');\n                }\n                else\n                {\n                    o->write_character('{');\n\n                    // first n-1 elements\n                    auto i = val.m_value.object->cbegin();\n                    for (std::size_t cnt = 0; cnt < val.m_value.object->size() - 1; ++cnt, ++i)\n                    {\n                        o->write_character('\\\"');\n                        dump_escaped(i->first, ensure_ascii);\n                        o->write_characters(\"\\\":\", 2);\n                        dump(i->second, false, ensure_ascii, indent_step, current_indent);\n                        o->write_character(',');\n                    }\n\n                    // last element\n                    assert(i != val.m_value.object->cend());\n                    assert(std::next(i) == val.m_value.object->cend());\n                    o->write_character('\\\"');\n                    dump_escaped(i->first, ensure_ascii);\n                    o->write_characters(\"\\\":\", 2);\n                    dump(i->second, false, ensure_ascii, indent_step, current_indent);\n\n                    o->write_character('}');\n                }\n\n                return;\n            }\n\n            case value_t::array:\n            {\n                if (val.m_value.array->empty())\n                {\n                    o->write_characters(\"[]\", 2);\n                    return;\n                }\n\n                if (pretty_print)\n                {\n                    o->write_characters(\"[\\n\", 2);\n\n                    // variable to hold indentation for recursive calls\n                    const auto new_indent = current_indent + indent_step;\n                    if (JSON_UNLIKELY(indent_string.size() < new_indent))\n                    {\n                        indent_string.resize(indent_string.size() * 2, ' ');\n                    }\n\n                    // first n-1 elements\n                    for (auto i = val.m_value.array->cbegin();\n                            i != val.m_value.array->cend() - 1; ++i)\n                    {\n                        o->write_characters(indent_string.c_str(), new_indent);\n                        dump(*i, true, ensure_ascii, indent_step, new_indent);\n                        o->write_characters(\",\\n\", 2);\n                    }\n\n                    // last element\n                    assert(not val.m_value.array->empty());\n                    o->write_characters(indent_string.c_str(), new_indent);\n                    dump(val.m_value.array->back(), true, ensure_ascii, indent_step, new_indent);\n\n                    o->write_character('\\n');\n                    o->write_characters(indent_string.c_str(), current_indent);\n                    o->write_character(']');\n                }\n                else\n                {\n                    o->write_character('[');\n\n                    // first n-1 elements\n                    for (auto i = val.m_value.array->cbegin();\n                            i != val.m_value.array->cend() - 1; ++i)\n                    {\n                        dump(*i, false, ensure_ascii, indent_step, current_indent);\n                        o->write_character(',');\n                    }\n\n                    // last element\n                    assert(not val.m_value.array->empty());\n                    dump(val.m_value.array->back(), false, ensure_ascii, indent_step, current_indent);\n\n                    o->write_character(']');\n                }\n\n                return;\n            }\n\n            case value_t::string:\n            {\n                o->write_character('\\\"');\n                dump_escaped(*val.m_value.string, ensure_ascii);\n                o->write_character('\\\"');\n                return;\n            }\n\n            case value_t::boolean:\n            {\n                if (val.m_value.boolean)\n                {\n                    o->write_characters(\"true\", 4);\n                }\n                else\n                {\n                    o->write_characters(\"false\", 5);\n                }\n                return;\n            }\n\n            case value_t::number_integer:\n            {\n                dump_integer(val.m_value.number_integer);\n                return;\n            }\n\n            case value_t::number_unsigned:\n            {\n                dump_integer(val.m_value.number_unsigned);\n                return;\n            }\n\n            case value_t::number_float:\n            {\n                dump_float(val.m_value.number_float);\n                return;\n            }\n\n            case value_t::discarded:\n            {\n                o->write_characters(\"<discarded>\", 11);\n                return;\n            }\n\n            case value_t::null:\n            {\n                o->write_characters(\"null\", 4);\n                return;\n            }\n        }\n    }\n\n  private:\n    /*!\n    @brief dump escaped string\n\n    Escape a string by replacing certain special characters by a sequence of an\n    escape character (backslash) and another character and other control\n    characters by a sequence of \"\\u\" followed by a four-digit hex\n    representation. The escaped string is written to output stream @a o.\n\n    @param[in] s  the string to escape\n    @param[in] ensure_ascii  whether to escape non-ASCII characters with\n                             \\uXXXX sequences\n\n    @complexity Linear in the length of string @a s.\n    */\n    void dump_escaped(const string_t& s, const bool ensure_ascii)\n    {\n        uint32_t codepoint;\n        uint8_t state = UTF8_ACCEPT;\n        std::size_t bytes = 0;  // number of bytes written to string_buffer\n\n        // number of bytes written at the point of the last valid byte\n        std::size_t bytes_after_last_accept = 0;\n        std::size_t undumped_chars = 0;\n\n        for (std::size_t i = 0; i < s.size(); ++i)\n        {\n            const auto byte = static_cast<uint8_t>(s[i]);\n\n            switch (decode(state, codepoint, byte))\n            {\n                case UTF8_ACCEPT:  // decode found a new code point\n                {\n                    switch (codepoint)\n                    {\n                        case 0x08: // backspace\n                        {\n                            string_buffer[bytes++] = '\\\\';\n                            string_buffer[bytes++] = 'b';\n                            break;\n                        }\n\n                        case 0x09: // horizontal tab\n                        {\n                            string_buffer[bytes++] = '\\\\';\n                            string_buffer[bytes++] = 't';\n                            break;\n                        }\n\n                        case 0x0A: // newline\n                        {\n                            string_buffer[bytes++] = '\\\\';\n                            string_buffer[bytes++] = 'n';\n                            break;\n                        }\n\n                        case 0x0C: // formfeed\n                        {\n                            string_buffer[bytes++] = '\\\\';\n                            string_buffer[bytes++] = 'f';\n                            break;\n                        }\n\n                        case 0x0D: // carriage return\n                        {\n                            string_buffer[bytes++] = '\\\\';\n                            string_buffer[bytes++] = 'r';\n                            break;\n                        }\n\n                        case 0x22: // quotation mark\n                        {\n                            string_buffer[bytes++] = '\\\\';\n                            string_buffer[bytes++] = '\\\"';\n                            break;\n                        }\n\n                        case 0x5C: // reverse solidus\n                        {\n                            string_buffer[bytes++] = '\\\\';\n                            string_buffer[bytes++] = '\\\\';\n                            break;\n                        }\n\n                        default:\n                        {\n                            // escape control characters (0x00..0x1F) or, if\n                            // ensure_ascii parameter is used, non-ASCII characters\n                            if ((codepoint <= 0x1F) or (ensure_ascii and (codepoint >= 0x7F)))\n                            {\n                                if (codepoint <= 0xFFFF)\n                                {\n                                    (std::snprintf)(string_buffer.data() + bytes, 7, \"\\\\u%04x\",\n                                                    static_cast<uint16_t>(codepoint));\n                                    bytes += 6;\n                                }\n                                else\n                                {\n                                    (std::snprintf)(string_buffer.data() + bytes, 13, \"\\\\u%04x\\\\u%04x\",\n                                                    static_cast<uint16_t>(0xD7C0 + (codepoint >> 10)),\n                                                    static_cast<uint16_t>(0xDC00 + (codepoint & 0x3FF)));\n                                    bytes += 12;\n                                }\n                            }\n                            else\n                            {\n                                // copy byte to buffer (all previous bytes\n                                // been copied have in default case above)\n                                string_buffer[bytes++] = s[i];\n                            }\n                            break;\n                        }\n                    }\n\n                    // write buffer and reset index; there must be 13 bytes\n                    // left, as this is the maximal number of bytes to be\n                    // written (\"\\uxxxx\\uxxxx\\0\") for one code point\n                    if (string_buffer.size() - bytes < 13)\n                    {\n                        o->write_characters(string_buffer.data(), bytes);\n                        bytes = 0;\n                    }\n\n                    // remember the byte position of this accept\n                    bytes_after_last_accept = bytes;\n                    undumped_chars = 0;\n                    break;\n                }\n\n                case UTF8_REJECT:  // decode found invalid UTF-8 byte\n                {\n                    switch (error_handler)\n                    {\n                        case error_handler_t::strict:\n                        {\n                            std::string sn(3, '\\0');\n                            (std::snprintf)(&sn[0], sn.size(), \"%.2X\", byte);\n                            JSON_THROW(type_error::create(316, \"invalid UTF-8 byte at index \" + std::to_string(i) + \": 0x\" + sn));\n                        }\n\n                        case error_handler_t::ignore:\n                        case error_handler_t::replace:\n                        {\n                            // in case we saw this character the first time, we\n                            // would like to read it again, because the byte\n                            // may be OK for itself, but just not OK for the\n                            // previous sequence\n                            if (undumped_chars > 0)\n                            {\n                                --i;\n                            }\n\n                            // reset length buffer to the last accepted index;\n                            // thus removing/ignoring the invalid characters\n                            bytes = bytes_after_last_accept;\n\n                            if (error_handler == error_handler_t::replace)\n                            {\n                                // add a replacement character\n                                if (ensure_ascii)\n                                {\n                                    string_buffer[bytes++] = '\\\\';\n                                    string_buffer[bytes++] = 'u';\n                                    string_buffer[bytes++] = 'f';\n                                    string_buffer[bytes++] = 'f';\n                                    string_buffer[bytes++] = 'f';\n                                    string_buffer[bytes++] = 'd';\n                                }\n                                else\n                                {\n                                    string_buffer[bytes++] = detail::binary_writer<BasicJsonType, char>::to_char_type('\\xEF');\n                                    string_buffer[bytes++] = detail::binary_writer<BasicJsonType, char>::to_char_type('\\xBF');\n                                    string_buffer[bytes++] = detail::binary_writer<BasicJsonType, char>::to_char_type('\\xBD');\n                                }\n                                bytes_after_last_accept = bytes;\n                            }\n\n                            undumped_chars = 0;\n\n                            // continue processing the string\n                            state = UTF8_ACCEPT;\n                            break;\n                        }\n                    }\n                    break;\n                }\n\n                default:  // decode found yet incomplete multi-byte code point\n                {\n                    if (not ensure_ascii)\n                    {\n                        // code point will not be escaped - copy byte to buffer\n                        string_buffer[bytes++] = s[i];\n                    }\n                    ++undumped_chars;\n                    break;\n                }\n            }\n        }\n\n        // we finished processing the string\n        if (JSON_LIKELY(state == UTF8_ACCEPT))\n        {\n            // write buffer\n            if (bytes > 0)\n            {\n                o->write_characters(string_buffer.data(), bytes);\n            }\n        }\n        else\n        {\n            // we finish reading, but do not accept: string was incomplete\n            switch (error_handler)\n            {\n                case error_handler_t::strict:\n                {\n                    std::string sn(3, '\\0');\n                    (std::snprintf)(&sn[0], sn.size(), \"%.2X\", static_cast<uint8_t>(s.back()));\n                    JSON_THROW(type_error::create(316, \"incomplete UTF-8 string; last byte: 0x\" + sn));\n                }\n\n                case error_handler_t::ignore:\n                {\n                    // write all accepted bytes\n                    o->write_characters(string_buffer.data(), bytes_after_last_accept);\n                    break;\n                }\n\n                case error_handler_t::replace:\n                {\n                    // write all accepted bytes\n                    o->write_characters(string_buffer.data(), bytes_after_last_accept);\n                    // add a replacement character\n                    if (ensure_ascii)\n                    {\n                        o->write_characters(\"\\\\ufffd\", 6);\n                    }\n                    else\n                    {\n                        o->write_characters(\"\\xEF\\xBF\\xBD\", 3);\n                    }\n                    break;\n                }\n            }\n        }\n    }\n\n    /*!\n    @brief dump an integer\n\n    Dump a given integer to output stream @a o. Works internally with\n    @a number_buffer.\n\n    @param[in] x  integer number (signed or unsigned) to dump\n    @tparam NumberType either @a number_integer_t or @a number_unsigned_t\n    */\n    template<typename NumberType, detail::enable_if_t<\n                 std::is_same<NumberType, number_unsigned_t>::value or\n                 std::is_same<NumberType, number_integer_t>::value,\n                 int> = 0>\n    void dump_integer(NumberType x)\n    {\n        // special case for \"0\"\n        if (x == 0)\n        {\n            o->write_character('0');\n            return;\n        }\n\n        const bool is_negative = std::is_same<NumberType, number_integer_t>::value and not (x >= 0);  // see issue #755\n        std::size_t i = 0;\n\n        while (x != 0)\n        {\n            // spare 1 byte for '\\0'\n            assert(i < number_buffer.size() - 1);\n\n            const auto digit = std::labs(static_cast<long>(x % 10));\n            number_buffer[i++] = static_cast<char>('0' + digit);\n            x /= 10;\n        }\n\n        if (is_negative)\n        {\n            // make sure there is capacity for the '-'\n            assert(i < number_buffer.size() - 2);\n            number_buffer[i++] = '-';\n        }\n\n        std::reverse(number_buffer.begin(), number_buffer.begin() + i);\n        o->write_characters(number_buffer.data(), i);\n    }\n\n    /*!\n    @brief dump a floating-point number\n\n    Dump a given floating-point number to output stream @a o. Works internally\n    with @a number_buffer.\n\n    @param[in] x  floating-point number to dump\n    */\n    void dump_float(number_float_t x)\n    {\n        // NaN / inf\n        if (not std::isfinite(x))\n        {\n            o->write_characters(\"null\", 4);\n            return;\n        }\n\n        // If number_float_t is an IEEE-754 single or double precision number,\n        // use the Grisu2 algorithm to produce short numbers which are\n        // guaranteed to round-trip, using strtof and strtod, resp.\n        //\n        // NB: The test below works if <long double> == <double>.\n        static constexpr bool is_ieee_single_or_double\n            = (std::numeric_limits<number_float_t>::is_iec559 and std::numeric_limits<number_float_t>::digits == 24 and std::numeric_limits<number_float_t>::max_exponent == 128) or\n              (std::numeric_limits<number_float_t>::is_iec559 and std::numeric_limits<number_float_t>::digits == 53 and std::numeric_limits<number_float_t>::max_exponent == 1024);\n\n        dump_float(x, std::integral_constant<bool, is_ieee_single_or_double>());\n    }\n\n    void dump_float(number_float_t x, std::true_type /*is_ieee_single_or_double*/)\n    {\n        char* begin = number_buffer.data();\n        char* end = ::nlohmann::detail::to_chars(begin, begin + number_buffer.size(), x);\n\n        o->write_characters(begin, static_cast<size_t>(end - begin));\n    }\n\n    void dump_float(number_float_t x, std::false_type /*is_ieee_single_or_double*/)\n    {\n        // get number of digits for a float -> text -> float round-trip\n        static constexpr auto d = std::numeric_limits<number_float_t>::max_digits10;\n\n        // the actual conversion\n        std::ptrdiff_t len = (std::snprintf)(number_buffer.data(), number_buffer.size(), \"%.*g\", d, x);\n\n        // negative value indicates an error\n        assert(len > 0);\n        // check if buffer was large enough\n        assert(static_cast<std::size_t>(len) < number_buffer.size());\n\n        // erase thousands separator\n        if (thousands_sep != '\\0')\n        {\n            const auto end = std::remove(number_buffer.begin(),\n                                         number_buffer.begin() + len, thousands_sep);\n            std::fill(end, number_buffer.end(), '\\0');\n            assert((end - number_buffer.begin()) <= len);\n            len = (end - number_buffer.begin());\n        }\n\n        // convert decimal point to '.'\n        if (decimal_point != '\\0' and decimal_point != '.')\n        {\n            const auto dec_pos = std::find(number_buffer.begin(), number_buffer.end(), decimal_point);\n            if (dec_pos != number_buffer.end())\n            {\n                *dec_pos = '.';\n            }\n        }\n\n        o->write_characters(number_buffer.data(), static_cast<std::size_t>(len));\n\n        // determine if need to append \".0\"\n        const bool value_is_int_like =\n            std::none_of(number_buffer.begin(), number_buffer.begin() + len + 1,\n                         [](char c)\n        {\n            return (c == '.' or c == 'e');\n        });\n\n        if (value_is_int_like)\n        {\n            o->write_characters(\".0\", 2);\n        }\n    }\n\n    /*!\n    @brief check whether a string is UTF-8 encoded\n\n    The function checks each byte of a string whether it is UTF-8 encoded. The\n    result of the check is stored in the @a state parameter. The function must\n    be called initially with state 0 (accept). State 1 means the string must\n    be rejected, because the current byte is not allowed. If the string is\n    completely processed, but the state is non-zero, the string ended\n    prematurely; that is, the last byte indicated more bytes should have\n    followed.\n\n    @param[in,out] state  the state of the decoding\n    @param[in,out] codep  codepoint (valid only if resulting state is UTF8_ACCEPT)\n    @param[in] byte       next byte to decode\n    @return               new state\n\n    @note The function has been edited: a std::array is used.\n\n    @copyright Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>\n    @sa http://bjoern.hoehrmann.de/utf-8/decoder/dfa/\n    */\n    static uint8_t decode(uint8_t& state, uint32_t& codep, const uint8_t byte) noexcept\n    {\n        static const std::array<uint8_t, 400> utf8d =\n        {\n            {\n                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00..1F\n                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20..3F\n                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40..5F\n                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60..7F\n                1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 80..9F\n                7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // A0..BF\n                8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // C0..DF\n                0xA, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3, 0x3, // E0..EF\n                0xB, 0x6, 0x6, 0x6, 0x5, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, // F0..FF\n                0x0, 0x1, 0x2, 0x3, 0x5, 0x8, 0x7, 0x1, 0x1, 0x1, 0x4, 0x6, 0x1, 0x1, 0x1, 0x1, // s0..s0\n                1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, // s1..s2\n                1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, // s3..s4\n                1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, // s5..s6\n                1, 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // s7..s8\n            }\n        };\n\n        const uint8_t type = utf8d[byte];\n\n        codep = (state != UTF8_ACCEPT)\n                ? (byte & 0x3fu) | (codep << 6)\n                : static_cast<uint32_t>(0xff >> type) & (byte);\n\n        state = utf8d[256u + state * 16u + type];\n        return state;\n    }\n\n  private:\n    /// the output of the serializer\n    output_adapter_t<char> o = nullptr;\n\n    /// a (hopefully) large enough character buffer\n    std::array<char, 64> number_buffer{{}};\n\n    /// the locale\n    const std::lconv* loc = nullptr;\n    /// the locale's thousand separator character\n    const char thousands_sep = '\\0';\n    /// the locale's decimal point character\n    const char decimal_point = '\\0';\n\n    /// string buffer\n    std::array<char, 512> string_buffer{{}};\n\n    /// the indentation character\n    const char indent_char;\n    /// the indentation string\n    string_t indent_string;\n\n    /// error_handler how to react on decoding errors\n    const error_handler_t error_handler;\n};\n}  // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/json_ref.hpp>\n\n\n#include <initializer_list>\n#include <utility>\n\n// #include <nlohmann/detail/meta/type_traits.hpp>\n\n\nnamespace nlohmann\n{\nnamespace detail\n{\ntemplate<typename BasicJsonType>\nclass json_ref\n{\n  public:\n    using value_type = BasicJsonType;\n\n    json_ref(value_type&& value)\n        : owned_value(std::move(value)), value_ref(&owned_value), is_rvalue(true)\n    {}\n\n    json_ref(const value_type& value)\n        : value_ref(const_cast<value_type*>(&value)), is_rvalue(false)\n    {}\n\n    json_ref(std::initializer_list<json_ref> init)\n        : owned_value(init), value_ref(&owned_value), is_rvalue(true)\n    {}\n\n    template <\n        class... Args,\n        enable_if_t<std::is_constructible<value_type, Args...>::value, int> = 0 >\n    json_ref(Args && ... args)\n        : owned_value(std::forward<Args>(args)...), value_ref(&owned_value),\n          is_rvalue(true) {}\n\n    // class should be movable only\n    json_ref(json_ref&&) = default;\n    json_ref(const json_ref&) = delete;\n    json_ref& operator=(const json_ref&) = delete;\n    json_ref& operator=(json_ref&&) = delete;\n    ~json_ref() = default;\n\n    value_type moved_or_copied() const\n    {\n        if (is_rvalue)\n        {\n            return std::move(*value_ref);\n        }\n        return *value_ref;\n    }\n\n    value_type const& operator*() const\n    {\n        return *static_cast<value_type const*>(value_ref);\n    }\n\n    value_type const* operator->() const\n    {\n        return static_cast<value_type const*>(value_ref);\n    }\n\n  private:\n    mutable value_type owned_value = nullptr;\n    value_type* value_ref = nullptr;\n    const bool is_rvalue;\n};\n}  // namespace detail\n}  // namespace nlohmann\n\n// #include <nlohmann/detail/json_pointer.hpp>\n\n\n#include <cassert> // assert\n#include <numeric> // accumulate\n#include <string> // string\n#include <vector> // vector\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n// #include <nlohmann/detail/exceptions.hpp>\n\n// #include <nlohmann/detail/value_t.hpp>\n\n\nnamespace nlohmann\n{\ntemplate<typename BasicJsonType>\nclass json_pointer\n{\n    // allow basic_json to access private members\n    NLOHMANN_BASIC_JSON_TPL_DECLARATION\n    friend class basic_json;\n\n  public:\n    /*!\n    @brief create JSON pointer\n\n    Create a JSON pointer according to the syntax described in\n    [Section 3 of RFC6901](https://tools.ietf.org/html/rfc6901#section-3).\n\n    @param[in] s  string representing the JSON pointer; if omitted, the empty\n                  string is assumed which references the whole JSON value\n\n    @throw parse_error.107 if the given JSON pointer @a s is nonempty and does\n                           not begin with a slash (`/`); see example below\n\n    @throw parse_error.108 if a tilde (`~`) in the given JSON pointer @a s is\n    not followed by `0` (representing `~`) or `1` (representing `/`); see\n    example below\n\n    @liveexample{The example shows the construction several valid JSON pointers\n    as well as the exceptional behavior.,json_pointer}\n\n    @since version 2.0.0\n    */\n    explicit json_pointer(const std::string& s = \"\")\n        : reference_tokens(split(s))\n    {}\n\n    /*!\n    @brief return a string representation of the JSON pointer\n\n    @invariant For each JSON pointer `ptr`, it holds:\n    @code {.cpp}\n    ptr == json_pointer(ptr.to_string());\n    @endcode\n\n    @return a string representation of the JSON pointer\n\n    @liveexample{The example shows the result of `to_string`.,\n    json_pointer__to_string}\n\n    @since version 2.0.0\n    */\n    std::string to_string() const\n    {\n        return std::accumulate(reference_tokens.begin(), reference_tokens.end(),\n                               std::string{},\n                               [](const std::string & a, const std::string & b)\n        {\n            return a + \"/\" + escape(b);\n        });\n    }\n\n    /// @copydoc to_string()\n    operator std::string() const\n    {\n        return to_string();\n    }\n\n    /*!\n    @param[in] s  reference token to be converted into an array index\n\n    @return integer representation of @a s\n\n    @throw out_of_range.404 if string @a s could not be converted to an integer\n    */\n    static int array_index(const std::string& s)\n    {\n        std::size_t processed_chars = 0;\n        const int res = std::stoi(s, &processed_chars);\n\n        // check if the string was completely read\n        if (JSON_UNLIKELY(processed_chars != s.size()))\n        {\n            JSON_THROW(detail::out_of_range::create(404, \"unresolved reference token '\" + s + \"'\"));\n        }\n\n        return res;\n    }\n\n  private:\n    /*!\n    @brief remove and return last reference pointer\n    @throw out_of_range.405 if JSON pointer has no parent\n    */\n    std::string pop_back()\n    {\n        if (JSON_UNLIKELY(is_root()))\n        {\n            JSON_THROW(detail::out_of_range::create(405, \"JSON pointer has no parent\"));\n        }\n\n        auto last = reference_tokens.back();\n        reference_tokens.pop_back();\n        return last;\n    }\n\n    /// return whether pointer points to the root document\n    bool is_root() const noexcept\n    {\n        return reference_tokens.empty();\n    }\n\n    json_pointer top() const\n    {\n        if (JSON_UNLIKELY(is_root()))\n        {\n            JSON_THROW(detail::out_of_range::create(405, \"JSON pointer has no parent\"));\n        }\n\n        json_pointer result = *this;\n        result.reference_tokens = {reference_tokens[0]};\n        return result;\n    }\n\n    /*!\n    @brief create and return a reference to the pointed to value\n\n    @complexity Linear in the number of reference tokens.\n\n    @throw parse_error.109 if array index is not a number\n    @throw type_error.313 if value cannot be unflattened\n    */\n    BasicJsonType& get_and_create(BasicJsonType& j) const\n    {\n        using size_type = typename BasicJsonType::size_type;\n        auto result = &j;\n\n        // in case no reference tokens exist, return a reference to the JSON value\n        // j which will be overwritten by a primitive value\n        for (const auto& reference_token : reference_tokens)\n        {\n            switch (result->m_type)\n            {\n                case detail::value_t::null:\n                {\n                    if (reference_token == \"0\")\n                    {\n                        // start a new array if reference token is 0\n                        result = &result->operator[](0);\n                    }\n                    else\n                    {\n                        // start a new object otherwise\n                        result = &result->operator[](reference_token);\n                    }\n                    break;\n                }\n\n                case detail::value_t::object:\n                {\n                    // create an entry in the object\n                    result = &result->operator[](reference_token);\n                    break;\n                }\n\n                case detail::value_t::array:\n                {\n                    // create an entry in the array\n                    JSON_TRY\n                    {\n                        result = &result->operator[](static_cast<size_type>(array_index(reference_token)));\n                    }\n                    JSON_CATCH(std::invalid_argument&)\n                    {\n                        JSON_THROW(detail::parse_error::create(109, 0, \"array index '\" + reference_token + \"' is not a number\"));\n                    }\n                    break;\n                }\n\n                /*\n                The following code is only reached if there exists a reference\n                token _and_ the current value is primitive. In this case, we have\n                an error situation, because primitive values may only occur as\n                single value; that is, with an empty list of reference tokens.\n                */\n                default:\n                    JSON_THROW(detail::type_error::create(313, \"invalid value to unflatten\"));\n            }\n        }\n\n        return *result;\n    }\n\n    /*!\n    @brief return a reference to the pointed to value\n\n    @note This version does not throw if a value is not present, but tries to\n          create nested values instead. For instance, calling this function\n          with pointer `\"/this/that\"` on a null value is equivalent to calling\n          `operator[](\"this\").operator[](\"that\")` on that value, effectively\n          changing the null value to an object.\n\n    @param[in] ptr  a JSON value\n\n    @return reference to the JSON value pointed to by the JSON pointer\n\n    @complexity Linear in the length of the JSON pointer.\n\n    @throw parse_error.106   if an array index begins with '0'\n    @throw parse_error.109   if an array index was not a number\n    @throw out_of_range.404  if the JSON pointer can not be resolved\n    */\n    BasicJsonType& get_unchecked(BasicJsonType* ptr) const\n    {\n        using size_type = typename BasicJsonType::size_type;\n        for (const auto& reference_token : reference_tokens)\n        {\n            // convert null values to arrays or objects before continuing\n            if (ptr->m_type == detail::value_t::null)\n            {\n                // check if reference token is a number\n                const bool nums =\n                    std::all_of(reference_token.begin(), reference_token.end(),\n                                [](const char x)\n                {\n                    return (x >= '0' and x <= '9');\n                });\n\n                // change value to array for numbers or \"-\" or to object otherwise\n                *ptr = (nums or reference_token == \"-\")\n                       ? detail::value_t::array\n                       : detail::value_t::object;\n            }\n\n            switch (ptr->m_type)\n            {\n                case detail::value_t::object:\n                {\n                    // use unchecked object access\n                    ptr = &ptr->operator[](reference_token);\n                    break;\n                }\n\n                case detail::value_t::array:\n                {\n                    // error condition (cf. RFC 6901, Sect. 4)\n                    if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0'))\n                    {\n                        JSON_THROW(detail::parse_error::create(106, 0,\n                                                               \"array index '\" + reference_token +\n                                                               \"' must not begin with '0'\"));\n                    }\n\n                    if (reference_token == \"-\")\n                    {\n                        // explicitly treat \"-\" as index beyond the end\n                        ptr = &ptr->operator[](ptr->m_value.array->size());\n                    }\n                    else\n                    {\n                        // convert array index to number; unchecked access\n                        JSON_TRY\n                        {\n                            ptr = &ptr->operator[](\n                                static_cast<size_type>(array_index(reference_token)));\n                        }\n                        JSON_CATCH(std::invalid_argument&)\n                        {\n                            JSON_THROW(detail::parse_error::create(109, 0, \"array index '\" + reference_token + \"' is not a number\"));\n                        }\n                    }\n                    break;\n                }\n\n                default:\n                    JSON_THROW(detail::out_of_range::create(404, \"unresolved reference token '\" + reference_token + \"'\"));\n            }\n        }\n\n        return *ptr;\n    }\n\n    /*!\n    @throw parse_error.106   if an array index begins with '0'\n    @throw parse_error.109   if an array index was not a number\n    @throw out_of_range.402  if the array index '-' is used\n    @throw out_of_range.404  if the JSON pointer can not be resolved\n    */\n    BasicJsonType& get_checked(BasicJsonType* ptr) const\n    {\n        using size_type = typename BasicJsonType::size_type;\n        for (const auto& reference_token : reference_tokens)\n        {\n            switch (ptr->m_type)\n            {\n                case detail::value_t::object:\n                {\n                    // note: at performs range check\n                    ptr = &ptr->at(reference_token);\n                    break;\n                }\n\n                case detail::value_t::array:\n                {\n                    if (JSON_UNLIKELY(reference_token == \"-\"))\n                    {\n                        // \"-\" always fails the range check\n                        JSON_THROW(detail::out_of_range::create(402,\n                                                                \"array index '-' (\" + std::to_string(ptr->m_value.array->size()) +\n                                                                \") is out of range\"));\n                    }\n\n                    // error condition (cf. RFC 6901, Sect. 4)\n                    if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0'))\n                    {\n                        JSON_THROW(detail::parse_error::create(106, 0,\n                                                               \"array index '\" + reference_token +\n                                                               \"' must not begin with '0'\"));\n                    }\n\n                    // note: at performs range check\n                    JSON_TRY\n                    {\n                        ptr = &ptr->at(static_cast<size_type>(array_index(reference_token)));\n                    }\n                    JSON_CATCH(std::invalid_argument&)\n                    {\n                        JSON_THROW(detail::parse_error::create(109, 0, \"array index '\" + reference_token + \"' is not a number\"));\n                    }\n                    break;\n                }\n\n                default:\n                    JSON_THROW(detail::out_of_range::create(404, \"unresolved reference token '\" + reference_token + \"'\"));\n            }\n        }\n\n        return *ptr;\n    }\n\n    /*!\n    @brief return a const reference to the pointed to value\n\n    @param[in] ptr  a JSON value\n\n    @return const reference to the JSON value pointed to by the JSON\n    pointer\n\n    @throw parse_error.106   if an array index begins with '0'\n    @throw parse_error.109   if an array index was not a number\n    @throw out_of_range.402  if the array index '-' is used\n    @throw out_of_range.404  if the JSON pointer can not be resolved\n    */\n    const BasicJsonType& get_unchecked(const BasicJsonType* ptr) const\n    {\n        using size_type = typename BasicJsonType::size_type;\n        for (const auto& reference_token : reference_tokens)\n        {\n            switch (ptr->m_type)\n            {\n                case detail::value_t::object:\n                {\n                    // use unchecked object access\n                    ptr = &ptr->operator[](reference_token);\n                    break;\n                }\n\n                case detail::value_t::array:\n                {\n                    if (JSON_UNLIKELY(reference_token == \"-\"))\n                    {\n                        // \"-\" cannot be used for const access\n                        JSON_THROW(detail::out_of_range::create(402,\n                                                                \"array index '-' (\" + std::to_string(ptr->m_value.array->size()) +\n                                                                \") is out of range\"));\n                    }\n\n                    // error condition (cf. RFC 6901, Sect. 4)\n                    if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0'))\n                    {\n                        JSON_THROW(detail::parse_error::create(106, 0,\n                                                               \"array index '\" + reference_token +\n                                                               \"' must not begin with '0'\"));\n                    }\n\n                    // use unchecked array access\n                    JSON_TRY\n                    {\n                        ptr = &ptr->operator[](\n                            static_cast<size_type>(array_index(reference_token)));\n                    }\n                    JSON_CATCH(std::invalid_argument&)\n                    {\n                        JSON_THROW(detail::parse_error::create(109, 0, \"array index '\" + reference_token + \"' is not a number\"));\n                    }\n                    break;\n                }\n\n                default:\n                    JSON_THROW(detail::out_of_range::create(404, \"unresolved reference token '\" + reference_token + \"'\"));\n            }\n        }\n\n        return *ptr;\n    }\n\n    /*!\n    @throw parse_error.106   if an array index begins with '0'\n    @throw parse_error.109   if an array index was not a number\n    @throw out_of_range.402  if the array index '-' is used\n    @throw out_of_range.404  if the JSON pointer can not be resolved\n    */\n    const BasicJsonType& get_checked(const BasicJsonType* ptr) const\n    {\n        using size_type = typename BasicJsonType::size_type;\n        for (const auto& reference_token : reference_tokens)\n        {\n            switch (ptr->m_type)\n            {\n                case detail::value_t::object:\n                {\n                    // note: at performs range check\n                    ptr = &ptr->at(reference_token);\n                    break;\n                }\n\n                case detail::value_t::array:\n                {\n                    if (JSON_UNLIKELY(reference_token == \"-\"))\n                    {\n                        // \"-\" always fails the range check\n                        JSON_THROW(detail::out_of_range::create(402,\n                                                                \"array index '-' (\" + std::to_string(ptr->m_value.array->size()) +\n                                                                \") is out of range\"));\n                    }\n\n                    // error condition (cf. RFC 6901, Sect. 4)\n                    if (JSON_UNLIKELY(reference_token.size() > 1 and reference_token[0] == '0'))\n                    {\n                        JSON_THROW(detail::parse_error::create(106, 0,\n                                                               \"array index '\" + reference_token +\n                                                               \"' must not begin with '0'\"));\n                    }\n\n                    // note: at performs range check\n                    JSON_TRY\n                    {\n                        ptr = &ptr->at(static_cast<size_type>(array_index(reference_token)));\n                    }\n                    JSON_CATCH(std::invalid_argument&)\n                    {\n                        JSON_THROW(detail::parse_error::create(109, 0, \"array index '\" + reference_token + \"' is not a number\"));\n                    }\n                    break;\n                }\n\n                default:\n                    JSON_THROW(detail::out_of_range::create(404, \"unresolved reference token '\" + reference_token + \"'\"));\n            }\n        }\n\n        return *ptr;\n    }\n\n    /*!\n    @brief split the string input to reference tokens\n\n    @note This function is only called by the json_pointer constructor.\n          All exceptions below are documented there.\n\n    @throw parse_error.107  if the pointer is not empty or begins with '/'\n    @throw parse_error.108  if character '~' is not followed by '0' or '1'\n    */\n    static std::vector<std::string> split(const std::string& reference_string)\n    {\n        std::vector<std::string> result;\n\n        // special case: empty reference string -> no reference tokens\n        if (reference_string.empty())\n        {\n            return result;\n        }\n\n        // check if nonempty reference string begins with slash\n        if (JSON_UNLIKELY(reference_string[0] != '/'))\n        {\n            JSON_THROW(detail::parse_error::create(107, 1,\n                                                   \"JSON pointer must be empty or begin with '/' - was: '\" +\n                                                   reference_string + \"'\"));\n        }\n\n        // extract the reference tokens:\n        // - slash: position of the last read slash (or end of string)\n        // - start: position after the previous slash\n        for (\n            // search for the first slash after the first character\n            std::size_t slash = reference_string.find_first_of('/', 1),\n            // set the beginning of the first reference token\n            start = 1;\n            // we can stop if start == 0 (if slash == std::string::npos)\n            start != 0;\n            // set the beginning of the next reference token\n            // (will eventually be 0 if slash == std::string::npos)\n            start = (slash == std::string::npos) ? 0 : slash + 1,\n            // find next slash\n            slash = reference_string.find_first_of('/', start))\n        {\n            // use the text between the beginning of the reference token\n            // (start) and the last slash (slash).\n            auto reference_token = reference_string.substr(start, slash - start);\n\n            // check reference tokens are properly escaped\n            for (std::size_t pos = reference_token.find_first_of('~');\n                    pos != std::string::npos;\n                    pos = reference_token.find_first_of('~', pos + 1))\n            {\n                assert(reference_token[pos] == '~');\n\n                // ~ must be followed by 0 or 1\n                if (JSON_UNLIKELY(pos == reference_token.size() - 1 or\n                                  (reference_token[pos + 1] != '0' and\n                                   reference_token[pos + 1] != '1')))\n                {\n                    JSON_THROW(detail::parse_error::create(108, 0, \"escape character '~' must be followed with '0' or '1'\"));\n                }\n            }\n\n            // finally, store the reference token\n            unescape(reference_token);\n            result.push_back(reference_token);\n        }\n\n        return result;\n    }\n\n    /*!\n    @brief replace all occurrences of a substring by another string\n\n    @param[in,out] s  the string to manipulate; changed so that all\n                   occurrences of @a f are replaced with @a t\n    @param[in]     f  the substring to replace with @a t\n    @param[in]     t  the string to replace @a f\n\n    @pre The search string @a f must not be empty. **This precondition is\n    enforced with an assertion.**\n\n    @since version 2.0.0\n    */\n    static void replace_substring(std::string& s, const std::string& f,\n                                  const std::string& t)\n    {\n        assert(not f.empty());\n        for (auto pos = s.find(f);                // find first occurrence of f\n                pos != std::string::npos;         // make sure f was found\n                s.replace(pos, f.size(), t),      // replace with t, and\n                pos = s.find(f, pos + t.size()))  // find next occurrence of f\n        {}\n    }\n\n    /// escape \"~\" to \"~0\" and \"/\" to \"~1\"\n    static std::string escape(std::string s)\n    {\n        replace_substring(s, \"~\", \"~0\");\n        replace_substring(s, \"/\", \"~1\");\n        return s;\n    }\n\n    /// unescape \"~1\" to tilde and \"~0\" to slash (order is important!)\n    static void unescape(std::string& s)\n    {\n        replace_substring(s, \"~1\", \"/\");\n        replace_substring(s, \"~0\", \"~\");\n    }\n\n    /*!\n    @param[in] reference_string  the reference string to the current value\n    @param[in] value             the value to consider\n    @param[in,out] result        the result object to insert values to\n\n    @note Empty objects or arrays are flattened to `null`.\n    */\n    static void flatten(const std::string& reference_string,\n                        const BasicJsonType& value,\n                        BasicJsonType& result)\n    {\n        switch (value.m_type)\n        {\n            case detail::value_t::array:\n            {\n                if (value.m_value.array->empty())\n                {\n                    // flatten empty array as null\n                    result[reference_string] = nullptr;\n                }\n                else\n                {\n                    // iterate array and use index as reference string\n                    for (std::size_t i = 0; i < value.m_value.array->size(); ++i)\n                    {\n                        flatten(reference_string + \"/\" + std::to_string(i),\n                                value.m_value.array->operator[](i), result);\n                    }\n                }\n                break;\n            }\n\n            case detail::value_t::object:\n            {\n                if (value.m_value.object->empty())\n                {\n                    // flatten empty object as null\n                    result[reference_string] = nullptr;\n                }\n                else\n                {\n                    // iterate object and use keys as reference string\n                    for (const auto& element : *value.m_value.object)\n                    {\n                        flatten(reference_string + \"/\" + escape(element.first), element.second, result);\n                    }\n                }\n                break;\n            }\n\n            default:\n            {\n                // add primitive value with its reference string\n                result[reference_string] = value;\n                break;\n            }\n        }\n    }\n\n    /*!\n    @param[in] value  flattened JSON\n\n    @return unflattened JSON\n\n    @throw parse_error.109 if array index is not a number\n    @throw type_error.314  if value is not an object\n    @throw type_error.315  if object values are not primitive\n    @throw type_error.313  if value cannot be unflattened\n    */\n    static BasicJsonType\n    unflatten(const BasicJsonType& value)\n    {\n        if (JSON_UNLIKELY(not value.is_object()))\n        {\n            JSON_THROW(detail::type_error::create(314, \"only objects can be unflattened\"));\n        }\n\n        BasicJsonType result;\n\n        // iterate the JSON object values\n        for (const auto& element : *value.m_value.object)\n        {\n            if (JSON_UNLIKELY(not element.second.is_primitive()))\n            {\n                JSON_THROW(detail::type_error::create(315, \"values in object must be primitive\"));\n            }\n\n            // assign value to reference pointed to by JSON pointer; Note that if\n            // the JSON pointer is \"\" (i.e., points to the whole value), function\n            // get_and_create returns a reference to result itself. An assignment\n            // will then create a primitive value.\n            json_pointer(element.first).get_and_create(result) = element.second;\n        }\n\n        return result;\n    }\n\n    friend bool operator==(json_pointer const& lhs,\n                           json_pointer const& rhs) noexcept\n    {\n        return (lhs.reference_tokens == rhs.reference_tokens);\n    }\n\n    friend bool operator!=(json_pointer const& lhs,\n                           json_pointer const& rhs) noexcept\n    {\n        return not (lhs == rhs);\n    }\n\n    /// the reference tokens\n    std::vector<std::string> reference_tokens;\n};\n}  // namespace nlohmann\n\n// #include <nlohmann/adl_serializer.hpp>\n\n\n#include <utility>\n\n// #include <nlohmann/detail/conversions/from_json.hpp>\n\n// #include <nlohmann/detail/conversions/to_json.hpp>\n\n\nnamespace nlohmann\n{\n\ntemplate<typename, typename>\nstruct adl_serializer\n{\n    /*!\n    @brief convert a JSON value to any value type\n\n    This function is usually called by the `get()` function of the\n    @ref basic_json class (either explicit or via conversion operators).\n\n    @param[in] j        JSON value to read from\n    @param[in,out] val  value to write to\n    */\n    template<typename BasicJsonType, typename ValueType>\n    static auto from_json(BasicJsonType&& j, ValueType& val) noexcept(\n        noexcept(::nlohmann::from_json(std::forward<BasicJsonType>(j), val)))\n    -> decltype(::nlohmann::from_json(std::forward<BasicJsonType>(j), val), void())\n    {\n        ::nlohmann::from_json(std::forward<BasicJsonType>(j), val);\n    }\n\n    /*!\n    @brief convert any value type to a JSON value\n\n    This function is usually called by the constructors of the @ref basic_json\n    class.\n\n    @param[in,out] j  JSON value to write to\n    @param[in] val    value to read from\n    */\n    template <typename BasicJsonType, typename ValueType>\n    static auto to_json(BasicJsonType& j, ValueType&& val) noexcept(\n        noexcept(::nlohmann::to_json(j, std::forward<ValueType>(val))))\n    -> decltype(::nlohmann::to_json(j, std::forward<ValueType>(val)), void())\n    {\n        ::nlohmann::to_json(j, std::forward<ValueType>(val));\n    }\n};\n\n}  // namespace nlohmann\n\n\n/*!\n@brief namespace for Niels Lohmann\n@see https://github.com/nlohmann\n@since version 1.0.0\n*/\nnamespace nlohmann\n{\n\n/*!\n@brief a class to store JSON values\n\n@tparam ObjectType type for JSON objects (`std::map` by default; will be used\nin @ref object_t)\n@tparam ArrayType type for JSON arrays (`std::vector` by default; will be used\nin @ref array_t)\n@tparam StringType type for JSON strings and object keys (`std::string` by\ndefault; will be used in @ref string_t)\n@tparam BooleanType type for JSON booleans (`bool` by default; will be used\nin @ref boolean_t)\n@tparam NumberIntegerType type for JSON integer numbers (`int64_t` by\ndefault; will be used in @ref number_integer_t)\n@tparam NumberUnsignedType type for JSON unsigned integer numbers (@c\n`uint64_t` by default; will be used in @ref number_unsigned_t)\n@tparam NumberFloatType type for JSON floating-point numbers (`double` by\ndefault; will be used in @ref number_float_t)\n@tparam AllocatorType type of the allocator to use (`std::allocator` by\ndefault)\n@tparam JSONSerializer the serializer to resolve internal calls to `to_json()`\nand `from_json()` (@ref adl_serializer by default)\n\n@requirement The class satisfies the following concept requirements:\n- Basic\n - [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible):\n   JSON values can be default constructed. The result will be a JSON null\n   value.\n - [MoveConstructible](https://en.cppreference.com/w/cpp/named_req/MoveConstructible):\n   A JSON value can be constructed from an rvalue argument.\n - [CopyConstructible](https://en.cppreference.com/w/cpp/named_req/CopyConstructible):\n   A JSON value can be copy-constructed from an lvalue expression.\n - [MoveAssignable](https://en.cppreference.com/w/cpp/named_req/MoveAssignable):\n   A JSON value van be assigned from an rvalue argument.\n - [CopyAssignable](https://en.cppreference.com/w/cpp/named_req/CopyAssignable):\n   A JSON value can be copy-assigned from an lvalue expression.\n - [Destructible](https://en.cppreference.com/w/cpp/named_req/Destructible):\n   JSON values can be destructed.\n- Layout\n - [StandardLayoutType](https://en.cppreference.com/w/cpp/named_req/StandardLayoutType):\n   JSON values have\n   [standard layout](https://en.cppreference.com/w/cpp/language/data_members#Standard_layout):\n   All non-static data members are private and standard layout types, the\n   class has no virtual functions or (virtual) base classes.\n- Library-wide\n - [EqualityComparable](https://en.cppreference.com/w/cpp/named_req/EqualityComparable):\n   JSON values can be compared with `==`, see @ref\n   operator==(const_reference,const_reference).\n - [LessThanComparable](https://en.cppreference.com/w/cpp/named_req/LessThanComparable):\n   JSON values can be compared with `<`, see @ref\n   operator<(const_reference,const_reference).\n - [Swappable](https://en.cppreference.com/w/cpp/named_req/Swappable):\n   Any JSON lvalue or rvalue of can be swapped with any lvalue or rvalue of\n   other compatible types, using unqualified function call @ref swap().\n - [NullablePointer](https://en.cppreference.com/w/cpp/named_req/NullablePointer):\n   JSON values can be compared against `std::nullptr_t` objects which are used\n   to model the `null` value.\n- Container\n - [Container](https://en.cppreference.com/w/cpp/named_req/Container):\n   JSON values can be used like STL containers and provide iterator access.\n - [ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer);\n   JSON values can be used like STL containers and provide reverse iterator\n   access.\n\n@invariant The member variables @a m_value and @a m_type have the following\nrelationship:\n- If `m_type == value_t::object`, then `m_value.object != nullptr`.\n- If `m_type == value_t::array`, then `m_value.array != nullptr`.\n- If `m_type == value_t::string`, then `m_value.string != nullptr`.\nThe invariants are checked by member function assert_invariant().\n\n@internal\n@note ObjectType trick from http://stackoverflow.com/a/9860911\n@endinternal\n\n@see [RFC 7159: The JavaScript Object Notation (JSON) Data Interchange\nFormat](http://rfc7159.net/rfc7159)\n\n@since version 1.0.0\n\n@nosubgrouping\n*/\nNLOHMANN_BASIC_JSON_TPL_DECLARATION\nclass basic_json\n{\n  private:\n    template<detail::value_t> friend struct detail::external_constructor;\n    friend ::nlohmann::json_pointer<basic_json>;\n    friend ::nlohmann::detail::parser<basic_json>;\n    friend ::nlohmann::detail::serializer<basic_json>;\n    template<typename BasicJsonType>\n    friend class ::nlohmann::detail::iter_impl;\n    template<typename BasicJsonType, typename CharType>\n    friend class ::nlohmann::detail::binary_writer;\n    template<typename BasicJsonType, typename SAX>\n    friend class ::nlohmann::detail::binary_reader;\n    template<typename BasicJsonType>\n    friend class ::nlohmann::detail::json_sax_dom_parser;\n    template<typename BasicJsonType>\n    friend class ::nlohmann::detail::json_sax_dom_callback_parser;\n\n    /// workaround type for MSVC\n    using basic_json_t = NLOHMANN_BASIC_JSON_TPL;\n\n    // convenience aliases for types residing in namespace detail;\n    using lexer = ::nlohmann::detail::lexer<basic_json>;\n    using parser = ::nlohmann::detail::parser<basic_json>;\n\n    using primitive_iterator_t = ::nlohmann::detail::primitive_iterator_t;\n    template<typename BasicJsonType>\n    using internal_iterator = ::nlohmann::detail::internal_iterator<BasicJsonType>;\n    template<typename BasicJsonType>\n    using iter_impl = ::nlohmann::detail::iter_impl<BasicJsonType>;\n    template<typename Iterator>\n    using iteration_proxy = ::nlohmann::detail::iteration_proxy<Iterator>;\n    template<typename Base> using json_reverse_iterator = ::nlohmann::detail::json_reverse_iterator<Base>;\n\n    template<typename CharType>\n    using output_adapter_t = ::nlohmann::detail::output_adapter_t<CharType>;\n\n    using binary_reader = ::nlohmann::detail::binary_reader<basic_json>;\n    template<typename CharType> using binary_writer = ::nlohmann::detail::binary_writer<basic_json, CharType>;\n\n    using serializer = ::nlohmann::detail::serializer<basic_json>;\n\n  public:\n    using value_t = detail::value_t;\n    /// JSON Pointer, see @ref nlohmann::json_pointer\n    using json_pointer = ::nlohmann::json_pointer<basic_json>;\n    template<typename T, typename SFINAE>\n    using json_serializer = JSONSerializer<T, SFINAE>;\n    /// how to treat decoding errors\n    using error_handler_t = detail::error_handler_t;\n    /// helper type for initializer lists of basic_json values\n    using initializer_list_t = std::initializer_list<detail::json_ref<basic_json>>;\n\n    using input_format_t = detail::input_format_t;\n    /// SAX interface type, see @ref nlohmann::json_sax\n    using json_sax_t = json_sax<basic_json>;\n\n    ////////////////\n    // exceptions //\n    ////////////////\n\n    /// @name exceptions\n    /// Classes to implement user-defined exceptions.\n    /// @{\n\n    /// @copydoc detail::exception\n    using exception = detail::exception;\n    /// @copydoc detail::parse_error\n    using parse_error = detail::parse_error;\n    /// @copydoc detail::invalid_iterator\n    using invalid_iterator = detail::invalid_iterator;\n    /// @copydoc detail::type_error\n    using type_error = detail::type_error;\n    /// @copydoc detail::out_of_range\n    using out_of_range = detail::out_of_range;\n    /// @copydoc detail::other_error\n    using other_error = detail::other_error;\n\n    /// @}\n\n\n    /////////////////////\n    // container types //\n    /////////////////////\n\n    /// @name container types\n    /// The canonic container types to use @ref basic_json like any other STL\n    /// container.\n    /// @{\n\n    /// the type of elements in a basic_json container\n    using value_type = basic_json;\n\n    /// the type of an element reference\n    using reference = value_type&;\n    /// the type of an element const reference\n    using const_reference = const value_type&;\n\n    /// a type to represent differences between iterators\n    using difference_type = std::ptrdiff_t;\n    /// a type to represent container sizes\n    using size_type = std::size_t;\n\n    /// the allocator type\n    using allocator_type = AllocatorType<basic_json>;\n\n    /// the type of an element pointer\n    using pointer = typename std::allocator_traits<allocator_type>::pointer;\n    /// the type of an element const pointer\n    using const_pointer = typename std::allocator_traits<allocator_type>::const_pointer;\n\n    /// an iterator for a basic_json container\n    using iterator = iter_impl<basic_json>;\n    /// a const iterator for a basic_json container\n    using const_iterator = iter_impl<const basic_json>;\n    /// a reverse iterator for a basic_json container\n    using reverse_iterator = json_reverse_iterator<typename basic_json::iterator>;\n    /// a const reverse iterator for a basic_json container\n    using const_reverse_iterator = json_reverse_iterator<typename basic_json::const_iterator>;\n\n    /// @}\n\n\n    /*!\n    @brief returns the allocator associated with the container\n    */\n    static allocator_type get_allocator()\n    {\n        return allocator_type();\n    }\n\n    /*!\n    @brief returns version information on the library\n\n    This function returns a JSON object with information about the library,\n    including the version number and information on the platform and compiler.\n\n    @return JSON object holding version information\n    key         | description\n    ----------- | ---------------\n    `compiler`  | Information on the used compiler. It is an object with the following keys: `c++` (the used C++ standard), `family` (the compiler family; possible values are `clang`, `icc`, `gcc`, `ilecpp`, `msvc`, `pgcpp`, `sunpro`, and `unknown`), and `version` (the compiler version).\n    `copyright` | The copyright line for the library as string.\n    `name`      | The name of the library as string.\n    `platform`  | The used platform as string. Possible values are `win32`, `linux`, `apple`, `unix`, and `unknown`.\n    `url`       | The URL of the project as string.\n    `version`   | The version of the library. It is an object with the following keys: `major`, `minor`, and `patch` as defined by [Semantic Versioning](http://semver.org), and `string` (the version string).\n\n    @liveexample{The following code shows an example output of the `meta()`\n    function.,meta}\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes to any JSON value.\n\n    @complexity Constant.\n\n    @since 2.1.0\n    */\n    static basic_json meta()\n    {\n        basic_json result;\n\n        result[\"copyright\"] = \"(C) 2013-2017 Niels Lohmann\";\n        result[\"name\"] = \"JSON for Modern C++\";\n        result[\"url\"] = \"https://github.com/nlohmann/json\";\n        result[\"version\"][\"string\"] =\n            std::to_string(NLOHMANN_JSON_VERSION_MAJOR) + \".\" +\n            std::to_string(NLOHMANN_JSON_VERSION_MINOR) + \".\" +\n            std::to_string(NLOHMANN_JSON_VERSION_PATCH);\n        result[\"version\"][\"major\"] = NLOHMANN_JSON_VERSION_MAJOR;\n        result[\"version\"][\"minor\"] = NLOHMANN_JSON_VERSION_MINOR;\n        result[\"version\"][\"patch\"] = NLOHMANN_JSON_VERSION_PATCH;\n\n#ifdef _WIN32\n        result[\"platform\"] = \"win32\";\n#elif defined __linux__\n        result[\"platform\"] = \"linux\";\n#elif defined __APPLE__\n        result[\"platform\"] = \"apple\";\n#elif defined __unix__\n        result[\"platform\"] = \"unix\";\n#else\n        result[\"platform\"] = \"unknown\";\n#endif\n\n#if defined(__ICC) || defined(__INTEL_COMPILER)\n        result[\"compiler\"] = {{\"family\", \"icc\"}, {\"version\", __INTEL_COMPILER}};\n#elif defined(__clang__)\n        result[\"compiler\"] = {{\"family\", \"clang\"}, {\"version\", __clang_version__}};\n#elif defined(__GNUC__) || defined(__GNUG__)\n        result[\"compiler\"] = {{\"family\", \"gcc\"}, {\"version\", std::to_string(__GNUC__) + \".\" + std::to_string(__GNUC_MINOR__) + \".\" + std::to_string(__GNUC_PATCHLEVEL__)}};\n#elif defined(__HP_cc) || defined(__HP_aCC)\n        result[\"compiler\"] = \"hp\"\n#elif defined(__IBMCPP__)\n        result[\"compiler\"] = {{\"family\", \"ilecpp\"}, {\"version\", __IBMCPP__}};\n#elif defined(_MSC_VER)\n        result[\"compiler\"] = {{\"family\", \"msvc\"}, {\"version\", _MSC_VER}};\n#elif defined(__PGI)\n        result[\"compiler\"] = {{\"family\", \"pgcpp\"}, {\"version\", __PGI}};\n#elif defined(__SUNPRO_CC)\n        result[\"compiler\"] = {{\"family\", \"sunpro\"}, {\"version\", __SUNPRO_CC}};\n#else\n        result[\"compiler\"] = {{\"family\", \"unknown\"}, {\"version\", \"unknown\"}};\n#endif\n\n#ifdef __cplusplus\n        result[\"compiler\"][\"c++\"] = std::to_string(__cplusplus);\n#else\n        result[\"compiler\"][\"c++\"] = \"unknown\";\n#endif\n        return result;\n    }\n\n\n    ///////////////////////////\n    // JSON value data types //\n    ///////////////////////////\n\n    /// @name JSON value data types\n    /// The data types to store a JSON value. These types are derived from\n    /// the template arguments passed to class @ref basic_json.\n    /// @{\n\n#if defined(JSON_HAS_CPP_14)\n    // Use transparent comparator if possible, combined with perfect forwarding\n    // on find() and count() calls prevents unnecessary string construction.\n    using object_comparator_t = std::less<>;\n#else\n    using object_comparator_t = std::less<StringType>;\n#endif\n\n    /*!\n    @brief a type for an object\n\n    [RFC 7159](http://rfc7159.net/rfc7159) describes JSON objects as follows:\n    > An object is an unordered collection of zero or more name/value pairs,\n    > where a name is a string and a value is a string, number, boolean, null,\n    > object, or array.\n\n    To store objects in C++, a type is defined by the template parameters\n    described below.\n\n    @tparam ObjectType  the container to store objects (e.g., `std::map` or\n    `std::unordered_map`)\n    @tparam StringType the type of the keys or names (e.g., `std::string`).\n    The comparison function `std::less<StringType>` is used to order elements\n    inside the container.\n    @tparam AllocatorType the allocator to use for objects (e.g.,\n    `std::allocator`)\n\n    #### Default type\n\n    With the default values for @a ObjectType (`std::map`), @a StringType\n    (`std::string`), and @a AllocatorType (`std::allocator`), the default\n    value for @a object_t is:\n\n    @code {.cpp}\n    std::map<\n      std::string, // key_type\n      basic_json, // value_type\n      std::less<std::string>, // key_compare\n      std::allocator<std::pair<const std::string, basic_json>> // allocator_type\n    >\n    @endcode\n\n    #### Behavior\n\n    The choice of @a object_t influences the behavior of the JSON class. With\n    the default type, objects have the following behavior:\n\n    - When all names are unique, objects will be interoperable in the sense\n      that all software implementations receiving that object will agree on\n      the name-value mappings.\n    - When the names within an object are not unique, it is unspecified which\n      one of the values for a given key will be chosen. For instance,\n      `{\"key\": 2, \"key\": 1}` could be equal to either `{\"key\": 1}` or\n      `{\"key\": 2}`.\n    - Internally, name/value pairs are stored in lexicographical order of the\n      names. Objects will also be serialized (see @ref dump) in this order.\n      For instance, `{\"b\": 1, \"a\": 2}` and `{\"a\": 2, \"b\": 1}` will be stored\n      and serialized as `{\"a\": 2, \"b\": 1}`.\n    - When comparing objects, the order of the name/value pairs is irrelevant.\n      This makes objects interoperable in the sense that they will not be\n      affected by these differences. For instance, `{\"b\": 1, \"a\": 2}` and\n      `{\"a\": 2, \"b\": 1}` will be treated as equal.\n\n    #### Limits\n\n    [RFC 7159](http://rfc7159.net/rfc7159) specifies:\n    > An implementation may set limits on the maximum depth of nesting.\n\n    In this class, the object's limit of nesting is not explicitly constrained.\n    However, a maximum depth of nesting may be introduced by the compiler or\n    runtime environment. A theoretical limit can be queried by calling the\n    @ref max_size function of a JSON object.\n\n    #### Storage\n\n    Objects are stored as pointers in a @ref basic_json type. That is, for any\n    access to object values, a pointer of type `object_t*` must be\n    dereferenced.\n\n    @sa @ref array_t -- type for an array value\n\n    @since version 1.0.0\n\n    @note The order name/value pairs are added to the object is *not*\n    preserved by the library. Therefore, iterating an object may return\n    name/value pairs in a different order than they were originally stored. In\n    fact, keys will be traversed in alphabetical order as `std::map` with\n    `std::less` is used by default. Please note this behavior conforms to [RFC\n    7159](http://rfc7159.net/rfc7159), because any order implements the\n    specified \"unordered\" nature of JSON objects.\n    */\n    using object_t = ObjectType<StringType,\n          basic_json,\n          object_comparator_t,\n          AllocatorType<std::pair<const StringType,\n          basic_json>>>;\n\n    /*!\n    @brief a type for an array\n\n    [RFC 7159](http://rfc7159.net/rfc7159) describes JSON arrays as follows:\n    > An array is an ordered sequence of zero or more values.\n\n    To store objects in C++, a type is defined by the template parameters\n    explained below.\n\n    @tparam ArrayType  container type to store arrays (e.g., `std::vector` or\n    `std::list`)\n    @tparam AllocatorType allocator to use for arrays (e.g., `std::allocator`)\n\n    #### Default type\n\n    With the default values for @a ArrayType (`std::vector`) and @a\n    AllocatorType (`std::allocator`), the default value for @a array_t is:\n\n    @code {.cpp}\n    std::vector<\n      basic_json, // value_type\n      std::allocator<basic_json> // allocator_type\n    >\n    @endcode\n\n    #### Limits\n\n    [RFC 7159](http://rfc7159.net/rfc7159) specifies:\n    > An implementation may set limits on the maximum depth of nesting.\n\n    In this class, the array's limit of nesting is not explicitly constrained.\n    However, a maximum depth of nesting may be introduced by the compiler or\n    runtime environment. A theoretical limit can be queried by calling the\n    @ref max_size function of a JSON array.\n\n    #### Storage\n\n    Arrays are stored as pointers in a @ref basic_json type. That is, for any\n    access to array values, a pointer of type `array_t*` must be dereferenced.\n\n    @sa @ref object_t -- type for an object value\n\n    @since version 1.0.0\n    */\n    using array_t = ArrayType<basic_json, AllocatorType<basic_json>>;\n\n    /*!\n    @brief a type for a string\n\n    [RFC 7159](http://rfc7159.net/rfc7159) describes JSON strings as follows:\n    > A string is a sequence of zero or more Unicode characters.\n\n    To store objects in C++, a type is defined by the template parameter\n    described below. Unicode values are split by the JSON class into\n    byte-sized characters during deserialization.\n\n    @tparam StringType  the container to store strings (e.g., `std::string`).\n    Note this container is used for keys/names in objects, see @ref object_t.\n\n    #### Default type\n\n    With the default values for @a StringType (`std::string`), the default\n    value for @a string_t is:\n\n    @code {.cpp}\n    std::string\n    @endcode\n\n    #### Encoding\n\n    Strings are stored in UTF-8 encoding. Therefore, functions like\n    `std::string::size()` or `std::string::length()` return the number of\n    bytes in the string rather than the number of characters or glyphs.\n\n    #### String comparison\n\n    [RFC 7159](http://rfc7159.net/rfc7159) states:\n    > Software implementations are typically required to test names of object\n    > members for equality. Implementations that transform the textual\n    > representation into sequences of Unicode code units and then perform the\n    > comparison numerically, code unit by code unit, are interoperable in the\n    > sense that implementations will agree in all cases on equality or\n    > inequality of two strings. For example, implementations that compare\n    > strings with escaped characters unconverted may incorrectly find that\n    > `\"a\\\\b\"` and `\"a\\u005Cb\"` are not equal.\n\n    This implementation is interoperable as it does compare strings code unit\n    by code unit.\n\n    #### Storage\n\n    String values are stored as pointers in a @ref basic_json type. That is,\n    for any access to string values, a pointer of type `string_t*` must be\n    dereferenced.\n\n    @since version 1.0.0\n    */\n    using string_t = StringType;\n\n    /*!\n    @brief a type for a boolean\n\n    [RFC 7159](http://rfc7159.net/rfc7159) implicitly describes a boolean as a\n    type which differentiates the two literals `true` and `false`.\n\n    To store objects in C++, a type is defined by the template parameter @a\n    BooleanType which chooses the type to use.\n\n    #### Default type\n\n    With the default values for @a BooleanType (`bool`), the default value for\n    @a boolean_t is:\n\n    @code {.cpp}\n    bool\n    @endcode\n\n    #### Storage\n\n    Boolean values are stored directly inside a @ref basic_json type.\n\n    @since version 1.0.0\n    */\n    using boolean_t = BooleanType;\n\n    /*!\n    @brief a type for a number (integer)\n\n    [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows:\n    > The representation of numbers is similar to that used in most\n    > programming languages. A number is represented in base 10 using decimal\n    > digits. It contains an integer component that may be prefixed with an\n    > optional minus sign, which may be followed by a fraction part and/or an\n    > exponent part. Leading zeros are not allowed. (...) Numeric values that\n    > cannot be represented in the grammar below (such as Infinity and NaN)\n    > are not permitted.\n\n    This description includes both integer and floating-point numbers.\n    However, C++ allows more precise storage if it is known whether the number\n    is a signed integer, an unsigned integer or a floating-point number.\n    Therefore, three different types, @ref number_integer_t, @ref\n    number_unsigned_t and @ref number_float_t are used.\n\n    To store integer numbers in C++, a type is defined by the template\n    parameter @a NumberIntegerType which chooses the type to use.\n\n    #### Default type\n\n    With the default values for @a NumberIntegerType (`int64_t`), the default\n    value for @a number_integer_t is:\n\n    @code {.cpp}\n    int64_t\n    @endcode\n\n    #### Default behavior\n\n    - The restrictions about leading zeros is not enforced in C++. Instead,\n      leading zeros in integer literals lead to an interpretation as octal\n      number. Internally, the value will be stored as decimal number. For\n      instance, the C++ integer literal `010` will be serialized to `8`.\n      During deserialization, leading zeros yield an error.\n    - Not-a-number (NaN) values will be serialized to `null`.\n\n    #### Limits\n\n    [RFC 7159](http://rfc7159.net/rfc7159) specifies:\n    > An implementation may set limits on the range and precision of numbers.\n\n    When the default type is used, the maximal integer number that can be\n    stored is `9223372036854775807` (INT64_MAX) and the minimal integer number\n    that can be stored is `-9223372036854775808` (INT64_MIN). Integer numbers\n    that are out of range will yield over/underflow when used in a\n    constructor. During deserialization, too large or small integer numbers\n    will be automatically be stored as @ref number_unsigned_t or @ref\n    number_float_t.\n\n    [RFC 7159](http://rfc7159.net/rfc7159) further states:\n    > Note that when such software is used, numbers that are integers and are\n    > in the range \\f$[-2^{53}+1, 2^{53}-1]\\f$ are interoperable in the sense\n    > that implementations will agree exactly on their numeric values.\n\n    As this range is a subrange of the exactly supported range [INT64_MIN,\n    INT64_MAX], this class's integer type is interoperable.\n\n    #### Storage\n\n    Integer number values are stored directly inside a @ref basic_json type.\n\n    @sa @ref number_float_t -- type for number values (floating-point)\n\n    @sa @ref number_unsigned_t -- type for number values (unsigned integer)\n\n    @since version 1.0.0\n    */\n    using number_integer_t = NumberIntegerType;\n\n    /*!\n    @brief a type for a number (unsigned)\n\n    [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows:\n    > The representation of numbers is similar to that used in most\n    > programming languages. A number is represented in base 10 using decimal\n    > digits. It contains an integer component that may be prefixed with an\n    > optional minus sign, which may be followed by a fraction part and/or an\n    > exponent part. Leading zeros are not allowed. (...) Numeric values that\n    > cannot be represented in the grammar below (such as Infinity and NaN)\n    > are not permitted.\n\n    This description includes both integer and floating-point numbers.\n    However, C++ allows more precise storage if it is known whether the number\n    is a signed integer, an unsigned integer or a floating-point number.\n    Therefore, three different types, @ref number_integer_t, @ref\n    number_unsigned_t and @ref number_float_t are used.\n\n    To store unsigned integer numbers in C++, a type is defined by the\n    template parameter @a NumberUnsignedType which chooses the type to use.\n\n    #### Default type\n\n    With the default values for @a NumberUnsignedType (`uint64_t`), the\n    default value for @a number_unsigned_t is:\n\n    @code {.cpp}\n    uint64_t\n    @endcode\n\n    #### Default behavior\n\n    - The restrictions about leading zeros is not enforced in C++. Instead,\n      leading zeros in integer literals lead to an interpretation as octal\n      number. Internally, the value will be stored as decimal number. For\n      instance, the C++ integer literal `010` will be serialized to `8`.\n      During deserialization, leading zeros yield an error.\n    - Not-a-number (NaN) values will be serialized to `null`.\n\n    #### Limits\n\n    [RFC 7159](http://rfc7159.net/rfc7159) specifies:\n    > An implementation may set limits on the range and precision of numbers.\n\n    When the default type is used, the maximal integer number that can be\n    stored is `18446744073709551615` (UINT64_MAX) and the minimal integer\n    number that can be stored is `0`. Integer numbers that are out of range\n    will yield over/underflow when used in a constructor. During\n    deserialization, too large or small integer numbers will be automatically\n    be stored as @ref number_integer_t or @ref number_float_t.\n\n    [RFC 7159](http://rfc7159.net/rfc7159) further states:\n    > Note that when such software is used, numbers that are integers and are\n    > in the range \\f$[-2^{53}+1, 2^{53}-1]\\f$ are interoperable in the sense\n    > that implementations will agree exactly on their numeric values.\n\n    As this range is a subrange (when considered in conjunction with the\n    number_integer_t type) of the exactly supported range [0, UINT64_MAX],\n    this class's integer type is interoperable.\n\n    #### Storage\n\n    Integer number values are stored directly inside a @ref basic_json type.\n\n    @sa @ref number_float_t -- type for number values (floating-point)\n    @sa @ref number_integer_t -- type for number values (integer)\n\n    @since version 2.0.0\n    */\n    using number_unsigned_t = NumberUnsignedType;\n\n    /*!\n    @brief a type for a number (floating-point)\n\n    [RFC 7159](http://rfc7159.net/rfc7159) describes numbers as follows:\n    > The representation of numbers is similar to that used in most\n    > programming languages. A number is represented in base 10 using decimal\n    > digits. It contains an integer component that may be prefixed with an\n    > optional minus sign, which may be followed by a fraction part and/or an\n    > exponent part. Leading zeros are not allowed. (...) Numeric values that\n    > cannot be represented in the grammar below (such as Infinity and NaN)\n    > are not permitted.\n\n    This description includes both integer and floating-point numbers.\n    However, C++ allows more precise storage if it is known whether the number\n    is a signed integer, an unsigned integer or a floating-point number.\n    Therefore, three different types, @ref number_integer_t, @ref\n    number_unsigned_t and @ref number_float_t are used.\n\n    To store floating-point numbers in C++, a type is defined by the template\n    parameter @a NumberFloatType which chooses the type to use.\n\n    #### Default type\n\n    With the default values for @a NumberFloatType (`double`), the default\n    value for @a number_float_t is:\n\n    @code {.cpp}\n    double\n    @endcode\n\n    #### Default behavior\n\n    - The restrictions about leading zeros is not enforced in C++. Instead,\n      leading zeros in floating-point literals will be ignored. Internally,\n      the value will be stored as decimal number. For instance, the C++\n      floating-point literal `01.2` will be serialized to `1.2`. During\n      deserialization, leading zeros yield an error.\n    - Not-a-number (NaN) values will be serialized to `null`.\n\n    #### Limits\n\n    [RFC 7159](http://rfc7159.net/rfc7159) states:\n    > This specification allows implementations to set limits on the range and\n    > precision of numbers accepted. Since software that implements IEEE\n    > 754-2008 binary64 (double precision) numbers is generally available and\n    > widely used, good interoperability can be achieved by implementations\n    > that expect no more precision or range than these provide, in the sense\n    > that implementations will approximate JSON numbers within the expected\n    > precision.\n\n    This implementation does exactly follow this approach, as it uses double\n    precision floating-point numbers. Note values smaller than\n    `-1.79769313486232e+308` and values greater than `1.79769313486232e+308`\n    will be stored as NaN internally and be serialized to `null`.\n\n    #### Storage\n\n    Floating-point number values are stored directly inside a @ref basic_json\n    type.\n\n    @sa @ref number_integer_t -- type for number values (integer)\n\n    @sa @ref number_unsigned_t -- type for number values (unsigned integer)\n\n    @since version 1.0.0\n    */\n    using number_float_t = NumberFloatType;\n\n    /// @}\n\n  private:\n\n    /// helper for exception-safe object creation\n    template<typename T, typename... Args>\n    static T* create(Args&& ... args)\n    {\n        AllocatorType<T> alloc;\n        using AllocatorTraits = std::allocator_traits<AllocatorType<T>>;\n\n        auto deleter = [&](T * object)\n        {\n            AllocatorTraits::deallocate(alloc, object, 1);\n        };\n        std::unique_ptr<T, decltype(deleter)> object(AllocatorTraits::allocate(alloc, 1), deleter);\n        AllocatorTraits::construct(alloc, object.get(), std::forward<Args>(args)...);\n        assert(object != nullptr);\n        return object.release();\n    }\n\n    ////////////////////////\n    // JSON value storage //\n    ////////////////////////\n\n    /*!\n    @brief a JSON value\n\n    The actual storage for a JSON value of the @ref basic_json class. This\n    union combines the different storage types for the JSON value types\n    defined in @ref value_t.\n\n    JSON type | value_t type    | used type\n    --------- | --------------- | ------------------------\n    object    | object          | pointer to @ref object_t\n    array     | array           | pointer to @ref array_t\n    string    | string          | pointer to @ref string_t\n    boolean   | boolean         | @ref boolean_t\n    number    | number_integer  | @ref number_integer_t\n    number    | number_unsigned | @ref number_unsigned_t\n    number    | number_float    | @ref number_float_t\n    null      | null            | *no value is stored*\n\n    @note Variable-length types (objects, arrays, and strings) are stored as\n    pointers. The size of the union should not exceed 64 bits if the default\n    value types are used.\n\n    @since version 1.0.0\n    */\n    union json_value\n    {\n        /// object (stored with pointer to save storage)\n        object_t* object;\n        /// array (stored with pointer to save storage)\n        array_t* array;\n        /// string (stored with pointer to save storage)\n        string_t* string;\n        /// boolean\n        boolean_t boolean;\n        /// number (integer)\n        number_integer_t number_integer;\n        /// number (unsigned integer)\n        number_unsigned_t number_unsigned;\n        /// number (floating-point)\n        number_float_t number_float;\n\n        /// default constructor (for null values)\n        json_value() = default;\n        /// constructor for booleans\n        json_value(boolean_t v) noexcept : boolean(v) {}\n        /// constructor for numbers (integer)\n        json_value(number_integer_t v) noexcept : number_integer(v) {}\n        /// constructor for numbers (unsigned)\n        json_value(number_unsigned_t v) noexcept : number_unsigned(v) {}\n        /// constructor for numbers (floating-point)\n        json_value(number_float_t v) noexcept : number_float(v) {}\n        /// constructor for empty values of a given type\n        json_value(value_t t)\n        {\n            switch (t)\n            {\n                case value_t::object:\n                {\n                    object = create<object_t>();\n                    break;\n                }\n\n                case value_t::array:\n                {\n                    array = create<array_t>();\n                    break;\n                }\n\n                case value_t::string:\n                {\n                    string = create<string_t>(\"\");\n                    break;\n                }\n\n                case value_t::boolean:\n                {\n                    boolean = boolean_t(false);\n                    break;\n                }\n\n                case value_t::number_integer:\n                {\n                    number_integer = number_integer_t(0);\n                    break;\n                }\n\n                case value_t::number_unsigned:\n                {\n                    number_unsigned = number_unsigned_t(0);\n                    break;\n                }\n\n                case value_t::number_float:\n                {\n                    number_float = number_float_t(0.0);\n                    break;\n                }\n\n                case value_t::null:\n                {\n                    object = nullptr;  // silence warning, see #821\n                    break;\n                }\n\n                default:\n                {\n                    object = nullptr;  // silence warning, see #821\n                    if (JSON_UNLIKELY(t == value_t::null))\n                    {\n                        JSON_THROW(other_error::create(500, \"961c151d2e87f2686a955a9be24d316f1362bf21 3.5.0\")); // LCOV_EXCL_LINE\n                    }\n                    break;\n                }\n            }\n        }\n\n        /// constructor for strings\n        json_value(const string_t& value)\n        {\n            string = create<string_t>(value);\n        }\n\n        /// constructor for rvalue strings\n        json_value(string_t&& value)\n        {\n            string = create<string_t>(std::move(value));\n        }\n\n        /// constructor for objects\n        json_value(const object_t& value)\n        {\n            object = create<object_t>(value);\n        }\n\n        /// constructor for rvalue objects\n        json_value(object_t&& value)\n        {\n            object = create<object_t>(std::move(value));\n        }\n\n        /// constructor for arrays\n        json_value(const array_t& value)\n        {\n            array = create<array_t>(value);\n        }\n\n        /// constructor for rvalue arrays\n        json_value(array_t&& value)\n        {\n            array = create<array_t>(std::move(value));\n        }\n\n        void destroy(value_t t) noexcept\n        {\n            switch (t)\n            {\n                case value_t::object:\n                {\n                    AllocatorType<object_t> alloc;\n                    std::allocator_traits<decltype(alloc)>::destroy(alloc, object);\n                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, object, 1);\n                    break;\n                }\n\n                case value_t::array:\n                {\n                    AllocatorType<array_t> alloc;\n                    std::allocator_traits<decltype(alloc)>::destroy(alloc, array);\n                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, array, 1);\n                    break;\n                }\n\n                case value_t::string:\n                {\n                    AllocatorType<string_t> alloc;\n                    std::allocator_traits<decltype(alloc)>::destroy(alloc, string);\n                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, string, 1);\n                    break;\n                }\n\n                default:\n                {\n                    break;\n                }\n            }\n        }\n    };\n\n    /*!\n    @brief checks the class invariants\n\n    This function asserts the class invariants. It needs to be called at the\n    end of every constructor to make sure that created objects respect the\n    invariant. Furthermore, it has to be called each time the type of a JSON\n    value is changed, because the invariant expresses a relationship between\n    @a m_type and @a m_value.\n    */\n    void assert_invariant() const noexcept\n    {\n        assert(m_type != value_t::object or m_value.object != nullptr);\n        assert(m_type != value_t::array or m_value.array != nullptr);\n        assert(m_type != value_t::string or m_value.string != nullptr);\n    }\n\n  public:\n    //////////////////////////\n    // JSON parser callback //\n    //////////////////////////\n\n    /*!\n    @brief parser event types\n\n    The parser callback distinguishes the following events:\n    - `object_start`: the parser read `{` and started to process a JSON object\n    - `key`: the parser read a key of a value in an object\n    - `object_end`: the parser read `}` and finished processing a JSON object\n    - `array_start`: the parser read `[` and started to process a JSON array\n    - `array_end`: the parser read `]` and finished processing a JSON array\n    - `value`: the parser finished reading a JSON value\n\n    @image html callback_events.png \"Example when certain parse events are triggered\"\n\n    @sa @ref parser_callback_t for more information and examples\n    */\n    using parse_event_t = typename parser::parse_event_t;\n\n    /*!\n    @brief per-element parser callback type\n\n    With a parser callback function, the result of parsing a JSON text can be\n    influenced. When passed to @ref parse, it is called on certain events\n    (passed as @ref parse_event_t via parameter @a event) with a set recursion\n    depth @a depth and context JSON value @a parsed. The return value of the\n    callback function is a boolean indicating whether the element that emitted\n    the callback shall be kept or not.\n\n    We distinguish six scenarios (determined by the event type) in which the\n    callback function can be called. The following table describes the values\n    of the parameters @a depth, @a event, and @a parsed.\n\n    parameter @a event | description | parameter @a depth | parameter @a parsed\n    ------------------ | ----------- | ------------------ | -------------------\n    parse_event_t::object_start | the parser read `{` and started to process a JSON object | depth of the parent of the JSON object | a JSON value with type discarded\n    parse_event_t::key | the parser read a key of a value in an object | depth of the currently parsed JSON object | a JSON string containing the key\n    parse_event_t::object_end | the parser read `}` and finished processing a JSON object | depth of the parent of the JSON object | the parsed JSON object\n    parse_event_t::array_start | the parser read `[` and started to process a JSON array | depth of the parent of the JSON array | a JSON value with type discarded\n    parse_event_t::array_end | the parser read `]` and finished processing a JSON array | depth of the parent of the JSON array | the parsed JSON array\n    parse_event_t::value | the parser finished reading a JSON value | depth of the value | the parsed JSON value\n\n    @image html callback_events.png \"Example when certain parse events are triggered\"\n\n    Discarding a value (i.e., returning `false`) has different effects\n    depending on the context in which function was called:\n\n    - Discarded values in structured types are skipped. That is, the parser\n      will behave as if the discarded value was never read.\n    - In case a value outside a structured type is skipped, it is replaced\n      with `null`. This case happens if the top-level element is skipped.\n\n    @param[in] depth  the depth of the recursion during parsing\n\n    @param[in] event  an event of type parse_event_t indicating the context in\n    the callback function has been called\n\n    @param[in,out] parsed  the current intermediate parse result; note that\n    writing to this value has no effect for parse_event_t::key events\n\n    @return Whether the JSON value which called the function during parsing\n    should be kept (`true`) or not (`false`). In the latter case, it is either\n    skipped completely or replaced by an empty discarded object.\n\n    @sa @ref parse for examples\n\n    @since version 1.0.0\n    */\n    using parser_callback_t = typename parser::parser_callback_t;\n\n    //////////////////\n    // constructors //\n    //////////////////\n\n    /// @name constructors and destructors\n    /// Constructors of class @ref basic_json, copy/move constructor, copy\n    /// assignment, static functions creating objects, and the destructor.\n    /// @{\n\n    /*!\n    @brief create an empty value with a given type\n\n    Create an empty JSON value with a given type. The value will be default\n    initialized with an empty value which depends on the type:\n\n    Value type  | initial value\n    ----------- | -------------\n    null        | `null`\n    boolean     | `false`\n    string      | `\"\"`\n    number      | `0`\n    object      | `{}`\n    array       | `[]`\n\n    @param[in] v  the type of the value to create\n\n    @complexity Constant.\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes to any JSON value.\n\n    @liveexample{The following code shows the constructor for different @ref\n    value_t values,basic_json__value_t}\n\n    @sa @ref clear() -- restores the postcondition of this constructor\n\n    @since version 1.0.0\n    */\n    basic_json(const value_t v)\n        : m_type(v), m_value(v)\n    {\n        assert_invariant();\n    }\n\n    /*!\n    @brief create a null object\n\n    Create a `null` JSON value. It either takes a null pointer as parameter\n    (explicitly creating `null`) or no parameter (implicitly creating `null`).\n    The passed null pointer itself is not read -- it is only used to choose\n    the right constructor.\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this constructor never throws\n    exceptions.\n\n    @liveexample{The following code shows the constructor with and without a\n    null pointer parameter.,basic_json__nullptr_t}\n\n    @since version 1.0.0\n    */\n    basic_json(std::nullptr_t = nullptr) noexcept\n        : basic_json(value_t::null)\n    {\n        assert_invariant();\n    }\n\n    /*!\n    @brief create a JSON value\n\n    This is a \"catch all\" constructor for all compatible JSON types; that is,\n    types for which a `to_json()` method exists. The constructor forwards the\n    parameter @a val to that method (to `json_serializer<U>::to_json` method\n    with `U = uncvref_t<CompatibleType>`, to be exact).\n\n    Template type @a CompatibleType includes, but is not limited to, the\n    following types:\n    - **arrays**: @ref array_t and all kinds of compatible containers such as\n      `std::vector`, `std::deque`, `std::list`, `std::forward_list`,\n      `std::array`, `std::valarray`, `std::set`, `std::unordered_set`,\n      `std::multiset`, and `std::unordered_multiset` with a `value_type` from\n      which a @ref basic_json value can be constructed.\n    - **objects**: @ref object_t and all kinds of compatible associative\n      containers such as `std::map`, `std::unordered_map`, `std::multimap`,\n      and `std::unordered_multimap` with a `key_type` compatible to\n      @ref string_t and a `value_type` from which a @ref basic_json value can\n      be constructed.\n    - **strings**: @ref string_t, string literals, and all compatible string\n      containers can be used.\n    - **numbers**: @ref number_integer_t, @ref number_unsigned_t,\n      @ref number_float_t, and all convertible number types such as `int`,\n      `size_t`, `int64_t`, `float` or `double` can be used.\n    - **boolean**: @ref boolean_t / `bool` can be used.\n\n    See the examples below.\n\n    @tparam CompatibleType a type such that:\n    - @a CompatibleType is not derived from `std::istream`,\n    - @a CompatibleType is not @ref basic_json (to avoid hijacking copy/move\n         constructors),\n    - @a CompatibleType is not a different @ref basic_json type (i.e. with different template arguments)\n    - @a CompatibleType is not a @ref basic_json nested type (e.g.,\n         @ref json_pointer, @ref iterator, etc ...)\n    - @ref @ref json_serializer<U> has a\n         `to_json(basic_json_t&, CompatibleType&&)` method\n\n    @tparam U = `uncvref_t<CompatibleType>`\n\n    @param[in] val the value to be forwarded to the respective constructor\n\n    @complexity Usually linear in the size of the passed @a val, also\n                depending on the implementation of the called `to_json()`\n                method.\n\n    @exceptionsafety Depends on the called constructor. For types directly\n    supported by the library (i.e., all types for which no `to_json()` function\n    was provided), strong guarantee holds: if an exception is thrown, there are\n    no changes to any JSON value.\n\n    @liveexample{The following code shows the constructor with several\n    compatible types.,basic_json__CompatibleType}\n\n    @since version 2.1.0\n    */\n    template <typename CompatibleType,\n              typename U = detail::uncvref_t<CompatibleType>,\n              detail::enable_if_t<\n                  not detail::is_basic_json<U>::value and detail::is_compatible_type<basic_json_t, U>::value, int> = 0>\n    basic_json(CompatibleType && val) noexcept(noexcept(\n                JSONSerializer<U>::to_json(std::declval<basic_json_t&>(),\n                                           std::forward<CompatibleType>(val))))\n    {\n        JSONSerializer<U>::to_json(*this, std::forward<CompatibleType>(val));\n        assert_invariant();\n    }\n\n    /*!\n    @brief create a JSON value from an existing one\n\n    This is a constructor for existing @ref basic_json types.\n    It does not hijack copy/move constructors, since the parameter has different\n    template arguments than the current ones.\n\n    The constructor tries to convert the internal @ref m_value of the parameter.\n\n    @tparam BasicJsonType a type such that:\n    - @a BasicJsonType is a @ref basic_json type.\n    - @a BasicJsonType has different template arguments than @ref basic_json_t.\n\n    @param[in] val the @ref basic_json value to be converted.\n\n    @complexity Usually linear in the size of the passed @a val, also\n                depending on the implementation of the called `to_json()`\n                method.\n\n    @exceptionsafety Depends on the called constructor. For types directly\n    supported by the library (i.e., all types for which no `to_json()` function\n    was provided), strong guarantee holds: if an exception is thrown, there are\n    no changes to any JSON value.\n\n    @since version 3.2.0\n    */\n    template <typename BasicJsonType,\n              detail::enable_if_t<\n                  detail::is_basic_json<BasicJsonType>::value and not std::is_same<basic_json, BasicJsonType>::value, int> = 0>\n    basic_json(const BasicJsonType& val)\n    {\n        using other_boolean_t = typename BasicJsonType::boolean_t;\n        using other_number_float_t = typename BasicJsonType::number_float_t;\n        using other_number_integer_t = typename BasicJsonType::number_integer_t;\n        using other_number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n        using other_string_t = typename BasicJsonType::string_t;\n        using other_object_t = typename BasicJsonType::object_t;\n        using other_array_t = typename BasicJsonType::array_t;\n\n        switch (val.type())\n        {\n            case value_t::boolean:\n                JSONSerializer<other_boolean_t>::to_json(*this, val.template get<other_boolean_t>());\n                break;\n            case value_t::number_float:\n                JSONSerializer<other_number_float_t>::to_json(*this, val.template get<other_number_float_t>());\n                break;\n            case value_t::number_integer:\n                JSONSerializer<other_number_integer_t>::to_json(*this, val.template get<other_number_integer_t>());\n                break;\n            case value_t::number_unsigned:\n                JSONSerializer<other_number_unsigned_t>::to_json(*this, val.template get<other_number_unsigned_t>());\n                break;\n            case value_t::string:\n                JSONSerializer<other_string_t>::to_json(*this, val.template get_ref<const other_string_t&>());\n                break;\n            case value_t::object:\n                JSONSerializer<other_object_t>::to_json(*this, val.template get_ref<const other_object_t&>());\n                break;\n            case value_t::array:\n                JSONSerializer<other_array_t>::to_json(*this, val.template get_ref<const other_array_t&>());\n                break;\n            case value_t::null:\n                *this = nullptr;\n                break;\n            case value_t::discarded:\n                m_type = value_t::discarded;\n                break;\n        }\n        assert_invariant();\n    }\n\n    /*!\n    @brief create a container (array or object) from an initializer list\n\n    Creates a JSON value of type array or object from the passed initializer\n    list @a init. In case @a type_deduction is `true` (default), the type of\n    the JSON value to be created is deducted from the initializer list @a init\n    according to the following rules:\n\n    1. If the list is empty, an empty JSON object value `{}` is created.\n    2. If the list consists of pairs whose first element is a string, a JSON\n       object value is created where the first elements of the pairs are\n       treated as keys and the second elements are as values.\n    3. In all other cases, an array is created.\n\n    The rules aim to create the best fit between a C++ initializer list and\n    JSON values. The rationale is as follows:\n\n    1. The empty initializer list is written as `{}` which is exactly an empty\n       JSON object.\n    2. C++ has no way of describing mapped types other than to list a list of\n       pairs. As JSON requires that keys must be of type string, rule 2 is the\n       weakest constraint one can pose on initializer lists to interpret them\n       as an object.\n    3. In all other cases, the initializer list could not be interpreted as\n       JSON object type, so interpreting it as JSON array type is safe.\n\n    With the rules described above, the following JSON values cannot be\n    expressed by an initializer list:\n\n    - the empty array (`[]`): use @ref array(initializer_list_t)\n      with an empty initializer list in this case\n    - arrays whose elements satisfy rule 2: use @ref\n      array(initializer_list_t) with the same initializer list\n      in this case\n\n    @note When used without parentheses around an empty initializer list, @ref\n    basic_json() is called instead of this function, yielding the JSON null\n    value.\n\n    @param[in] init  initializer list with JSON values\n\n    @param[in] type_deduction internal parameter; when set to `true`, the type\n    of the JSON value is deducted from the initializer list @a init; when set\n    to `false`, the type provided via @a manual_type is forced. This mode is\n    used by the functions @ref array(initializer_list_t) and\n    @ref object(initializer_list_t).\n\n    @param[in] manual_type internal parameter; when @a type_deduction is set\n    to `false`, the created JSON value will use the provided type (only @ref\n    value_t::array and @ref value_t::object are valid); when @a type_deduction\n    is set to `true`, this parameter has no effect\n\n    @throw type_error.301 if @a type_deduction is `false`, @a manual_type is\n    `value_t::object`, but @a init contains an element which is not a pair\n    whose first element is a string. In this case, the constructor could not\n    create an object. If @a type_deduction would have be `true`, an array\n    would have been created. See @ref object(initializer_list_t)\n    for an example.\n\n    @complexity Linear in the size of the initializer list @a init.\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes to any JSON value.\n\n    @liveexample{The example below shows how JSON values are created from\n    initializer lists.,basic_json__list_init_t}\n\n    @sa @ref array(initializer_list_t) -- create a JSON array\n    value from an initializer list\n    @sa @ref object(initializer_list_t) -- create a JSON object\n    value from an initializer list\n\n    @since version 1.0.0\n    */\n    basic_json(initializer_list_t init,\n               bool type_deduction = true,\n               value_t manual_type = value_t::array)\n    {\n        // check if each element is an array with two elements whose first\n        // element is a string\n        bool is_an_object = std::all_of(init.begin(), init.end(),\n                                        [](const detail::json_ref<basic_json>& element_ref)\n        {\n            return (element_ref->is_array() and element_ref->size() == 2 and (*element_ref)[0].is_string());\n        });\n\n        // adjust type if type deduction is not wanted\n        if (not type_deduction)\n        {\n            // if array is wanted, do not create an object though possible\n            if (manual_type == value_t::array)\n            {\n                is_an_object = false;\n            }\n\n            // if object is wanted but impossible, throw an exception\n            if (JSON_UNLIKELY(manual_type == value_t::object and not is_an_object))\n            {\n                JSON_THROW(type_error::create(301, \"cannot create object from initializer list\"));\n            }\n        }\n\n        if (is_an_object)\n        {\n            // the initializer list is a list of pairs -> create object\n            m_type = value_t::object;\n            m_value = value_t::object;\n\n            std::for_each(init.begin(), init.end(), [this](const detail::json_ref<basic_json>& element_ref)\n            {\n                auto element = element_ref.moved_or_copied();\n                m_value.object->emplace(\n                    std::move(*((*element.m_value.array)[0].m_value.string)),\n                    std::move((*element.m_value.array)[1]));\n            });\n        }\n        else\n        {\n            // the initializer list describes an array -> create array\n            m_type = value_t::array;\n            m_value.array = create<array_t>(init.begin(), init.end());\n        }\n\n        assert_invariant();\n    }\n\n    /*!\n    @brief explicitly create an array from an initializer list\n\n    Creates a JSON array value from a given initializer list. That is, given a\n    list of values `a, b, c`, creates the JSON value `[a, b, c]`. If the\n    initializer list is empty, the empty array `[]` is created.\n\n    @note This function is only needed to express two edge cases that cannot\n    be realized with the initializer list constructor (@ref\n    basic_json(initializer_list_t, bool, value_t)). These cases\n    are:\n    1. creating an array whose elements are all pairs whose first element is a\n    string -- in this case, the initializer list constructor would create an\n    object, taking the first elements as keys\n    2. creating an empty array -- passing the empty initializer list to the\n    initializer list constructor yields an empty object\n\n    @param[in] init  initializer list with JSON values to create an array from\n    (optional)\n\n    @return JSON array value\n\n    @complexity Linear in the size of @a init.\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes to any JSON value.\n\n    @liveexample{The following code shows an example for the `array`\n    function.,array}\n\n    @sa @ref basic_json(initializer_list_t, bool, value_t) --\n    create a JSON value from an initializer list\n    @sa @ref object(initializer_list_t) -- create a JSON object\n    value from an initializer list\n\n    @since version 1.0.0\n    */\n    static basic_json array(initializer_list_t init = {})\n    {\n        return basic_json(init, false, value_t::array);\n    }\n\n    /*!\n    @brief explicitly create an object from an initializer list\n\n    Creates a JSON object value from a given initializer list. The initializer\n    lists elements must be pairs, and their first elements must be strings. If\n    the initializer list is empty, the empty object `{}` is created.\n\n    @note This function is only added for symmetry reasons. In contrast to the\n    related function @ref array(initializer_list_t), there are\n    no cases which can only be expressed by this function. That is, any\n    initializer list @a init can also be passed to the initializer list\n    constructor @ref basic_json(initializer_list_t, bool, value_t).\n\n    @param[in] init  initializer list to create an object from (optional)\n\n    @return JSON object value\n\n    @throw type_error.301 if @a init is not a list of pairs whose first\n    elements are strings. In this case, no object can be created. When such a\n    value is passed to @ref basic_json(initializer_list_t, bool, value_t),\n    an array would have been created from the passed initializer list @a init.\n    See example below.\n\n    @complexity Linear in the size of @a init.\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes to any JSON value.\n\n    @liveexample{The following code shows an example for the `object`\n    function.,object}\n\n    @sa @ref basic_json(initializer_list_t, bool, value_t) --\n    create a JSON value from an initializer list\n    @sa @ref array(initializer_list_t) -- create a JSON array\n    value from an initializer list\n\n    @since version 1.0.0\n    */\n    static basic_json object(initializer_list_t init = {})\n    {\n        return basic_json(init, false, value_t::object);\n    }\n\n    /*!\n    @brief construct an array with count copies of given value\n\n    Constructs a JSON array value by creating @a cnt copies of a passed value.\n    In case @a cnt is `0`, an empty array is created.\n\n    @param[in] cnt  the number of JSON copies of @a val to create\n    @param[in] val  the JSON value to copy\n\n    @post `std::distance(begin(),end()) == cnt` holds.\n\n    @complexity Linear in @a cnt.\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes to any JSON value.\n\n    @liveexample{The following code shows examples for the @ref\n    basic_json(size_type\\, const basic_json&)\n    constructor.,basic_json__size_type_basic_json}\n\n    @since version 1.0.0\n    */\n    basic_json(size_type cnt, const basic_json& val)\n        : m_type(value_t::array)\n    {\n        m_value.array = create<array_t>(cnt, val);\n        assert_invariant();\n    }\n\n    /*!\n    @brief construct a JSON container given an iterator range\n\n    Constructs the JSON value with the contents of the range `[first, last)`.\n    The semantics depends on the different types a JSON value can have:\n    - In case of a null type, invalid_iterator.206 is thrown.\n    - In case of other primitive types (number, boolean, or string), @a first\n      must be `begin()` and @a last must be `end()`. In this case, the value is\n      copied. Otherwise, invalid_iterator.204 is thrown.\n    - In case of structured types (array, object), the constructor behaves as\n      similar versions for `std::vector` or `std::map`; that is, a JSON array\n      or object is constructed from the values in the range.\n\n    @tparam InputIT an input iterator type (@ref iterator or @ref\n    const_iterator)\n\n    @param[in] first begin of the range to copy from (included)\n    @param[in] last end of the range to copy from (excluded)\n\n    @pre Iterators @a first and @a last must be initialized. **This\n         precondition is enforced with an assertion (see warning).** If\n         assertions are switched off, a violation of this precondition yields\n         undefined behavior.\n\n    @pre Range `[first, last)` is valid. Usually, this precondition cannot be\n         checked efficiently. Only certain edge cases are detected; see the\n         description of the exceptions below. A violation of this precondition\n         yields undefined behavior.\n\n    @warning A precondition is enforced with a runtime assertion that will\n             result in calling `std::abort` if this precondition is not met.\n             Assertions can be disabled by defining `NDEBUG` at compile time.\n             See https://en.cppreference.com/w/cpp/error/assert for more\n             information.\n\n    @throw invalid_iterator.201 if iterators @a first and @a last are not\n    compatible (i.e., do not belong to the same JSON value). In this case,\n    the range `[first, last)` is undefined.\n    @throw invalid_iterator.204 if iterators @a first and @a last belong to a\n    primitive type (number, boolean, or string), but @a first does not point\n    to the first element any more. In this case, the range `[first, last)` is\n    undefined. See example code below.\n    @throw invalid_iterator.206 if iterators @a first and @a last belong to a\n    null value. In this case, the range `[first, last)` is undefined.\n\n    @complexity Linear in distance between @a first and @a last.\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes to any JSON value.\n\n    @liveexample{The example below shows several ways to create JSON values by\n    specifying a subrange with iterators.,basic_json__InputIt_InputIt}\n\n    @since version 1.0.0\n    */\n    template<class InputIT, typename std::enable_if<\n                 std::is_same<InputIT, typename basic_json_t::iterator>::value or\n                 std::is_same<InputIT, typename basic_json_t::const_iterator>::value, int>::type = 0>\n    basic_json(InputIT first, InputIT last)\n    {\n        assert(first.m_object != nullptr);\n        assert(last.m_object != nullptr);\n\n        // make sure iterator fits the current value\n        if (JSON_UNLIKELY(first.m_object != last.m_object))\n        {\n            JSON_THROW(invalid_iterator::create(201, \"iterators are not compatible\"));\n        }\n\n        // copy type from first iterator\n        m_type = first.m_object->m_type;\n\n        // check if iterator range is complete for primitive values\n        switch (m_type)\n        {\n            case value_t::boolean:\n            case value_t::number_float:\n            case value_t::number_integer:\n            case value_t::number_unsigned:\n            case value_t::string:\n            {\n                if (JSON_UNLIKELY(not first.m_it.primitive_iterator.is_begin()\n                                  or not last.m_it.primitive_iterator.is_end()))\n                {\n                    JSON_THROW(invalid_iterator::create(204, \"iterators out of range\"));\n                }\n                break;\n            }\n\n            default:\n                break;\n        }\n\n        switch (m_type)\n        {\n            case value_t::number_integer:\n            {\n                m_value.number_integer = first.m_object->m_value.number_integer;\n                break;\n            }\n\n            case value_t::number_unsigned:\n            {\n                m_value.number_unsigned = first.m_object->m_value.number_unsigned;\n                break;\n            }\n\n            case value_t::number_float:\n            {\n                m_value.number_float = first.m_object->m_value.number_float;\n                break;\n            }\n\n            case value_t::boolean:\n            {\n                m_value.boolean = first.m_object->m_value.boolean;\n                break;\n            }\n\n            case value_t::string:\n            {\n                m_value = *first.m_object->m_value.string;\n                break;\n            }\n\n            case value_t::object:\n            {\n                m_value.object = create<object_t>(first.m_it.object_iterator,\n                                                  last.m_it.object_iterator);\n                break;\n            }\n\n            case value_t::array:\n            {\n                m_value.array = create<array_t>(first.m_it.array_iterator,\n                                                last.m_it.array_iterator);\n                break;\n            }\n\n            default:\n                JSON_THROW(invalid_iterator::create(206, \"cannot construct with iterators from \" +\n                                                    std::string(first.m_object->type_name())));\n        }\n\n        assert_invariant();\n    }\n\n\n    ///////////////////////////////////////\n    // other constructors and destructor //\n    ///////////////////////////////////////\n\n    /// @private\n    basic_json(const detail::json_ref<basic_json>& ref)\n        : basic_json(ref.moved_or_copied())\n    {}\n\n    /*!\n    @brief copy constructor\n\n    Creates a copy of a given JSON value.\n\n    @param[in] other  the JSON value to copy\n\n    @post `*this == other`\n\n    @complexity Linear in the size of @a other.\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes to any JSON value.\n\n    @requirement This function helps `basic_json` satisfying the\n    [Container](https://en.cppreference.com/w/cpp/named_req/Container)\n    requirements:\n    - The complexity is linear.\n    - As postcondition, it holds: `other == basic_json(other)`.\n\n    @liveexample{The following code shows an example for the copy\n    constructor.,basic_json__basic_json}\n\n    @since version 1.0.0\n    */\n    basic_json(const basic_json& other)\n        : m_type(other.m_type)\n    {\n        // check of passed value is valid\n        other.assert_invariant();\n\n        switch (m_type)\n        {\n            case value_t::object:\n            {\n                m_value = *other.m_value.object;\n                break;\n            }\n\n            case value_t::array:\n            {\n                m_value = *other.m_value.array;\n                break;\n            }\n\n            case value_t::string:\n            {\n                m_value = *other.m_value.string;\n                break;\n            }\n\n            case value_t::boolean:\n            {\n                m_value = other.m_value.boolean;\n                break;\n            }\n\n            case value_t::number_integer:\n            {\n                m_value = other.m_value.number_integer;\n                break;\n            }\n\n            case value_t::number_unsigned:\n            {\n                m_value = other.m_value.number_unsigned;\n                break;\n            }\n\n            case value_t::number_float:\n            {\n                m_value = other.m_value.number_float;\n                break;\n            }\n\n            default:\n                break;\n        }\n\n        assert_invariant();\n    }\n\n    /*!\n    @brief move constructor\n\n    Move constructor. Constructs a JSON value with the contents of the given\n    value @a other using move semantics. It \"steals\" the resources from @a\n    other and leaves it as JSON null value.\n\n    @param[in,out] other  value to move to this object\n\n    @post `*this` has the same value as @a other before the call.\n    @post @a other is a JSON null value.\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this constructor never throws\n    exceptions.\n\n    @requirement This function helps `basic_json` satisfying the\n    [MoveConstructible](https://en.cppreference.com/w/cpp/named_req/MoveConstructible)\n    requirements.\n\n    @liveexample{The code below shows the move constructor explicitly called\n    via std::move.,basic_json__moveconstructor}\n\n    @since version 1.0.0\n    */\n    basic_json(basic_json&& other) noexcept\n        : m_type(std::move(other.m_type)),\n          m_value(std::move(other.m_value))\n    {\n        // check that passed value is valid\n        other.assert_invariant();\n\n        // invalidate payload\n        other.m_type = value_t::null;\n        other.m_value = {};\n\n        assert_invariant();\n    }\n\n    /*!\n    @brief copy assignment\n\n    Copy assignment operator. Copies a JSON value via the \"copy and swap\"\n    strategy: It is expressed in terms of the copy constructor, destructor,\n    and the `swap()` member function.\n\n    @param[in] other  value to copy from\n\n    @complexity Linear.\n\n    @requirement This function helps `basic_json` satisfying the\n    [Container](https://en.cppreference.com/w/cpp/named_req/Container)\n    requirements:\n    - The complexity is linear.\n\n    @liveexample{The code below shows and example for the copy assignment. It\n    creates a copy of value `a` which is then swapped with `b`. Finally\\, the\n    copy of `a` (which is the null value after the swap) is\n    destroyed.,basic_json__copyassignment}\n\n    @since version 1.0.0\n    */\n    basic_json& operator=(basic_json other) noexcept (\n        std::is_nothrow_move_constructible<value_t>::value and\n        std::is_nothrow_move_assignable<value_t>::value and\n        std::is_nothrow_move_constructible<json_value>::value and\n        std::is_nothrow_move_assignable<json_value>::value\n    )\n    {\n        // check that passed value is valid\n        other.assert_invariant();\n\n        using std::swap;\n        swap(m_type, other.m_type);\n        swap(m_value, other.m_value);\n\n        assert_invariant();\n        return *this;\n    }\n\n    /*!\n    @brief destructor\n\n    Destroys the JSON value and frees all allocated memory.\n\n    @complexity Linear.\n\n    @requirement This function helps `basic_json` satisfying the\n    [Container](https://en.cppreference.com/w/cpp/named_req/Container)\n    requirements:\n    - The complexity is linear.\n    - All stored elements are destroyed and all memory is freed.\n\n    @since version 1.0.0\n    */\n    ~basic_json() noexcept\n    {\n        assert_invariant();\n        m_value.destroy(m_type);\n    }\n\n    /// @}\n\n  public:\n    ///////////////////////\n    // object inspection //\n    ///////////////////////\n\n    /// @name object inspection\n    /// Functions to inspect the type of a JSON value.\n    /// @{\n\n    /*!\n    @brief serialization\n\n    Serialization function for JSON values. The function tries to mimic\n    Python's `json.dumps()` function, and currently supports its @a indent\n    and @a ensure_ascii parameters.\n\n    @param[in] indent If indent is nonnegative, then array elements and object\n    members will be pretty-printed with that indent level. An indent level of\n    `0` will only insert newlines. `-1` (the default) selects the most compact\n    representation.\n    @param[in] indent_char The character to use for indentation if @a indent is\n    greater than `0`. The default is ` ` (space).\n    @param[in] ensure_ascii If @a ensure_ascii is true, all non-ASCII characters\n    in the output are escaped with `\\uXXXX` sequences, and the result consists\n    of ASCII characters only.\n    @param[in] error_handler  how to react on decoding errors; there are three\n    possible values: `strict` (throws and exception in case a decoding error\n    occurs; default), `replace` (replace invalid UTF-8 sequences with U+FFFD),\n    and `ignore` (ignore invalid UTF-8 sequences during serialization).\n\n    @return string containing the serialization of the JSON value\n\n    @throw type_error.316 if a string stored inside the JSON value is not\n                          UTF-8 encoded\n\n    @complexity Linear.\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes in the JSON value.\n\n    @liveexample{The following example shows the effect of different @a indent\\,\n    @a indent_char\\, and @a ensure_ascii parameters to the result of the\n    serialization.,dump}\n\n    @see https://docs.python.org/2/library/json.html#json.dump\n\n    @since version 1.0.0; indentation character @a indent_char, option\n           @a ensure_ascii and exceptions added in version 3.0.0; error\n           handlers added in version 3.4.0.\n    */\n    string_t dump(const int indent = -1,\n                  const char indent_char = ' ',\n                  const bool ensure_ascii = false,\n                  const error_handler_t error_handler = error_handler_t::strict) const\n    {\n        string_t result;\n        serializer s(detail::output_adapter<char, string_t>(result), indent_char, error_handler);\n\n        if (indent >= 0)\n        {\n            s.dump(*this, true, ensure_ascii, static_cast<unsigned int>(indent));\n        }\n        else\n        {\n            s.dump(*this, false, ensure_ascii, 0);\n        }\n\n        return result;\n    }\n\n    /*!\n    @brief return the type of the JSON value (explicit)\n\n    Return the type of the JSON value as a value from the @ref value_t\n    enumeration.\n\n    @return the type of the JSON value\n            Value type                | return value\n            ------------------------- | -------------------------\n            null                      | value_t::null\n            boolean                   | value_t::boolean\n            string                    | value_t::string\n            number (integer)          | value_t::number_integer\n            number (unsigned integer) | value_t::number_unsigned\n            number (floating-point)   | value_t::number_float\n            object                    | value_t::object\n            array                     | value_t::array\n            discarded                 | value_t::discarded\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @liveexample{The following code exemplifies `type()` for all JSON\n    types.,type}\n\n    @sa @ref operator value_t() -- return the type of the JSON value (implicit)\n    @sa @ref type_name() -- return the type as string\n\n    @since version 1.0.0\n    */\n    constexpr value_t type() const noexcept\n    {\n        return m_type;\n    }\n\n    /*!\n    @brief return whether type is primitive\n\n    This function returns true if and only if the JSON type is primitive\n    (string, number, boolean, or null).\n\n    @return `true` if type is primitive (string, number, boolean, or null),\n    `false` otherwise.\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @liveexample{The following code exemplifies `is_primitive()` for all JSON\n    types.,is_primitive}\n\n    @sa @ref is_structured() -- returns whether JSON value is structured\n    @sa @ref is_null() -- returns whether JSON value is `null`\n    @sa @ref is_string() -- returns whether JSON value is a string\n    @sa @ref is_boolean() -- returns whether JSON value is a boolean\n    @sa @ref is_number() -- returns whether JSON value is a number\n\n    @since version 1.0.0\n    */\n    constexpr bool is_primitive() const noexcept\n    {\n        return is_null() or is_string() or is_boolean() or is_number();\n    }\n\n    /*!\n    @brief return whether type is structured\n\n    This function returns true if and only if the JSON type is structured\n    (array or object).\n\n    @return `true` if type is structured (array or object), `false` otherwise.\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @liveexample{The following code exemplifies `is_structured()` for all JSON\n    types.,is_structured}\n\n    @sa @ref is_primitive() -- returns whether value is primitive\n    @sa @ref is_array() -- returns whether value is an array\n    @sa @ref is_object() -- returns whether value is an object\n\n    @since version 1.0.0\n    */\n    constexpr bool is_structured() const noexcept\n    {\n        return is_array() or is_object();\n    }\n\n    /*!\n    @brief return whether value is null\n\n    This function returns true if and only if the JSON value is null.\n\n    @return `true` if type is null, `false` otherwise.\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @liveexample{The following code exemplifies `is_null()` for all JSON\n    types.,is_null}\n\n    @since version 1.0.0\n    */\n    constexpr bool is_null() const noexcept\n    {\n        return (m_type == value_t::null);\n    }\n\n    /*!\n    @brief return whether value is a boolean\n\n    This function returns true if and only if the JSON value is a boolean.\n\n    @return `true` if type is boolean, `false` otherwise.\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @liveexample{The following code exemplifies `is_boolean()` for all JSON\n    types.,is_boolean}\n\n    @since version 1.0.0\n    */\n    constexpr bool is_boolean() const noexcept\n    {\n        return (m_type == value_t::boolean);\n    }\n\n    /*!\n    @brief return whether value is a number\n\n    This function returns true if and only if the JSON value is a number. This\n    includes both integer (signed and unsigned) and floating-point values.\n\n    @return `true` if type is number (regardless whether integer, unsigned\n    integer or floating-type), `false` otherwise.\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @liveexample{The following code exemplifies `is_number()` for all JSON\n    types.,is_number}\n\n    @sa @ref is_number_integer() -- check if value is an integer or unsigned\n    integer number\n    @sa @ref is_number_unsigned() -- check if value is an unsigned integer\n    number\n    @sa @ref is_number_float() -- check if value is a floating-point number\n\n    @since version 1.0.0\n    */\n    constexpr bool is_number() const noexcept\n    {\n        return is_number_integer() or is_number_float();\n    }\n\n    /*!\n    @brief return whether value is an integer number\n\n    This function returns true if and only if the JSON value is a signed or\n    unsigned integer number. This excludes floating-point values.\n\n    @return `true` if type is an integer or unsigned integer number, `false`\n    otherwise.\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @liveexample{The following code exemplifies `is_number_integer()` for all\n    JSON types.,is_number_integer}\n\n    @sa @ref is_number() -- check if value is a number\n    @sa @ref is_number_unsigned() -- check if value is an unsigned integer\n    number\n    @sa @ref is_number_float() -- check if value is a floating-point number\n\n    @since version 1.0.0\n    */\n    constexpr bool is_number_integer() const noexcept\n    {\n        return (m_type == value_t::number_integer or m_type == value_t::number_unsigned);\n    }\n\n    /*!\n    @brief return whether value is an unsigned integer number\n\n    This function returns true if and only if the JSON value is an unsigned\n    integer number. This excludes floating-point and signed integer values.\n\n    @return `true` if type is an unsigned integer number, `false` otherwise.\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @liveexample{The following code exemplifies `is_number_unsigned()` for all\n    JSON types.,is_number_unsigned}\n\n    @sa @ref is_number() -- check if value is a number\n    @sa @ref is_number_integer() -- check if value is an integer or unsigned\n    integer number\n    @sa @ref is_number_float() -- check if value is a floating-point number\n\n    @since version 2.0.0\n    */\n    constexpr bool is_number_unsigned() const noexcept\n    {\n        return (m_type == value_t::number_unsigned);\n    }\n\n    /*!\n    @brief return whether value is a floating-point number\n\n    This function returns true if and only if the JSON value is a\n    floating-point number. This excludes signed and unsigned integer values.\n\n    @return `true` if type is a floating-point number, `false` otherwise.\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @liveexample{The following code exemplifies `is_number_float()` for all\n    JSON types.,is_number_float}\n\n    @sa @ref is_number() -- check if value is number\n    @sa @ref is_number_integer() -- check if value is an integer number\n    @sa @ref is_number_unsigned() -- check if value is an unsigned integer\n    number\n\n    @since version 1.0.0\n    */\n    constexpr bool is_number_float() const noexcept\n    {\n        return (m_type == value_t::number_float);\n    }\n\n    /*!\n    @brief return whether value is an object\n\n    This function returns true if and only if the JSON value is an object.\n\n    @return `true` if type is object, `false` otherwise.\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @liveexample{The following code exemplifies `is_object()` for all JSON\n    types.,is_object}\n\n    @since version 1.0.0\n    */\n    constexpr bool is_object() const noexcept\n    {\n        return (m_type == value_t::object);\n    }\n\n    /*!\n    @brief return whether value is an array\n\n    This function returns true if and only if the JSON value is an array.\n\n    @return `true` if type is array, `false` otherwise.\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @liveexample{The following code exemplifies `is_array()` for all JSON\n    types.,is_array}\n\n    @since version 1.0.0\n    */\n    constexpr bool is_array() const noexcept\n    {\n        return (m_type == value_t::array);\n    }\n\n    /*!\n    @brief return whether value is a string\n\n    This function returns true if and only if the JSON value is a string.\n\n    @return `true` if type is string, `false` otherwise.\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @liveexample{The following code exemplifies `is_string()` for all JSON\n    types.,is_string}\n\n    @since version 1.0.0\n    */\n    constexpr bool is_string() const noexcept\n    {\n        return (m_type == value_t::string);\n    }\n\n    /*!\n    @brief return whether value is discarded\n\n    This function returns true if and only if the JSON value was discarded\n    during parsing with a callback function (see @ref parser_callback_t).\n\n    @note This function will always be `false` for JSON values after parsing.\n    That is, discarded values can only occur during parsing, but will be\n    removed when inside a structured value or replaced by null in other cases.\n\n    @return `true` if type is discarded, `false` otherwise.\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @liveexample{The following code exemplifies `is_discarded()` for all JSON\n    types.,is_discarded}\n\n    @since version 1.0.0\n    */\n    constexpr bool is_discarded() const noexcept\n    {\n        return (m_type == value_t::discarded);\n    }\n\n    /*!\n    @brief return the type of the JSON value (implicit)\n\n    Implicitly return the type of the JSON value as a value from the @ref\n    value_t enumeration.\n\n    @return the type of the JSON value\n\n    @complexity Constant.\n\n    @exceptionsafety No-throw guarantee: this member function never throws\n    exceptions.\n\n    @liveexample{The following code exemplifies the @ref value_t operator for\n    all JSON types.,operator__value_t}\n\n    @sa @ref type() -- return the type of the JSON value (explicit)\n    @sa @ref type_name() -- return the type as string\n\n    @since version 1.0.0\n    */\n    constexpr operator value_t() const noexcept\n    {\n        return m_type;\n    }\n\n    /// @}\n\n  private:\n    //////////////////\n    // value access //\n    //////////////////\n\n    /// get a boolean (explicit)\n    boolean_t get_impl(boolean_t* /*unused*/) const\n    {\n        if (JSON_LIKELY(is_boolean()))\n        {\n            return m_value.boolean;\n        }\n\n        JSON_THROW(type_error::create(302, \"type must be boolean, but is \" + std::string(type_name())));\n    }\n\n    /// get a pointer to the value (object)\n    object_t* get_impl_ptr(object_t* /*unused*/) noexcept\n    {\n        return is_object() ? m_value.object : nullptr;\n    }\n\n    /// get a pointer to the value (object)\n    constexpr const object_t* get_impl_ptr(const object_t* /*unused*/) const noexcept\n    {\n        return is_object() ? m_value.object : nullptr;\n    }\n\n    /// get a pointer to the value (array)\n    array_t* get_impl_ptr(array_t* /*unused*/) noexcept\n    {\n        return is_array() ? m_value.array : nullptr;\n    }\n\n    /// get a pointer to the value (array)\n    constexpr const array_t* get_impl_ptr(const array_t* /*unused*/) const noexcept\n    {\n        return is_array() ? m_value.array : nullptr;\n    }\n\n    /// get a pointer to the value (string)\n    string_t* get_impl_ptr(string_t* /*unused*/) noexcept\n    {\n        return is_string() ? m_value.string : nullptr;\n    }\n\n    /// get a pointer to the value (string)\n    constexpr const string_t* get_impl_ptr(const string_t* /*unused*/) const noexcept\n    {\n        return is_string() ? m_value.string : nullptr;\n    }\n\n    /// get a pointer to the value (boolean)\n    boolean_t* get_impl_ptr(boolean_t* /*unused*/) noexcept\n    {\n        return is_boolean() ? &m_value.boolean : nullptr;\n    }\n\n    /// get a pointer to the value (boolean)\n    constexpr const boolean_t* get_impl_ptr(const boolean_t* /*unused*/) const noexcept\n    {\n        return is_boolean() ? &m_value.boolean : nullptr;\n    }\n\n    /// get a pointer to the value (integer number)\n    number_integer_t* get_impl_ptr(number_integer_t* /*unused*/) noexcept\n    {\n        return is_number_integer() ? &m_value.number_integer : nullptr;\n    }\n\n    /// get a pointer to the value (integer number)\n    constexpr const number_integer_t* get_impl_ptr(const number_integer_t* /*unused*/) const noexcept\n    {\n        return is_number_integer() ? &m_value.number_integer : nullptr;\n    }\n\n    /// get a pointer to the value (unsigned number)\n    number_unsigned_t* get_impl_ptr(number_unsigned_t* /*unused*/) noexcept\n    {\n        return is_number_unsigned() ? &m_value.number_unsigned : nullptr;\n    }\n\n    /// get a pointer to the value (unsigned number)\n    constexpr const number_unsigned_t* get_impl_ptr(const number_unsigned_t* /*unused*/) const noexcept\n    {\n        return is_number_unsigned() ? &m_value.number_unsigned : nullptr;\n    }\n\n    /// get a pointer to the value (floating-point number)\n    number_float_t* get_impl_ptr(number_float_t* /*unused*/) noexcept\n    {\n        return is_number_float() ? &m_value.number_float : nullptr;\n    }\n\n    /// get a pointer to the value (floating-point number)\n    constexpr const number_float_t* get_impl_ptr(const number_float_t* /*unused*/) const noexcept\n    {\n        return is_number_float() ? &m_value.number_float : nullptr;\n    }\n\n    /*!\n    @brief helper function to implement get_ref()\n\n    This function helps to implement get_ref() without code duplication for\n    const and non-const overloads\n\n    @tparam ThisType will be deduced as `basic_json` or `const basic_json`\n\n    @throw type_error.303 if ReferenceType does not match underlying value\n    type of the current JSON\n    */\n    template<typename ReferenceType, typename ThisType>\n    static ReferenceType get_ref_impl(ThisType& obj)\n    {\n        // delegate the call to get_ptr<>()\n        auto ptr = obj.template get_ptr<typename std::add_pointer<ReferenceType>::type>();\n\n        if (JSON_LIKELY(ptr != nullptr))\n        {\n            return *ptr;\n        }\n\n        JSON_THROW(type_error::create(303, \"incompatible ReferenceType for get_ref, actual type is \" + std::string(obj.type_name())));\n    }\n\n  public:\n    /// @name value access\n    /// Direct access to the stored value of a JSON value.\n    /// @{\n\n    /*!\n    @brief get special-case overload\n\n    This overloads avoids a lot of template boilerplate, it can be seen as the\n    identity method\n\n    @tparam BasicJsonType == @ref basic_json\n\n    @return a copy of *this\n\n    @complexity Constant.\n\n    @since version 2.1.0\n    */\n    template<typename BasicJsonType, detail::enable_if_t<\n                 std::is_same<typename std::remove_const<BasicJsonType>::type, basic_json_t>::value,\n                 int> = 0>\n    basic_json get() const\n    {\n        return *this;\n    }\n\n    /*!\n    @brief get special-case overload\n\n    This overloads converts the current @ref basic_json in a different\n    @ref basic_json type\n\n    @tparam BasicJsonType == @ref basic_json\n\n    @return a copy of *this, converted into @tparam BasicJsonType\n\n    @complexity Depending on the implementation of the called `from_json()`\n                method.\n\n    @since version 3.2.0\n    */\n    template<typename BasicJsonType, detail::enable_if_t<\n                 not std::is_same<BasicJsonType, basic_json>::value and\n                 detail::is_basic_json<BasicJsonType>::value, int> = 0>\n    BasicJsonType get() const\n    {\n        return *this;\n    }\n\n    /*!\n    @brief get a value (explicit)\n\n    Explicit type conversion between the JSON value and a compatible value\n    which is [CopyConstructible](https://en.cppreference.com/w/cpp/named_req/CopyConstructible)\n    and [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible).\n    The value is converted by calling the @ref json_serializer<ValueType>\n    `from_json()` method.\n\n    The function is equivalent to executing\n    @code {.cpp}\n    ValueType ret;\n    JSONSerializer<ValueType>::from_json(*this, ret);\n    return ret;\n    @endcode\n\n    This overloads is chosen if:\n    - @a ValueType is not @ref basic_json,\n    - @ref json_serializer<ValueType> has a `from_json()` method of the form\n      `void from_json(const basic_json&, ValueType&)`, and\n    - @ref json_serializer<ValueType> does not have a `from_json()` method of\n      the form `ValueType from_json(const basic_json&)`\n\n    @tparam ValueTypeCV the provided value type\n    @tparam ValueType the returned value type\n\n    @return copy of the JSON value, converted to @a ValueType\n\n    @throw what @ref json_serializer<ValueType> `from_json()` method throws\n\n    @liveexample{The example below shows several conversions from JSON values\n    to other types. There a few things to note: (1) Floating-point numbers can\n    be converted to integers\\, (2) A JSON array can be converted to a standard\n    `std::vector<short>`\\, (3) A JSON object can be converted to C++\n    associative containers such as `std::unordered_map<std::string\\,\n    json>`.,get__ValueType_const}\n\n    @since version 2.1.0\n    */\n    template<typename ValueTypeCV, typename ValueType = detail::uncvref_t<ValueTypeCV>,\n             detail::enable_if_t <\n                 not detail::is_basic_json<ValueType>::value and\n                 detail::has_from_json<basic_json_t, ValueType>::value and\n                 not detail::has_non_default_from_json<basic_json_t, ValueType>::value,\n                 int> = 0>\n    ValueType get() const noexcept(noexcept(\n                                       JSONSerializer<ValueType>::from_json(std::declval<const basic_json_t&>(), std::declval<ValueType&>())))\n    {\n        // we cannot static_assert on ValueTypeCV being non-const, because\n        // there is support for get<const basic_json_t>(), which is why we\n        // still need the uncvref\n        static_assert(not std::is_reference<ValueTypeCV>::value,\n                      \"get() cannot be used with reference types, you might want to use get_ref()\");\n        static_assert(std::is_default_constructible<ValueType>::value,\n                      \"types must be DefaultConstructible when used with get()\");\n\n        ValueType ret;\n        JSONSerializer<ValueType>::from_json(*this, ret);\n        return ret;\n    }\n\n    /*!\n    @brief get a value (explicit); special case\n\n    Explicit type conversion between the JSON value and a compatible value\n    which is **not** [CopyConstructible](https://en.cppreference.com/w/cpp/named_req/CopyConstructible)\n    and **not** [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible).\n    The value is converted by calling the @ref json_serializer<ValueType>\n    `from_json()` method.\n\n    The function is equivalent to executing\n    @code {.cpp}\n    return JSONSerializer<ValueTypeCV>::from_json(*this);\n    @endcode\n\n    This overloads is chosen if:\n    - @a ValueType is not @ref basic_json and\n    - @ref json_serializer<ValueType> has a `from_json()` method of the form\n      `ValueType from_json(const basic_json&)`\n\n    @note If @ref json_serializer<ValueType> has both overloads of\n    `from_json()`, this one is chosen.\n\n    @tparam ValueTypeCV the provided value type\n    @tparam ValueType the returned value type\n\n    @return copy of the JSON value, converted to @a ValueType\n\n    @throw what @ref json_serializer<ValueType> `from_json()` method throws\n\n    @since version 2.1.0\n    */\n    template<typename ValueTypeCV, typename ValueType = detail::uncvref_t<ValueTypeCV>,\n             detail::enable_if_t<not std::is_same<basic_json_t, ValueType>::value and\n                                 detail::has_non_default_from_json<basic_json_t, ValueType>::value,\n                                 int> = 0>\n    ValueType get() const noexcept(noexcept(\n                                       JSONSerializer<ValueTypeCV>::from_json(std::declval<const basic_json_t&>())))\n    {\n        static_assert(not std::is_reference<ValueTypeCV>::value,\n                      \"get() cannot be used with reference types, you might want to use get_ref()\");\n        return JSONSerializer<ValueTypeCV>::from_json(*this);\n    }\n\n    /*!\n    @brief get a value (explicit)\n\n    Explicit type conversion between the JSON value and a compatible value.\n    The value is filled into the input parameter by calling the @ref json_serializer<ValueType>\n    `from_json()` method.\n\n    The function is equivalent to executing\n    @code {.cpp}\n    ValueType v;\n    JSONSerializer<ValueType>::from_json(*this, v);\n    @endcode\n\n    This overloads is chosen if:\n    - @a ValueType is not @ref basic_json,\n    - @ref json_serializer<ValueType> has a `from_json()` method of the form\n      `void from_json(const basic_json&, ValueType&)`, and\n\n    @tparam ValueType the input parameter type.\n\n    @return the input parameter, allowing chaining calls.\n\n    @throw what @ref json_serializer<ValueType> `from_json()` method throws\n\n    @liveexample{The example below shows several conversions from JSON values\n    to other types. There a few things to note: (1) Floating-point numbers can\n    be converted to integers\\, (2) A JSON array can be converted to a standard\n    `std::vector<short>`\\, (3) A JSON object can be converted to C++\n    associative containers such as `std::unordered_map<std::string\\,\n    json>`.,get_to}\n\n    @since version 3.3.0\n    */\n    template<typename ValueType,\n             detail::enable_if_t <\n                 not detail::is_basic_json<ValueType>::value and\n                 detail::has_from_json<basic_json_t, ValueType>::value,\n                 int> = 0>\n    ValueType & get_to(ValueType& v) const noexcept(noexcept(\n                JSONSerializer<ValueType>::from_json(std::declval<const basic_json_t&>(), v)))\n    {\n        JSONSerializer<ValueType>::from_json(*this, v);\n        return v;\n    }\n\n\n    /*!\n    @brief get a pointer value (implicit)\n\n    Implicit pointer access to the internally stored JSON value. No copies are\n    made.\n\n    @warning Writing data to the pointee of the result yields an undefined\n    state.\n\n    @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref\n    object_t, @ref string_t, @ref boolean_t, @ref number_integer_t,\n    @ref number_unsigned_t, or @ref number_float_t. Enforced by a static\n    assertion.\n\n    @return pointer to the internally stored JSON value if the requested\n    pointer type @a PointerType fits to the JSON value; `nullptr` otherwise\n\n    @complexity Constant.\n\n    @liveexample{The example below shows how pointers to internal values of a\n    JSON value can be requested. Note that no type conversions are made and a\n    `nullptr` is returned if the value and the requested pointer type does not\n    match.,get_ptr}\n\n    @since version 1.0.0\n    */\n    template<typename PointerType, typename std::enable_if<\n                 std::is_pointer<PointerType>::value, int>::type = 0>\n    auto get_ptr() noexcept -> decltype(std::declval<basic_json_t&>().get_impl_ptr(std::declval<PointerType>()))\n    {\n        // delegate the call to get_impl_ptr<>()\n        return get_impl_ptr(static_cast<PointerType>(nullptr));\n    }\n\n    /*!\n    @brief get a pointer value (implicit)\n    @copydoc get_ptr()\n    */\n    template<typename PointerType, typename std::enable_if<\n                 std::is_pointer<PointerType>::value and\n                 std::is_const<typename std::remove_pointer<PointerType>::type>::value, int>::type = 0>\n    constexpr auto get_ptr() const noexcept -> decltype(std::declval<const basic_json_t&>().get_impl_ptr(std::declval<PointerType>()))\n    {\n        // delegate the call to get_impl_ptr<>() const\n        return get_impl_ptr(static_cast<PointerType>(nullptr));\n    }\n\n    /*!\n    @brief get a pointer value (explicit)\n\n    Explicit pointer access to the internally stored JSON value. No copies are\n    made.\n\n    @warning The pointer becomes invalid if the underlying JSON object\n    changes.\n\n    @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref\n    object_t, @ref string_t, @ref boolean_t, @ref number_integer_t,\n    @ref number_unsigned_t, or @ref number_float_t.\n\n    @return pointer to the internally stored JSON value if the requested\n    pointer type @a PointerType fits to the JSON value; `nullptr` otherwise\n\n    @complexity Constant.\n\n    @liveexample{The example below shows how pointers to internal values of a\n    JSON value can be requested. Note that no type conversions are made and a\n    `nullptr` is returned if the value and the requested pointer type does not\n    match.,get__PointerType}\n\n    @sa @ref get_ptr() for explicit pointer-member access\n\n    @since version 1.0.0\n    */\n    template<typename PointerType, typename std::enable_if<\n                 std::is_pointer<PointerType>::value, int>::type = 0>\n    auto get() noexcept -> decltype(std::declval<basic_json_t&>().template get_ptr<PointerType>())\n    {\n        // delegate the call to get_ptr\n        return get_ptr<PointerType>();\n    }\n\n    /*!\n    @brief get a pointer value (explicit)\n    @copydoc get()\n    */\n    template<typename PointerType, typename std::enable_if<\n                 std::is_pointer<PointerType>::value, int>::type = 0>\n    constexpr auto get() const noexcept -> decltype(std::declval<const basic_json_t&>().template get_ptr<PointerType>())\n    {\n        // delegate the call to get_ptr\n        return get_ptr<PointerType>();\n    }\n\n    /*!\n    @brief get a reference value (implicit)\n\n    Implicit reference access to the internally stored JSON value. No copies\n    are made.\n\n    @warning Writing data to the referee of the result yields an undefined\n    state.\n\n    @tparam ReferenceType reference type; must be a reference to @ref array_t,\n    @ref object_t, @ref string_t, @ref boolean_t, @ref number_integer_t, or\n    @ref number_float_t. Enforced by static assertion.\n\n    @return reference to the internally stored JSON value if the requested\n    reference type @a ReferenceType fits to the JSON value; throws\n    type_error.303 otherwise\n\n    @throw type_error.303 in case passed type @a ReferenceType is incompatible\n    with the stored JSON value; see example below\n\n    @complexity Constant.\n\n    @liveexample{The example shows several calls to `get_ref()`.,get_ref}\n\n    @since version 1.1.0\n    */\n    template<typename ReferenceType, typename std::enable_if<\n                 std::is_reference<ReferenceType>::value, int>::type = 0>\n    ReferenceType get_ref()\n    {\n        // delegate call to get_ref_impl\n        return get_ref_impl<ReferenceType>(*this);\n    }\n\n    /*!\n    @brief get a reference value (implicit)\n    @copydoc get_ref()\n    */\n    template<typename ReferenceType, typename std::enable_if<\n                 std::is_reference<ReferenceType>::value and\n                 std::is_const<typename std::remove_reference<ReferenceType>::type>::value, int>::type = 0>\n    ReferenceType get_ref() const\n    {\n        // delegate call to get_ref_impl\n        return get_ref_impl<ReferenceType>(*this);\n    }\n\n    /*!\n    @brief get a value (implicit)\n\n    Implicit type conversion between the JSON value and a compatible value.\n    The call is realized by calling @ref get() const.\n\n    @tparam ValueType non-pointer type compatible to the JSON value, for\n    instance `int` for JSON integer numbers, `bool` for JSON booleans, or\n    `std::vector` types for JSON arrays. The character type of @ref string_t\n    as well as an initializer list of this type is excluded to avoid\n    ambiguities as these types implicitly convert to `std::string`.\n\n    @return copy of the JSON value, converted to type @a ValueType\n\n    @throw type_error.302 in case passed type @a ValueType is incompatible\n    to the JSON value type (e.g., the JSON value is of type boolean, but a\n    string is requested); see example below\n\n    @complexity Linear in the size of the JSON value.\n\n    @liveexample{The example below shows several conversions from JSON values\n    to other types. There a few things to note: (1) Floating-point numbers can\n    be converted to integers\\, (2) A JSON array can be converted to a standard\n    `std::vector<short>`\\, (3) A JSON object can be converted to C++\n    associative containers such as `std::unordered_map<std::string\\,\n    json>`.,operator__ValueType}\n\n    @since version 1.0.0\n    */\n    template < typename ValueType, typename std::enable_if <\n                   not std::is_pointer<ValueType>::value and\n                   not std::is_same<ValueType, detail::json_ref<basic_json>>::value and\n                   not std::is_same<ValueType, typename string_t::value_type>::value and\n                   not detail::is_basic_json<ValueType>::value\n\n#ifndef _MSC_VER  // fix for issue #167 operator<< ambiguity under VS2015\n                   and not std::is_same<ValueType, std::initializer_list<typename string_t::value_type>>::value\n#if defined(JSON_HAS_CPP_17) && defined(_MSC_VER) and _MSC_VER <= 1914\n                   and not std::is_same<ValueType, typename std::string_view>::value\n#endif\n#endif\n                   and detail::is_detected<detail::get_template_function, const basic_json_t&, ValueType>::value\n                   , int >::type = 0 >\n    operator ValueType() const\n    {\n        // delegate the call to get<>() const\n        return get<ValueType>();\n    }\n\n    /// @}\n\n\n    ////////////////////\n    // element access //\n    ////////////////////\n\n    /// @name element access\n    /// Access to the JSON value.\n    /// @{\n\n    /*!\n    @brief access specified array element with bounds checking\n\n    Returns a reference to the element at specified location @a idx, with\n    bounds checking.\n\n    @param[in] idx  index of the element to access\n\n    @return reference to the element at index @a idx\n\n    @throw type_error.304 if the JSON value is not an array; in this case,\n    calling `at` with an index makes no sense. See example below.\n    @throw out_of_range.401 if the index @a idx is out of range of the array;\n    that is, `idx >= size()`. See example below.\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes in the JSON value.\n\n    @complexity Constant.\n\n    @since version 1.0.0\n\n    @liveexample{The example below shows how array elements can be read and\n    written using `at()`. It also demonstrates the different exceptions that\n    can be thrown.,at__size_type}\n    */\n    reference at(size_type idx)\n    {\n        // at only works for arrays\n        if (JSON_LIKELY(is_array()))\n        {\n            JSON_TRY\n            {\n                return m_value.array->at(idx);\n            }\n            JSON_CATCH (std::out_of_range&)\n            {\n                // create better exception explanation\n                JSON_THROW(out_of_range::create(401, \"array index \" + std::to_string(idx) + \" is out of range\"));\n            }\n        }\n        else\n        {\n            JSON_THROW(type_error::create(304, \"cannot use at() with \" + std::string(type_name())));\n        }\n    }\n\n    /*!\n    @brief access specified array element with bounds checking\n\n    Returns a const reference to the element at specified location @a idx,\n    with bounds checking.\n\n    @param[in] idx  index of the element to access\n\n    @return const reference to the element at index @a idx\n\n    @throw type_error.304 if the JSON value is not an array; in this case,\n    calling `at` with an index makes no sense. See example below.\n    @throw out_of_range.401 if the index @a idx is out of range of the array;\n    that is, `idx >= size()`. See example below.\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes in the JSON value.\n\n    @complexity Constant.\n\n    @since version 1.0.0\n\n    @liveexample{The example below shows how array elements can be read using\n    `at()`. It also demonstrates the different exceptions that can be thrown.,\n    at__size_type_const}\n    */\n    const_reference at(size_type idx) const\n    {\n        // at only works for arrays\n        if (JSON_LIKELY(is_array()))\n        {\n            JSON_TRY\n            {\n                return m_value.array->at(idx);\n            }\n            JSON_CATCH (std::out_of_range&)\n            {\n                // create better exception explanation\n                JSON_THROW(out_of_range::create(401, \"array index \" + std::to_string(idx) + \" is out of range\"));\n            }\n        }\n        else\n        {\n            JSON_THROW(type_error::create(304, \"cannot use at() with \" + std::string(type_name())));\n        }\n    }\n\n    /*!\n    @brief access specified object element with bounds checking\n\n    Returns a reference to the element at with specified key @a key, with\n    bounds checking.\n\n    @param[in] key  key of the element to access\n\n    @return reference to the element at key @a key\n\n    @throw type_error.304 if the JSON value is not an object; in this case,\n    calling `at` with a key makes no sense. See example below.\n    @throw out_of_range.403 if the key @a key is is not stored in the object;\n    that is, `find(key) == end()`. See example below.\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes in the JSON value.\n\n    @complexity Logarithmic in the size of the container.\n\n    @sa @ref operator[](const typename object_t::key_type&) for unchecked\n    access by reference\n    @sa @ref value() for access by value with a default value\n\n    @since version 1.0.0\n\n    @liveexample{The example below shows how object elements can be read and\n    written using `at()`. It also demonstrates the different exceptions that\n    can be thrown.,at__object_t_key_type}\n    */\n    reference at(const typename object_t::key_type& key)\n    {\n        // at only works for objects\n        if (JSON_LIKELY(is_object()))\n        {\n            JSON_TRY\n            {\n                return m_value.object->at(key);\n            }\n            JSON_CATCH (std::out_of_range&)\n            {\n                // create better exception explanation\n                JSON_THROW(out_of_range::create(403, \"key '\" + key + \"' not found\"));\n            }\n        }\n        else\n        {\n            JSON_THROW(type_error::create(304, \"cannot use at() with \" + std::string(type_name())));\n        }\n    }\n\n    /*!\n    @brief access specified object element with bounds checking\n\n    Returns a const reference to the element at with specified key @a key,\n    with bounds checking.\n\n    @param[in] key  key of the element to access\n\n    @return const reference to the element at key @a key\n\n    @throw type_error.304 if the JSON value is not an object; in this case,\n    calling `at` with a key makes no sense. See example below.\n    @throw out_of_range.403 if the key @a key is is not stored in the object;\n    that is, `find(key) == end()`. See example below.\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes in the JSON value.\n\n    @complexity Logarithmic in the size of the container.\n\n    @sa @ref operator[](const typename object_t::key_type&) for unchecked\n    access by reference\n    @sa @ref value() for access by value with a default value\n\n    @since version 1.0.0\n\n    @liveexample{The example below shows how object elements can be read using\n    `at()`. It also demonstrates the different exceptions that can be thrown.,\n    at__object_t_key_type_const}\n    */\n    const_reference at(const typename object_t::key_type& key) const\n    {\n        // at only works for objects\n        if (JSON_LIKELY(is_object()))\n        {\n            JSON_TRY\n            {\n                return m_value.object->at(key);\n            }\n            JSON_CATCH (std::out_of_range&)\n            {\n                // create better exception explanation\n                JSON_THROW(out_of_range::create(403, \"key '\" + key + \"' not found\"));\n            }\n        }\n        else\n        {\n            JSON_THROW(type_error::create(304, \"cannot use at() with \" + std::string(type_name())));\n        }\n    }\n\n    /*!\n    @brief access specified array element\n\n    Returns a reference to the element at specified location @a idx.\n\n    @note If @a idx is beyond the range of the array (i.e., `idx >= size()`),\n    then the array is silently filled up with `null` values to make `idx` a\n    valid reference to the last stored element.\n\n    @param[in] idx  index of the element to access\n\n    @return reference to the element at index @a idx\n\n    @throw type_error.305 if the JSON value is not an array or null; in that\n    cases, using the [] operator with an index makes no sense.\n\n    @complexity Constant if @a idx is in the range of the array. Otherwise\n    linear in `idx - size()`.\n\n    @liveexample{The example below shows how array elements can be read and\n    written using `[]` operator. Note the addition of `null`\n    values.,operatorarray__size_type}\n\n    @since version 1.0.0\n    */\n    reference operator[](size_type idx)\n    {\n        // implicitly convert null value to an empty array\n        if (is_null())\n        {\n            m_type = value_t::array;\n            m_value.array = create<array_t>();\n            assert_invariant();\n        }\n\n        // operator[] only works for arrays\n        if (JSON_LIKELY(is_array()))\n        {\n            // fill up array with null values if given idx is outside range\n            if (idx >= m_value.array->size())\n            {\n                m_value.array->insert(m_value.array->end(),\n                                      idx - m_value.array->size() + 1,\n                                      basic_json());\n            }\n\n            return m_value.array->operator[](idx);\n        }\n\n        JSON_THROW(type_error::create(305, \"cannot use operator[] with a numeric argument with \" + std::string(type_name())));\n    }\n\n    /*!\n    @brief access specified array element\n\n    Returns a const reference to the element at specified location @a idx.\n\n    @param[in] idx  index of the element to access\n\n    @return const reference to the element at index @a idx\n\n    @throw type_error.305 if the JSON value is not an array; in that case,\n    using the [] operator with an index makes no sense.\n\n    @complexity Constant.\n\n    @liveexample{The example below shows how array elements can be read using\n    the `[]` operator.,operatorarray__size_type_const}\n\n    @since version 1.0.0\n    */\n    const_reference operator[](size_type idx) const\n    {\n        // const operator[] only works for arrays\n        if (JSON_LIKELY(is_array()))\n        {\n            return m_value.array->operator[](idx);\n        }\n\n        JSON_THROW(type_error::create(305, \"cannot use operator[] with a numeric argument with \" + std::string(type_name())));\n    }\n\n    /*!\n    @brief access specified object element\n\n    Returns a reference to the element at with specified key @a key.\n\n    @note If @a key is not found in the object, then it is silently added to\n    the object and filled with a `null` value to make `key` a valid reference.\n    In case the value was `null` before, it is converted to an object.\n\n    @param[in] key  key of the element to access\n\n    @return reference to the element at key @a key\n\n    @throw type_error.305 if the JSON value is not an object or null; in that\n    cases, using the [] operator with a key makes no sense.\n\n    @complexity Logarithmic in the size of the container.\n\n    @liveexample{The example below shows how object elements can be read and\n    written using the `[]` operator.,operatorarray__key_type}\n\n    @sa @ref at(const typename object_t::key_type&) for access by reference\n    with range checking\n    @sa @ref value() for access by value with a default value\n\n    @since version 1.0.0\n    */\n    reference operator[](const typename object_t::key_type& key)\n    {\n        // implicitly convert null value to an empty object\n        if (is_null())\n        {\n            m_type = value_t::object;\n            m_value.object = create<object_t>();\n            assert_invariant();\n        }\n\n        // operator[] only works for objects\n        if (JSON_LIKELY(is_object()))\n        {\n            return m_value.object->operator[](key);\n        }\n\n        JSON_THROW(type_error::create(305, \"cannot use operator[] with a string argument with \" + std::string(type_name())));\n    }\n\n    /*!\n    @brief read-only access specified object element\n\n    Returns a const reference to the element at with specified key @a key. No\n    bounds checking is performed.\n\n    @warning If the element with key @a key does not exist, the behavior is\n    undefined.\n\n    @param[in] key  key of the element to access\n\n    @return const reference to the element at key @a key\n\n    @pre The element with key @a key must exist. **This precondition is\n         enforced with an assertion.**\n\n    @throw type_error.305 if the JSON value is not an object; in that case,\n    using the [] operator with a key makes no sense.\n\n    @complexity Logarithmic in the size of the container.\n\n    @liveexample{The example below shows how object elements can be read using\n    the `[]` operator.,operatorarray__key_type_const}\n\n    @sa @ref at(const typename object_t::key_type&) for access by reference\n    with range checking\n    @sa @ref value() for access by value with a default value\n\n    @since version 1.0.0\n    */\n    const_reference operator[](const typename object_t::key_type& key) const\n    {\n        // const operator[] only works for objects\n        if (JSON_LIKELY(is_object()))\n        {\n            assert(m_value.object->find(key) != m_value.object->end());\n            return m_value.object->find(key)->second;\n        }\n\n        JSON_THROW(type_error::create(305, \"cannot use operator[] with a string argument with \" + std::string(type_name())));\n    }\n\n    /*!\n    @brief access specified object element\n\n    Returns a reference to the element at with specified key @a key.\n\n    @note If @a key is not found in the object, then it is silently added to\n    the object and filled with a `null` value to make `key` a valid reference.\n    In case the value was `null` before, it is converted to an object.\n\n    @param[in] key  key of the element to access\n\n    @return reference to the element at key @a key\n\n    @throw type_error.305 if the JSON value is not an object or null; in that\n    cases, using the [] operator with a key makes no sense.\n\n    @complexity Logarithmic in the size of the container.\n\n    @liveexample{The example below shows how object elements can be read and\n    written using the `[]` operator.,operatorarray__key_type}\n\n    @sa @ref at(const typename object_t::key_type&) for access by reference\n    with range checking\n    @sa @ref value() for access by value with a default value\n\n    @since version 1.1.0\n    */\n    template<typename T>\n    reference operator[](T* key)\n    {\n        // implicitly convert null to object\n        if (is_null())\n        {\n            m_type = value_t::object;\n            m_value = value_t::object;\n            assert_invariant();\n        }\n\n        // at only works for objects\n        if (JSON_LIKELY(is_object()))\n        {\n            return m_value.object->operator[](key);\n        }\n\n        JSON_THROW(type_error::create(305, \"cannot use operator[] with a string argument with \" + std::string(type_name())));\n    }\n\n    /*!\n    @brief read-only access specified object element\n\n    Returns a const reference to the element at with specified key @a key. No\n    bounds checking is performed.\n\n    @warning If the element with key @a key does not exist, the behavior is\n    undefined.\n\n    @param[in] key  key of the element to access\n\n    @return const reference to the element at key @a key\n\n    @pre The element with key @a key must exist. **This precondition is\n         enforced with an assertion.**\n\n    @throw type_error.305 if the JSON value is not an object; in that case,\n    using the [] operator with a key makes no sense.\n\n    @complexity Logarithmic in the size of the container.\n\n    @liveexample{The example below shows how object elements can be read using\n    the `[]` operator.,operatorarray__key_type_const}\n\n    @sa @ref at(const typename object_t::key_type&) for access by reference\n    with range checking\n    @sa @ref value() for access by value with a default value\n\n    @since version 1.1.0\n    */\n    template<typename T>\n    const_reference operator[](T* key) const\n    {\n        // at only works for objects\n        if (JSON_LIKELY(is_object()))\n        {\n            assert(m_value.object->find(key) != m_value.object->end());\n            return m_value.object->find(key)->second;\n        }\n\n        JSON_THROW(type_error::create(305, \"cannot use operator[] with a string argument with \" + std::string(type_name())));\n    }\n\n    /*!\n    @brief access specified object element with default value\n\n    Returns either a copy of an object's element at the specified key @a key\n    or a given default value if no element with key @a key exists.\n\n    The function is basically equivalent to executing\n    @code {.cpp}\n    try {\n        return at(key);\n    } catch(out_of_range) {\n        return default_value;\n    }\n    @endcode\n\n    @note Unlike @ref at(const typename object_t::key_type&), this function\n    does not throw if the given key @a key was not found.\n\n    @note Unlike @ref operator[](const typename object_t::key_type& key), this\n    function does not implicitly add an element to the position defined by @a\n    key. This function is furthermore also applicable to const objects.\n\n    @param[in] key  key of the element to access\n    @param[in] default_value  the value to return if @a key is not found\n\n    @tparam ValueType type compatible to JSON values, for instance `int` for\n    JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for\n    JSON arrays. Note the type of the expected value at @a key and the default\n    value @a default_value must be compatible.\n\n    @return copy of the element at key @a key or @a default_value if @a key\n    is not found\n\n    @throw type_error.306 if the JSON value is not an object; in that case,\n    using `value()` with a key makes no sense.\n\n    @complexity Logarithmic in the size of the container.\n\n    @liveexample{The example below shows how object elements can be queried\n    with a default value.,basic_json__value}\n\n    @sa @ref at(const typename object_t::key_type&) for access by reference\n    with range checking\n    @sa @ref operator[](const typename object_t::key_type&) for unchecked\n    access by reference\n\n    @since version 1.0.0\n    */\n    template<class ValueType, typename std::enable_if<\n                 std::is_convertible<basic_json_t, ValueType>::value, int>::type = 0>\n    ValueType value(const typename object_t::key_type& key, const ValueType& default_value) const\n    {\n        // at only works for objects\n        if (JSON_LIKELY(is_object()))\n        {\n            // if key is found, return value and given default value otherwise\n            const auto it = find(key);\n            if (it != end())\n            {\n                return *it;\n            }\n\n            return default_value;\n        }\n\n        JSON_THROW(type_error::create(306, \"cannot use value() with \" + std::string(type_name())));\n    }\n\n    /*!\n    @brief overload for a default value of type const char*\n    @copydoc basic_json::value(const typename object_t::key_type&, const ValueType&) const\n    */\n    string_t value(const typename object_t::key_type& key, const char* default_value) const\n    {\n        return value(key, string_t(default_value));\n    }\n\n    /*!\n    @brief access specified object element via JSON Pointer with default value\n\n    Returns either a copy of an object's element at the specified key @a key\n    or a given default value if no element with key @a key exists.\n\n    The function is basically equivalent to executing\n    @code {.cpp}\n    try {\n        return at(ptr);\n    } catch(out_of_range) {\n        return default_value;\n    }\n    @endcode\n\n    @note Unlike @ref at(const json_pointer&), this function does not throw\n    if the given key @a key was not found.\n\n    @param[in] ptr  a JSON pointer to the element to access\n    @param[in] default_value  the value to return if @a ptr found no value\n\n    @tparam ValueType type compatible to JSON values, for instance `int` for\n    JSON integer numbers, `bool` for JSON booleans, or `std::vector` types for\n    JSON arrays. Note the type of the expected value at @a key and the default\n    value @a default_value must be compatible.\n\n    @return copy of the element at key @a key or @a default_value if @a key\n    is not found\n\n    @throw type_error.306 if the JSON value is not an object; in that case,\n    using `value()` with a key makes no sense.\n\n    @complexity Logarithmic in the size of the container.\n\n    @liveexample{The example below shows how object elements can be queried\n    with a default value.,basic_json__value_ptr}\n\n    @sa @ref operator[](const json_pointer&) for unchecked access by reference\n\n    @since version 2.0.2\n    */\n    template<class ValueType, typename std::enable_if<\n                 std::is_convertible<basic_json_t, ValueType>::value, int>::type = 0>\n    ValueType value(const json_pointer& ptr, const ValueType& default_value) const\n    {\n        // at only works for objects\n        if (JSON_LIKELY(is_object()))\n        {\n            // if pointer resolves a value, return it or use default value\n            JSON_TRY\n            {\n                return ptr.get_checked(this);\n            }\n            JSON_INTERNAL_CATCH (out_of_range&)\n            {\n                return default_value;\n            }\n        }\n\n        JSON_THROW(type_error::create(306, \"cannot use value() with \" + std::string(type_name())));\n    }\n\n    /*!\n    @brief overload for a default value of type const char*\n    @copydoc basic_json::value(const json_pointer&, ValueType) const\n    */\n    string_t value(const json_pointer& ptr, const char* default_value) const\n    {\n        return value(ptr, string_t(default_value));\n    }\n\n    /*!\n    @brief access the first element\n\n    Returns a reference to the first element in the container. For a JSON\n    container `c`, the expression `c.front()` is equivalent to `*c.begin()`.\n\n    @return In case of a structured type (array or object), a reference to the\n    first element is returned. In case of number, string, or boolean values, a\n    reference to the value is returned.\n\n    @complexity Constant.\n\n    @pre The JSON value must not be `null` (would throw `std::out_of_range`)\n    or an empty array or object (undefined behavior, **guarded by\n    assertions**).\n    @post The JSON value remains unchanged.\n\n    @throw invalid_iterator.214 when called on `null` value\n\n    @liveexample{The following code shows an example for `front()`.,front}\n\n    @sa @ref back() -- access the last element\n\n    @since version 1.0.0\n    */\n    reference front()\n    {\n        return *begin();\n    }\n\n    /*!\n    @copydoc basic_json::front()\n    */\n    const_reference front() const\n    {\n        return *cbegin();\n    }\n\n    /*!\n    @brief access the last element\n\n    Returns a reference to the last element in the container. For a JSON\n    container `c`, the expression `c.back()` is equivalent to\n    @code {.cpp}\n    auto tmp = c.end();\n    --tmp;\n    return *tmp;\n    @endcode\n\n    @return In case of a structured type (array or object), a reference to the\n    last element is returned. In case of number, string, or boolean values, a\n    reference to the value is returned.\n\n    @complexity Constant.\n\n    @pre The JSON value must not be `null` (would throw `std::out_of_range`)\n    or an empty array or object (undefined behavior, **guarded by\n    assertions**).\n    @post The JSON value remains unchanged.\n\n    @throw invalid_iterator.214 when called on a `null` value. See example\n    below.\n\n    @liveexample{The following code shows an example for `back()`.,back}\n\n    @sa @ref front() -- access the first element\n\n    @since version 1.0.0\n    */\n    reference back()\n    {\n        auto tmp = end();\n        --tmp;\n        return *tmp;\n    }\n\n    /*!\n    @copydoc basic_json::back()\n    */\n    const_reference back() const\n    {\n        auto tmp = cend();\n        --tmp;\n        return *tmp;\n    }\n\n    /*!\n    @brief remove element given an iterator\n\n    Removes the element specified by iterator @a pos. The iterator @a pos must\n    be valid and dereferenceable. Thus the `end()` iterator (which is valid,\n    but is not dereferenceable) cannot be used as a value for @a pos.\n\n    If called on a primitive type other than `null`, the resulting JSON value\n    will be `null`.\n\n    @param[in] pos iterator to the element to remove\n    @return Iterator following the last removed element. If the iterator @a\n    pos refers to the last element, the `end()` iterator is returned.\n\n    @tparam IteratorType an @ref iterator or @ref const_iterator\n\n    @post Invalidates iterators and references at or after the point of the\n    erase, including the `end()` iterator.\n\n    @throw type_error.307 if called on a `null` value; example: `\"cannot use\n    erase() with null\"`\n    @throw invalid_iterator.202 if called on an iterator which does not belong\n    to the current JSON value; example: `\"iterator does not fit current\n    value\"`\n    @throw invalid_iterator.205 if called on a primitive type with invalid\n    iterator (i.e., any iterator which is not `begin()`); example: `\"iterator\n    out of range\"`\n\n    @complexity The complexity depends on the type:\n    - objects: amortized constant\n    - arrays: linear in distance between @a pos and the end of the container\n    - strings: linear in the length of the string\n    - other types: constant\n\n    @liveexample{The example shows the result of `erase()` for different JSON\n    types.,erase__IteratorType}\n\n    @sa @ref erase(IteratorType, IteratorType) -- removes the elements in\n    the given range\n    @sa @ref erase(const typename object_t::key_type&) -- removes the element\n    from an object at the given key\n    @sa @ref erase(const size_type) -- removes the element from an array at\n    the given index\n\n    @since version 1.0.0\n    */\n    template<class IteratorType, typename std::enable_if<\n                 std::is_same<IteratorType, typename basic_json_t::iterator>::value or\n                 std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int>::type\n             = 0>\n    IteratorType erase(IteratorType pos)\n    {\n        // make sure iterator fits the current value\n        if (JSON_UNLIKELY(this != pos.m_object))\n        {\n            JSON_THROW(invalid_iterator::create(202, \"iterator does not fit current value\"));\n        }\n\n        IteratorType result = end();\n\n        switch (m_type)\n        {\n            case value_t::boolean:\n            case value_t::number_float:\n            case value_t::number_integer:\n            case value_t::number_unsigned:\n            case value_t::string:\n            {\n                if (JSON_UNLIKELY(not pos.m_it.primitive_iterator.is_begin()))\n                {\n                    JSON_THROW(invalid_iterator::create(205, \"iterator out of range\"));\n                }\n\n                if (is_string())\n                {\n                    AllocatorType<string_t> alloc;\n                    std::allocator_traits<decltype(alloc)>::destroy(alloc, m_value.string);\n                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_value.string, 1);\n                    m_value.string = nullptr;\n                }\n\n                m_type = value_t::null;\n                assert_invariant();\n                break;\n            }\n\n            case value_t::object:\n            {\n                result.m_it.object_iterator = m_value.object->erase(pos.m_it.object_iterator);\n                break;\n            }\n\n            case value_t::array:\n            {\n                result.m_it.array_iterator = m_value.array->erase(pos.m_it.array_iterator);\n                break;\n            }\n\n            default:\n                JSON_THROW(type_error::create(307, \"cannot use erase() with \" + std::string(type_name())));\n        }\n\n        return result;\n    }\n\n    /*!\n    @brief remove elements given an iterator range\n\n    Removes the element specified by the range `[first; last)`. The iterator\n    @a first does not need to be dereferenceable if `first == last`: erasing\n    an empty range is a no-op.\n\n    If called on a primitive type other than `null`, the resulting JSON value\n    will be `null`.\n\n    @param[in] first iterator to the beginning of the range to remove\n    @param[in] last iterator past the end of the range to remove\n    @return Iterator following the last removed element. If the iterator @a\n    second refers to the last element, the `end()` iterator is returned.\n\n    @tparam IteratorType an @ref iterator or @ref const_iterator\n\n    @post Invalidates iterators and references at or after the point of the\n    erase, including the `end()` iterator.\n\n    @throw type_error.307 if called on a `null` value; example: `\"cannot use\n    erase() with null\"`\n    @throw invalid_iterator.203 if called on iterators which does not belong\n    to the current JSON value; example: `\"iterators do not fit current value\"`\n    @throw invalid_iterator.204 if called on a primitive type with invalid\n    iterators (i.e., if `first != begin()` and `last != end()`); example:\n    `\"iterators out of range\"`\n\n    @complexity The complexity depends on the type:\n    - objects: `log(size()) + std::distance(first, last)`\n    - arrays: linear in the distance between @a first and @a last, plus linear\n      in the distance between @a last and end of the container\n    - strings: linear in the length of the string\n    - other types: constant\n\n    @liveexample{The example shows the result of `erase()` for different JSON\n    types.,erase__IteratorType_IteratorType}\n\n    @sa @ref erase(IteratorType) -- removes the element at a given position\n    @sa @ref erase(const typename object_t::key_type&) -- removes the element\n    from an object at the given key\n    @sa @ref erase(const size_type) -- removes the element from an array at\n    the given index\n\n    @since version 1.0.0\n    */\n    template<class IteratorType, typename std::enable_if<\n                 std::is_same<IteratorType, typename basic_json_t::iterator>::value or\n                 std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int>::type\n             = 0>\n    IteratorType erase(IteratorType first, IteratorType last)\n    {\n        // make sure iterator fits the current value\n        if (JSON_UNLIKELY(this != first.m_object or this != last.m_object))\n        {\n            JSON_THROW(invalid_iterator::create(203, \"iterators do not fit current value\"));\n        }\n\n        IteratorType result = end();\n\n        switch (m_type)\n        {\n            case value_t::boolean:\n            case value_t::number_float:\n            case value_t::number_integer:\n            case value_t::number_unsigned:\n            case value_t::string:\n            {\n                if (JSON_LIKELY(not first.m_it.primitive_iterator.is_begin()\n                                or not last.m_it.primitive_iterator.is_end()))\n                {\n                    JSON_THROW(invalid_iterator::create(204, \"iterators out of range\"));\n                }\n\n                if (is_string())\n                {\n                    AllocatorType<string_t> alloc;\n                    std::allocator_traits<decltype(alloc)>::destroy(alloc, m_value.string);\n                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_value.string, 1);\n                    m_value.string = nullptr;\n                }\n\n                m_type = value_t::null;\n                assert_invariant();\n                break;\n            }\n\n            case value_t::object:\n            {\n                result.m_it.object_iterator = m_value.object->erase(first.m_it.object_iterator,\n                                              last.m_it.object_iterator);\n                break;\n            }\n\n            case value_t::array:\n            {\n                result.m_it.array_iterator = m_value.array->erase(first.m_it.array_iterator,\n                                             last.m_it.array_iterator);\n                break;\n            }\n\n            default:\n                JSON_THROW(type_error::create(307, \"cannot use erase() with \" + std::string(type_name())));\n        }\n\n        return result;\n    }\n\n    /*!\n    @brief remove element from a JSON object given a key\n\n    Removes elements from a JSON object with the key value @a key.\n\n    @param[in] key value of the elements to remove\n\n    @return Number of elements removed. If @a ObjectType is the default\n    `std::map` type, the return value will always be `0` (@a key was not\n    found) or `1` (@a key was found).\n\n    @post References and iterators to the erased elements are invalidated.\n    Other references and iterators are not affected.\n\n    @throw type_error.307 when called on a type other than JSON object;\n    example: `\"cannot use erase() with null\"`\n\n    @complexity `log(size()) + count(key)`\n\n    @liveexample{The example shows the effect of `erase()`.,erase__key_type}\n\n    @sa @ref erase(IteratorType) -- removes the element at a given position\n    @sa @ref erase(IteratorType, IteratorType) -- removes the elements in\n    the given range\n    @sa @ref erase(const size_type) -- removes the element from an array at\n    the given index\n\n    @since version 1.0.0\n    */\n    size_type erase(const typename object_t::key_type& key)\n    {\n        // this erase only works for objects\n        if (JSON_LIKELY(is_object()))\n        {\n            return m_value.object->erase(key);\n        }\n\n        JSON_THROW(type_error::create(307, \"cannot use erase() with \" + std::string(type_name())));\n    }\n\n    /*!\n    @brief remove element from a JSON array given an index\n\n    Removes element from a JSON array at the index @a idx.\n\n    @param[in] idx index of the element to remove\n\n    @throw type_error.307 when called on a type other than JSON object;\n    example: `\"cannot use erase() with null\"`\n    @throw out_of_range.401 when `idx >= size()`; example: `\"array index 17\n    is out of range\"`\n\n    @complexity Linear in distance between @a idx and the end of the container.\n\n    @liveexample{The example shows the effect of `erase()`.,erase__size_type}\n\n    @sa @ref erase(IteratorType) -- removes the element at a given position\n    @sa @ref erase(IteratorType, IteratorType) -- removes the elements in\n    the given range\n    @sa @ref erase(const typename object_t::key_type&) -- removes the element\n    from an object at the given key\n\n    @since version 1.0.0\n    */\n    void erase(const size_type idx)\n    {\n        // this erase only works for arrays\n        if (JSON_LIKELY(is_array()))\n        {\n            if (JSON_UNLIKELY(idx >= size()))\n            {\n                JSON_THROW(out_of_range::create(401, \"array index \" + std::to_string(idx) + \" is out of range\"));\n            }\n\n            m_value.array->erase(m_value.array->begin() + static_cast<difference_type>(idx));\n        }\n        else\n        {\n            JSON_THROW(type_error::create(307, \"cannot use erase() with \" + std::string(type_name())));\n        }\n    }\n\n    /// @}\n\n\n    ////////////\n    // lookup //\n    ////////////\n\n    /// @name lookup\n    /// @{\n\n    /*!\n    @brief find an element in a JSON object\n\n    Finds an element in a JSON object with key equivalent to @a key. If the\n    element is not found or the JSON value is not an object, end() is\n    returned.\n\n    @note This method always returns @ref end() when executed on a JSON type\n          that is not an object.\n\n    @param[in] key key value of the element to search for.\n\n    @return Iterator to an element with key equivalent to @a key. If no such\n    element is found or the JSON value is not an object, past-the-end (see\n    @ref end()) iterator is returned.\n\n    @complexity Logarithmic in the size of the JSON object.\n\n    @liveexample{The example shows how `find()` is used.,find__key_type}\n\n    @since version 1.0.0\n    */\n    template<typename KeyT>\n    iterator find(KeyT&& key)\n    {\n        auto result = end();\n\n        if (is_object())\n        {\n            result.m_it.object_iterator = m_value.object->find(std::forward<KeyT>(key));\n        }\n\n        return result;\n    }\n\n    /*!\n    @brief find an element in a JSON object\n    @copydoc find(KeyT&&)\n    */\n    template<typename KeyT>\n    const_iterator find(KeyT&& key) const\n    {\n        auto result = cend();\n\n        if (is_object())\n        {\n            result.m_it.object_iterator = m_value.object->find(std::forward<KeyT>(key));\n        }\n\n        return result;\n    }\n\n    /*!\n    @brief returns the number of occurrences of a key in a JSON object\n\n    Returns the number of elements with key @a key. If ObjectType is the\n    default `std::map` type, the return value will always be `0` (@a key was\n    not found) or `1` (@a key was found).\n\n    @note This method always returns `0` when executed on a JSON type that is\n          not an object.\n\n    @param[in] key key value of the element to count\n\n    @return Number of elements with key @a key. If the JSON value is not an\n    object, the return value will be `0`.\n\n    @complexity Logarithmic in the size of the JSON object.\n\n    @liveexample{The example shows how `count()` is used.,count}\n\n    @since version 1.0.0\n    */\n    template<typename KeyT>\n    size_type count(KeyT&& key) const\n    {\n        // return 0 for all nonobject types\n        return is_object() ? m_value.object->count(std::forward<KeyT>(key)) : 0;\n    }\n\n    /// @}\n\n\n    ///////////////\n    // iterators //\n    ///////////////\n\n    /// @name iterators\n    /// @{\n\n    /*!\n    @brief returns an iterator to the first element\n\n    Returns an iterator to the first element.\n\n    @image html range-begin-end.svg \"Illustration from cppreference.com\"\n\n    @return iterator to the first element\n\n    @complexity Constant.\n\n    @requirement This function helps `basic_json` satisfying the\n    [Container](https://en.cppreference.com/w/cpp/named_req/Container)\n    requirements:\n    - The complexity is constant.\n\n    @liveexample{The following code shows an example for `begin()`.,begin}\n\n    @sa @ref cbegin() -- returns a const iterator to the beginning\n    @sa @ref end() -- returns an iterator to the end\n    @sa @ref cend() -- returns a const iterator to the end\n\n    @since version 1.0.0\n    */\n    iterator begin() noexcept\n    {\n        iterator result(this);\n        result.set_begin();\n        return result;\n    }\n\n    /*!\n    @copydoc basic_json::cbegin()\n    */\n    const_iterator begin() const noexcept\n    {\n        return cbegin();\n    }\n\n    /*!\n    @brief returns a const iterator to the first element\n\n    Returns a const iterator to the first element.\n\n    @image html range-begin-end.svg \"Illustration from cppreference.com\"\n\n    @return const iterator to the first element\n\n    @complexity Constant.\n\n    @requirement This function helps `basic_json` satisfying the\n    [Container](https://en.cppreference.com/w/cpp/named_req/Container)\n    requirements:\n    - The complexity is constant.\n    - Has the semantics of `const_cast<const basic_json&>(*this).begin()`.\n\n    @liveexample{The following code shows an example for `cbegin()`.,cbegin}\n\n    @sa @ref begin() -- returns an iterator to the beginning\n    @sa @ref end() -- returns an iterator to the end\n    @sa @ref cend() -- returns a const iterator to the end\n\n    @since version 1.0.0\n    */\n    const_iterator cbegin() const noexcept\n    {\n        const_iterator result(this);\n        result.set_begin();\n        return result;\n    }\n\n    /*!\n    @brief returns an iterator to one past the last element\n\n    Returns an iterator to one past the last element.\n\n    @image html range-begin-end.svg \"Illustration from cppreference.com\"\n\n    @return iterator one past the last element\n\n    @complexity Constant.\n\n    @requirement This function helps `basic_json` satisfying the\n    [Container](https://en.cppreference.com/w/cpp/named_req/Container)\n    requirements:\n    - The complexity is constant.\n\n    @liveexample{The following code shows an example for `end()`.,end}\n\n    @sa @ref cend() -- returns a const iterator to the end\n    @sa @ref begin() -- returns an iterator to the beginning\n    @sa @ref cbegin() -- returns a const iterator to the beginning\n\n    @since version 1.0.0\n    */\n    iterator end() noexcept\n    {\n        iterator result(this);\n        result.set_end();\n        return result;\n    }\n\n    /*!\n    @copydoc basic_json::cend()\n    */\n    const_iterator end() const noexcept\n    {\n        return cend();\n    }\n\n    /*!\n    @brief returns a const iterator to one past the last element\n\n    Returns a const iterator to one past the last element.\n\n    @image html range-begin-end.svg \"Illustration from cppreference.com\"\n\n    @return const iterator one past the last element\n\n    @complexity Constant.\n\n    @requirement This function helps `basic_json` satisfying the\n    [Container](https://en.cppreference.com/w/cpp/named_req/Container)\n    requirements:\n    - The complexity is constant.\n    - Has the semantics of `const_cast<const basic_json&>(*this).end()`.\n\n    @liveexample{The following code shows an example for `cend()`.,cend}\n\n    @sa @ref end() -- returns an iterator to the end\n    @sa @ref begin() -- returns an iterator to the beginning\n    @sa @ref cbegin() -- returns a const iterator to the beginning\n\n    @since version 1.0.0\n    */\n    const_iterator cend() const noexcept\n    {\n        const_iterator result(this);\n        result.set_end();\n        return result;\n    }\n\n    /*!\n    @brief returns an iterator to the reverse-beginning\n\n    Returns an iterator to the reverse-beginning; that is, the last element.\n\n    @image html range-rbegin-rend.svg \"Illustration from cppreference.com\"\n\n    @complexity Constant.\n\n    @requirement This function helps `basic_json` satisfying the\n    [ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer)\n    requirements:\n    - The complexity is constant.\n    - Has the semantics of `reverse_iterator(end())`.\n\n    @liveexample{The following code shows an example for `rbegin()`.,rbegin}\n\n    @sa @ref crbegin() -- returns a const reverse iterator to the beginning\n    @sa @ref rend() -- returns a reverse iterator to the end\n    @sa @ref crend() -- returns a const reverse iterator to the end\n\n    @since version 1.0.0\n    */\n    reverse_iterator rbegin() noexcept\n    {\n        return reverse_iterator(end());\n    }\n\n    /*!\n    @copydoc basic_json::crbegin()\n    */\n    const_reverse_iterator rbegin() const noexcept\n    {\n        return crbegin();\n    }\n\n    /*!\n    @brief returns an iterator to the reverse-end\n\n    Returns an iterator to the reverse-end; that is, one before the first\n    element.\n\n    @image html range-rbegin-rend.svg \"Illustration from cppreference.com\"\n\n    @complexity Constant.\n\n    @requirement This function helps `basic_json` satisfying the\n    [ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer)\n    requirements:\n    - The complexity is constant.\n    - Has the semantics of `reverse_iterator(begin())`.\n\n    @liveexample{The following code shows an example for `rend()`.,rend}\n\n    @sa @ref crend() -- returns a const reverse iterator to the end\n    @sa @ref rbegin() -- returns a reverse iterator to the beginning\n    @sa @ref crbegin() -- returns a const reverse iterator to the beginning\n\n    @since version 1.0.0\n    */\n    reverse_iterator rend() noexcept\n    {\n        return reverse_iterator(begin());\n    }\n\n    /*!\n    @copydoc basic_json::crend()\n    */\n    const_reverse_iterator rend() const noexcept\n    {\n        return crend();\n    }\n\n    /*!\n    @brief returns a const reverse iterator to the last element\n\n    Returns a const iterator to the reverse-beginning; that is, the last\n    element.\n\n    @image html range-rbegin-rend.svg \"Illustration from cppreference.com\"\n\n    @complexity Constant.\n\n    @requirement This function helps `basic_json` satisfying the\n    [ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer)\n    requirements:\n    - The complexity is constant.\n    - Has the semantics of `const_cast<const basic_json&>(*this).rbegin()`.\n\n    @liveexample{The following code shows an example for `crbegin()`.,crbegin}\n\n    @sa @ref rbegin() -- returns a reverse iterator to the beginning\n    @sa @ref rend() -- returns a reverse iterator to the end\n    @sa @ref crend() -- returns a const reverse iterator to the end\n\n    @since version 1.0.0\n    */\n    const_reverse_iterator crbegin() const noexcept\n    {\n        return const_reverse_iterator(cend());\n    }\n\n    /*!\n    @brief returns a const reverse iterator to one before the first\n\n    Returns a const reverse iterator to the reverse-end; that is, one before\n    the first element.\n\n    @image html range-rbegin-rend.svg \"Illustration from cppreference.com\"\n\n    @complexity Constant.\n\n    @requirement This function helps `basic_json` satisfying the\n    [ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer)\n    requirements:\n    - The complexity is constant.\n    - Has the semantics of `const_cast<const basic_json&>(*this).rend()`.\n\n    @liveexample{The following code shows an example for `crend()`.,crend}\n\n    @sa @ref rend() -- returns a reverse iterator to the end\n    @sa @ref rbegin() -- returns a reverse iterator to the beginning\n    @sa @ref crbegin() -- returns a const reverse iterator to the beginning\n\n    @since version 1.0.0\n    */\n    const_reverse_iterator crend() const noexcept\n    {\n        return const_reverse_iterator(cbegin());\n    }\n\n  public:\n    /*!\n    @brief wrapper to access iterator member functions in range-based for\n\n    This function allows to access @ref iterator::key() and @ref\n    iterator::value() during range-based for loops. In these loops, a\n    reference to the JSON values is returned, so there is no access to the\n    underlying iterator.\n\n    For loop without iterator_wrapper:\n\n    @code{cpp}\n    for (auto it = j_object.begin(); it != j_object.end(); ++it)\n    {\n        std::cout << \"key: \" << it.key() << \", value:\" << it.value() << '\\n';\n    }\n    @endcode\n\n    Range-based for loop without iterator proxy:\n\n    @code{cpp}\n    for (auto it : j_object)\n    {\n        // \"it\" is of type json::reference and has no key() member\n        std::cout << \"value: \" << it << '\\n';\n    }\n    @endcode\n\n    Range-based for loop with iterator proxy:\n\n    @code{cpp}\n    for (auto it : json::iterator_wrapper(j_object))\n    {\n        std::cout << \"key: \" << it.key() << \", value:\" << it.value() << '\\n';\n    }\n    @endcode\n\n    @note When iterating over an array, `key()` will return the index of the\n          element as string (see example).\n\n    @param[in] ref  reference to a JSON value\n    @return iteration proxy object wrapping @a ref with an interface to use in\n            range-based for loops\n\n    @liveexample{The following code shows how the wrapper is used,iterator_wrapper}\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes in the JSON value.\n\n    @complexity Constant.\n\n    @note The name of this function is not yet final and may change in the\n    future.\n\n    @deprecated This stream operator is deprecated and will be removed in\n                future 4.0.0 of the library. Please use @ref items() instead;\n                that is, replace `json::iterator_wrapper(j)` with `j.items()`.\n    */\n    JSON_DEPRECATED\n    static iteration_proxy<iterator> iterator_wrapper(reference ref) noexcept\n    {\n        return ref.items();\n    }\n\n    /*!\n    @copydoc iterator_wrapper(reference)\n    */\n    JSON_DEPRECATED\n    static iteration_proxy<const_iterator> iterator_wrapper(const_reference ref) noexcept\n    {\n        return ref.items();\n    }\n\n    /*!\n    @brief helper to access iterator member functions in range-based for\n\n    This function allows to access @ref iterator::key() and @ref\n    iterator::value() during range-based for loops. In these loops, a\n    reference to the JSON values is returned, so there is no access to the\n    underlying iterator.\n\n    For loop without `items()` function:\n\n    @code{cpp}\n    for (auto it = j_object.begin(); it != j_object.end(); ++it)\n    {\n        std::cout << \"key: \" << it.key() << \", value:\" << it.value() << '\\n';\n    }\n    @endcode\n\n    Range-based for loop without `items()` function:\n\n    @code{cpp}\n    for (auto it : j_object)\n    {\n        // \"it\" is of type json::reference and has no key() member\n        std::cout << \"value: \" << it << '\\n';\n    }\n    @endcode\n\n    Range-based for loop with `items()` function:\n\n    @code{cpp}\n    for (auto& el : j_object.items())\n    {\n        std::cout << \"key: \" << el.key() << \", value:\" << el.value() << '\\n';\n    }\n    @endcode\n\n    The `items()` function also allows to use\n    [structured bindings](https://en.cppreference.com/w/cpp/language/structured_binding)\n    (C++17):\n\n    @code{cpp}\n    for (auto& [key, val] : j_object.items())\n    {\n        std::cout << \"key: \" << key << \", value:\" << val << '\\n';\n    }\n    @endcode\n\n    @note When iterating over an array, `key()` will return the index of the\n          element as string (see example). For primitive types (e.g., numbers),\n          `key()` returns an empty string.\n\n    @return iteration proxy object wrapping @a ref with an interface to use in\n            range-based for loops\n\n    @liveexample{The following code shows how the function is used.,items}\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes in the JSON value.\n\n    @complexity Constant.\n\n    @since version 3.1.0, structured bindings support since 3.5.0.\n    */\n    iteration_proxy<iterator> items() noexcept\n    {\n        return iteration_proxy<iterator>(*this);\n    }\n\n    /*!\n    @copydoc items()\n    */\n    iteration_proxy<const_iterator> items() const noexcept\n    {\n        return iteration_proxy<const_iterator>(*this);\n    }\n\n    /// @}\n\n\n    //////////////\n    // capacity //\n    //////////////\n\n    /// @name capacity\n    /// @{\n\n    /*!\n    @brief checks whether the container is empty.\n\n    Checks if a JSON value has no elements (i.e. whether its @ref size is `0`).\n\n    @return The return value depends on the different types and is\n            defined as follows:\n            Value type  | return value\n            ----------- | -------------\n            null        | `true`\n            boolean     | `false`\n            string      | `false`\n            number      | `false`\n            object      | result of function `object_t::empty()`\n            array       | result of function `array_t::empty()`\n\n    @liveexample{The following code uses `empty()` to check if a JSON\n    object contains any elements.,empty}\n\n    @complexity Constant, as long as @ref array_t and @ref object_t satisfy\n    the Container concept; that is, their `empty()` functions have constant\n    complexity.\n\n    @iterators No changes.\n\n    @exceptionsafety No-throw guarantee: this function never throws exceptions.\n\n    @note This function does not return whether a string stored as JSON value\n    is empty - it returns whether the JSON container itself is empty which is\n    false in the case of a string.\n\n    @requirement This function helps `basic_json` satisfying the\n    [Container](https://en.cppreference.com/w/cpp/named_req/Container)\n    requirements:\n    - The complexity is constant.\n    - Has the semantics of `begin() == end()`.\n\n    @sa @ref size() -- returns the number of elements\n\n    @since version 1.0.0\n    */\n    bool empty() const noexcept\n    {\n        switch (m_type)\n        {\n            case value_t::null:\n            {\n                // null values are empty\n                return true;\n            }\n\n            case value_t::array:\n            {\n                // delegate call to array_t::empty()\n                return m_value.array->empty();\n            }\n\n            case value_t::object:\n            {\n                // delegate call to object_t::empty()\n                return m_value.object->empty();\n            }\n\n            default:\n            {\n                // all other types are nonempty\n                return false;\n            }\n        }\n    }\n\n    /*!\n    @brief returns the number of elements\n\n    Returns the number of elements in a JSON value.\n\n    @return The return value depends on the different types and is\n            defined as follows:\n            Value type  | return value\n            ----------- | -------------\n            null        | `0`\n            boolean     | `1`\n            string      | `1`\n            number      | `1`\n            object      | result of function object_t::size()\n            array       | result of function array_t::size()\n\n    @liveexample{The following code calls `size()` on the different value\n    types.,size}\n\n    @complexity Constant, as long as @ref array_t and @ref object_t satisfy\n    the Container concept; that is, their size() functions have constant\n    complexity.\n\n    @iterators No changes.\n\n    @exceptionsafety No-throw guarantee: this function never throws exceptions.\n\n    @note This function does not return the length of a string stored as JSON\n    value - it returns the number of elements in the JSON value which is 1 in\n    the case of a string.\n\n    @requirement This function helps `basic_json` satisfying the\n    [Container](https://en.cppreference.com/w/cpp/named_req/Container)\n    requirements:\n    - The complexity is constant.\n    - Has the semantics of `std::distance(begin(), end())`.\n\n    @sa @ref empty() -- checks whether the container is empty\n    @sa @ref max_size() -- returns the maximal number of elements\n\n    @since version 1.0.0\n    */\n    size_type size() const noexcept\n    {\n        switch (m_type)\n        {\n            case value_t::null:\n            {\n                // null values are empty\n                return 0;\n            }\n\n            case value_t::array:\n            {\n                // delegate call to array_t::size()\n                return m_value.array->size();\n            }\n\n            case value_t::object:\n            {\n                // delegate call to object_t::size()\n                return m_value.object->size();\n            }\n\n            default:\n            {\n                // all other types have size 1\n                return 1;\n            }\n        }\n    }\n\n    /*!\n    @brief returns the maximum possible number of elements\n\n    Returns the maximum number of elements a JSON value is able to hold due to\n    system or library implementation limitations, i.e. `std::distance(begin(),\n    end())` for the JSON value.\n\n    @return The return value depends on the different types and is\n            defined as follows:\n            Value type  | return value\n            ----------- | -------------\n            null        | `0` (same as `size()`)\n            boolean     | `1` (same as `size()`)\n            string      | `1` (same as `size()`)\n            number      | `1` (same as `size()`)\n            object      | result of function `object_t::max_size()`\n            array       | result of function `array_t::max_size()`\n\n    @liveexample{The following code calls `max_size()` on the different value\n    types. Note the output is implementation specific.,max_size}\n\n    @complexity Constant, as long as @ref array_t and @ref object_t satisfy\n    the Container concept; that is, their `max_size()` functions have constant\n    complexity.\n\n    @iterators No changes.\n\n    @exceptionsafety No-throw guarantee: this function never throws exceptions.\n\n    @requirement This function helps `basic_json` satisfying the\n    [Container](https://en.cppreference.com/w/cpp/named_req/Container)\n    requirements:\n    - The complexity is constant.\n    - Has the semantics of returning `b.size()` where `b` is the largest\n      possible JSON value.\n\n    @sa @ref size() -- returns the number of elements\n\n    @since version 1.0.0\n    */\n    size_type max_size() const noexcept\n    {\n        switch (m_type)\n        {\n            case value_t::array:\n            {\n                // delegate call to array_t::max_size()\n                return m_value.array->max_size();\n            }\n\n            case value_t::object:\n            {\n                // delegate call to object_t::max_size()\n                return m_value.object->max_size();\n            }\n\n            default:\n            {\n                // all other types have max_size() == size()\n                return size();\n            }\n        }\n    }\n\n    /// @}\n\n\n    ///////////////\n    // modifiers //\n    ///////////////\n\n    /// @name modifiers\n    /// @{\n\n    /*!\n    @brief clears the contents\n\n    Clears the content of a JSON value and resets it to the default value as\n    if @ref basic_json(value_t) would have been called with the current value\n    type from @ref type():\n\n    Value type  | initial value\n    ----------- | -------------\n    null        | `null`\n    boolean     | `false`\n    string      | `\"\"`\n    number      | `0`\n    object      | `{}`\n    array       | `[]`\n\n    @post Has the same effect as calling\n    @code {.cpp}\n    *this = basic_json(type());\n    @endcode\n\n    @liveexample{The example below shows the effect of `clear()` to different\n    JSON types.,clear}\n\n    @complexity Linear in the size of the JSON value.\n\n    @iterators All iterators, pointers and references related to this container\n               are invalidated.\n\n    @exceptionsafety No-throw guarantee: this function never throws exceptions.\n\n    @sa @ref basic_json(value_t) -- constructor that creates an object with the\n        same value than calling `clear()`\n\n    @since version 1.0.0\n    */\n    void clear() noexcept\n    {\n        switch (m_type)\n        {\n            case value_t::number_integer:\n            {\n                m_value.number_integer = 0;\n                break;\n            }\n\n            case value_t::number_unsigned:\n            {\n                m_value.number_unsigned = 0;\n                break;\n            }\n\n            case value_t::number_float:\n            {\n                m_value.number_float = 0.0;\n                break;\n            }\n\n            case value_t::boolean:\n            {\n                m_value.boolean = false;\n                break;\n            }\n\n            case value_t::string:\n            {\n                m_value.string->clear();\n                break;\n            }\n\n            case value_t::array:\n            {\n                m_value.array->clear();\n                break;\n            }\n\n            case value_t::object:\n            {\n                m_value.object->clear();\n                break;\n            }\n\n            default:\n                break;\n        }\n    }\n\n    /*!\n    @brief add an object to an array\n\n    Appends the given element @a val to the end of the JSON value. If the\n    function is called on a JSON null value, an empty array is created before\n    appending @a val.\n\n    @param[in] val the value to add to the JSON array\n\n    @throw type_error.308 when called on a type other than JSON array or\n    null; example: `\"cannot use push_back() with number\"`\n\n    @complexity Amortized constant.\n\n    @liveexample{The example shows how `push_back()` and `+=` can be used to\n    add elements to a JSON array. Note how the `null` value was silently\n    converted to a JSON array.,push_back}\n\n    @since version 1.0.0\n    */\n    void push_back(basic_json&& val)\n    {\n        // push_back only works for null objects or arrays\n        if (JSON_UNLIKELY(not(is_null() or is_array())))\n        {\n            JSON_THROW(type_error::create(308, \"cannot use push_back() with \" + std::string(type_name())));\n        }\n\n        // transform null object into an array\n        if (is_null())\n        {\n            m_type = value_t::array;\n            m_value = value_t::array;\n            assert_invariant();\n        }\n\n        // add element to array (move semantics)\n        m_value.array->push_back(std::move(val));\n        // invalidate object\n        val.m_type = value_t::null;\n    }\n\n    /*!\n    @brief add an object to an array\n    @copydoc push_back(basic_json&&)\n    */\n    reference operator+=(basic_json&& val)\n    {\n        push_back(std::move(val));\n        return *this;\n    }\n\n    /*!\n    @brief add an object to an array\n    @copydoc push_back(basic_json&&)\n    */\n    void push_back(const basic_json& val)\n    {\n        // push_back only works for null objects or arrays\n        if (JSON_UNLIKELY(not(is_null() or is_array())))\n        {\n            JSON_THROW(type_error::create(308, \"cannot use push_back() with \" + std::string(type_name())));\n        }\n\n        // transform null object into an array\n        if (is_null())\n        {\n            m_type = value_t::array;\n            m_value = value_t::array;\n            assert_invariant();\n        }\n\n        // add element to array\n        m_value.array->push_back(val);\n    }\n\n    /*!\n    @brief add an object to an array\n    @copydoc push_back(basic_json&&)\n    */\n    reference operator+=(const basic_json& val)\n    {\n        push_back(val);\n        return *this;\n    }\n\n    /*!\n    @brief add an object to an object\n\n    Inserts the given element @a val to the JSON object. If the function is\n    called on a JSON null value, an empty object is created before inserting\n    @a val.\n\n    @param[in] val the value to add to the JSON object\n\n    @throw type_error.308 when called on a type other than JSON object or\n    null; example: `\"cannot use push_back() with number\"`\n\n    @complexity Logarithmic in the size of the container, O(log(`size()`)).\n\n    @liveexample{The example shows how `push_back()` and `+=` can be used to\n    add elements to a JSON object. Note how the `null` value was silently\n    converted to a JSON object.,push_back__object_t__value}\n\n    @since version 1.0.0\n    */\n    void push_back(const typename object_t::value_type& val)\n    {\n        // push_back only works for null objects or objects\n        if (JSON_UNLIKELY(not(is_null() or is_object())))\n        {\n            JSON_THROW(type_error::create(308, \"cannot use push_back() with \" + std::string(type_name())));\n        }\n\n        // transform null object into an object\n        if (is_null())\n        {\n            m_type = value_t::object;\n            m_value = value_t::object;\n            assert_invariant();\n        }\n\n        // add element to array\n        m_value.object->insert(val);\n    }\n\n    /*!\n    @brief add an object to an object\n    @copydoc push_back(const typename object_t::value_type&)\n    */\n    reference operator+=(const typename object_t::value_type& val)\n    {\n        push_back(val);\n        return *this;\n    }\n\n    /*!\n    @brief add an object to an object\n\n    This function allows to use `push_back` with an initializer list. In case\n\n    1. the current value is an object,\n    2. the initializer list @a init contains only two elements, and\n    3. the first element of @a init is a string,\n\n    @a init is converted into an object element and added using\n    @ref push_back(const typename object_t::value_type&). Otherwise, @a init\n    is converted to a JSON value and added using @ref push_back(basic_json&&).\n\n    @param[in] init  an initializer list\n\n    @complexity Linear in the size of the initializer list @a init.\n\n    @note This function is required to resolve an ambiguous overload error,\n          because pairs like `{\"key\", \"value\"}` can be both interpreted as\n          `object_t::value_type` or `std::initializer_list<basic_json>`, see\n          https://github.com/nlohmann/json/issues/235 for more information.\n\n    @liveexample{The example shows how initializer lists are treated as\n    objects when possible.,push_back__initializer_list}\n    */\n    void push_back(initializer_list_t init)\n    {\n        if (is_object() and init.size() == 2 and (*init.begin())->is_string())\n        {\n            basic_json&& key = init.begin()->moved_or_copied();\n            push_back(typename object_t::value_type(\n                          std::move(key.get_ref<string_t&>()), (init.begin() + 1)->moved_or_copied()));\n        }\n        else\n        {\n            push_back(basic_json(init));\n        }\n    }\n\n    /*!\n    @brief add an object to an object\n    @copydoc push_back(initializer_list_t)\n    */\n    reference operator+=(initializer_list_t init)\n    {\n        push_back(init);\n        return *this;\n    }\n\n    /*!\n    @brief add an object to an array\n\n    Creates a JSON value from the passed parameters @a args to the end of the\n    JSON value. If the function is called on a JSON null value, an empty array\n    is created before appending the value created from @a args.\n\n    @param[in] args arguments to forward to a constructor of @ref basic_json\n    @tparam Args compatible types to create a @ref basic_json object\n\n    @throw type_error.311 when called on a type other than JSON array or\n    null; example: `\"cannot use emplace_back() with number\"`\n\n    @complexity Amortized constant.\n\n    @liveexample{The example shows how `push_back()` can be used to add\n    elements to a JSON array. Note how the `null` value was silently converted\n    to a JSON array.,emplace_back}\n\n    @since version 2.0.8\n    */\n    template<class... Args>\n    void emplace_back(Args&& ... args)\n    {\n        // emplace_back only works for null objects or arrays\n        if (JSON_UNLIKELY(not(is_null() or is_array())))\n        {\n            JSON_THROW(type_error::create(311, \"cannot use emplace_back() with \" + std::string(type_name())));\n        }\n\n        // transform null object into an array\n        if (is_null())\n        {\n            m_type = value_t::array;\n            m_value = value_t::array;\n            assert_invariant();\n        }\n\n        // add element to array (perfect forwarding)\n        m_value.array->emplace_back(std::forward<Args>(args)...);\n    }\n\n    /*!\n    @brief add an object to an object if key does not exist\n\n    Inserts a new element into a JSON object constructed in-place with the\n    given @a args if there is no element with the key in the container. If the\n    function is called on a JSON null value, an empty object is created before\n    appending the value created from @a args.\n\n    @param[in] args arguments to forward to a constructor of @ref basic_json\n    @tparam Args compatible types to create a @ref basic_json object\n\n    @return a pair consisting of an iterator to the inserted element, or the\n            already-existing element if no insertion happened, and a bool\n            denoting whether the insertion took place.\n\n    @throw type_error.311 when called on a type other than JSON object or\n    null; example: `\"cannot use emplace() with number\"`\n\n    @complexity Logarithmic in the size of the container, O(log(`size()`)).\n\n    @liveexample{The example shows how `emplace()` can be used to add elements\n    to a JSON object. Note how the `null` value was silently converted to a\n    JSON object. Further note how no value is added if there was already one\n    value stored with the same key.,emplace}\n\n    @since version 2.0.8\n    */\n    template<class... Args>\n    std::pair<iterator, bool> emplace(Args&& ... args)\n    {\n        // emplace only works for null objects or arrays\n        if (JSON_UNLIKELY(not(is_null() or is_object())))\n        {\n            JSON_THROW(type_error::create(311, \"cannot use emplace() with \" + std::string(type_name())));\n        }\n\n        // transform null object into an object\n        if (is_null())\n        {\n            m_type = value_t::object;\n            m_value = value_t::object;\n            assert_invariant();\n        }\n\n        // add element to array (perfect forwarding)\n        auto res = m_value.object->emplace(std::forward<Args>(args)...);\n        // create result iterator and set iterator to the result of emplace\n        auto it = begin();\n        it.m_it.object_iterator = res.first;\n\n        // return pair of iterator and boolean\n        return {it, res.second};\n    }\n\n    /// Helper for insertion of an iterator\n    /// @note: This uses std::distance to support GCC 4.8,\n    ///        see https://github.com/nlohmann/json/pull/1257\n    template<typename... Args>\n    iterator insert_iterator(const_iterator pos, Args&& ... args)\n    {\n        iterator result(this);\n        assert(m_value.array != nullptr);\n\n        auto insert_pos = std::distance(m_value.array->begin(), pos.m_it.array_iterator);\n        m_value.array->insert(pos.m_it.array_iterator, std::forward<Args>(args)...);\n        result.m_it.array_iterator = m_value.array->begin() + insert_pos;\n\n        // This could have been written as:\n        // result.m_it.array_iterator = m_value.array->insert(pos.m_it.array_iterator, cnt, val);\n        // but the return value of insert is missing in GCC 4.8, so it is written this way instead.\n\n        return result;\n    }\n\n    /*!\n    @brief inserts element\n\n    Inserts element @a val before iterator @a pos.\n\n    @param[in] pos iterator before which the content will be inserted; may be\n    the end() iterator\n    @param[in] val element to insert\n    @return iterator pointing to the inserted @a val.\n\n    @throw type_error.309 if called on JSON values other than arrays;\n    example: `\"cannot use insert() with string\"`\n    @throw invalid_iterator.202 if @a pos is not an iterator of *this;\n    example: `\"iterator does not fit current value\"`\n\n    @complexity Constant plus linear in the distance between @a pos and end of\n    the container.\n\n    @liveexample{The example shows how `insert()` is used.,insert}\n\n    @since version 1.0.0\n    */\n    iterator insert(const_iterator pos, const basic_json& val)\n    {\n        // insert only works for arrays\n        if (JSON_LIKELY(is_array()))\n        {\n            // check if iterator pos fits to this JSON value\n            if (JSON_UNLIKELY(pos.m_object != this))\n            {\n                JSON_THROW(invalid_iterator::create(202, \"iterator does not fit current value\"));\n            }\n\n            // insert to array and return iterator\n            return insert_iterator(pos, val);\n        }\n\n        JSON_THROW(type_error::create(309, \"cannot use insert() with \" + std::string(type_name())));\n    }\n\n    /*!\n    @brief inserts element\n    @copydoc insert(const_iterator, const basic_json&)\n    */\n    iterator insert(const_iterator pos, basic_json&& val)\n    {\n        return insert(pos, val);\n    }\n\n    /*!\n    @brief inserts elements\n\n    Inserts @a cnt copies of @a val before iterator @a pos.\n\n    @param[in] pos iterator before which the content will be inserted; may be\n    the end() iterator\n    @param[in] cnt number of copies of @a val to insert\n    @param[in] val element to insert\n    @return iterator pointing to the first element inserted, or @a pos if\n    `cnt==0`\n\n    @throw type_error.309 if called on JSON values other than arrays; example:\n    `\"cannot use insert() with string\"`\n    @throw invalid_iterator.202 if @a pos is not an iterator of *this;\n    example: `\"iterator does not fit current value\"`\n\n    @complexity Linear in @a cnt plus linear in the distance between @a pos\n    and end of the container.\n\n    @liveexample{The example shows how `insert()` is used.,insert__count}\n\n    @since version 1.0.0\n    */\n    iterator insert(const_iterator pos, size_type cnt, const basic_json& val)\n    {\n        // insert only works for arrays\n        if (JSON_LIKELY(is_array()))\n        {\n            // check if iterator pos fits to this JSON value\n            if (JSON_UNLIKELY(pos.m_object != this))\n            {\n                JSON_THROW(invalid_iterator::create(202, \"iterator does not fit current value\"));\n            }\n\n            // insert to array and return iterator\n            return insert_iterator(pos, cnt, val);\n        }\n\n        JSON_THROW(type_error::create(309, \"cannot use insert() with \" + std::string(type_name())));\n    }\n\n    /*!\n    @brief inserts elements\n\n    Inserts elements from range `[first, last)` before iterator @a pos.\n\n    @param[in] pos iterator before which the content will be inserted; may be\n    the end() iterator\n    @param[in] first begin of the range of elements to insert\n    @param[in] last end of the range of elements to insert\n\n    @throw type_error.309 if called on JSON values other than arrays; example:\n    `\"cannot use insert() with string\"`\n    @throw invalid_iterator.202 if @a pos is not an iterator of *this;\n    example: `\"iterator does not fit current value\"`\n    @throw invalid_iterator.210 if @a first and @a last do not belong to the\n    same JSON value; example: `\"iterators do not fit\"`\n    @throw invalid_iterator.211 if @a first or @a last are iterators into\n    container for which insert is called; example: `\"passed iterators may not\n    belong to container\"`\n\n    @return iterator pointing to the first element inserted, or @a pos if\n    `first==last`\n\n    @complexity Linear in `std::distance(first, last)` plus linear in the\n    distance between @a pos and end of the container.\n\n    @liveexample{The example shows how `insert()` is used.,insert__range}\n\n    @since version 1.0.0\n    */\n    iterator insert(const_iterator pos, const_iterator first, const_iterator last)\n    {\n        // insert only works for arrays\n        if (JSON_UNLIKELY(not is_array()))\n        {\n            JSON_THROW(type_error::create(309, \"cannot use insert() with \" + std::string(type_name())));\n        }\n\n        // check if iterator pos fits to this JSON value\n        if (JSON_UNLIKELY(pos.m_object != this))\n        {\n            JSON_THROW(invalid_iterator::create(202, \"iterator does not fit current value\"));\n        }\n\n        // check if range iterators belong to the same JSON object\n        if (JSON_UNLIKELY(first.m_object != last.m_object))\n        {\n            JSON_THROW(invalid_iterator::create(210, \"iterators do not fit\"));\n        }\n\n        if (JSON_UNLIKELY(first.m_object == this))\n        {\n            JSON_THROW(invalid_iterator::create(211, \"passed iterators may not belong to container\"));\n        }\n\n        // insert to array and return iterator\n        return insert_iterator(pos, first.m_it.array_iterator, last.m_it.array_iterator);\n    }\n\n    /*!\n    @brief inserts elements\n\n    Inserts elements from initializer list @a ilist before iterator @a pos.\n\n    @param[in] pos iterator before which the content will be inserted; may be\n    the end() iterator\n    @param[in] ilist initializer list to insert the values from\n\n    @throw type_error.309 if called on JSON values other than arrays; example:\n    `\"cannot use insert() with string\"`\n    @throw invalid_iterator.202 if @a pos is not an iterator of *this;\n    example: `\"iterator does not fit current value\"`\n\n    @return iterator pointing to the first element inserted, or @a pos if\n    `ilist` is empty\n\n    @complexity Linear in `ilist.size()` plus linear in the distance between\n    @a pos and end of the container.\n\n    @liveexample{The example shows how `insert()` is used.,insert__ilist}\n\n    @since version 1.0.0\n    */\n    iterator insert(const_iterator pos, initializer_list_t ilist)\n    {\n        // insert only works for arrays\n        if (JSON_UNLIKELY(not is_array()))\n        {\n            JSON_THROW(type_error::create(309, \"cannot use insert() with \" + std::string(type_name())));\n        }\n\n        // check if iterator pos fits to this JSON value\n        if (JSON_UNLIKELY(pos.m_object != this))\n        {\n            JSON_THROW(invalid_iterator::create(202, \"iterator does not fit current value\"));\n        }\n\n        // insert to array and return iterator\n        return insert_iterator(pos, ilist.begin(), ilist.end());\n    }\n\n    /*!\n    @brief inserts elements\n\n    Inserts elements from range `[first, last)`.\n\n    @param[in] first begin of the range of elements to insert\n    @param[in] last end of the range of elements to insert\n\n    @throw type_error.309 if called on JSON values other than objects; example:\n    `\"cannot use insert() with string\"`\n    @throw invalid_iterator.202 if iterator @a first or @a last does does not\n    point to an object; example: `\"iterators first and last must point to\n    objects\"`\n    @throw invalid_iterator.210 if @a first and @a last do not belong to the\n    same JSON value; example: `\"iterators do not fit\"`\n\n    @complexity Logarithmic: `O(N*log(size() + N))`, where `N` is the number\n    of elements to insert.\n\n    @liveexample{The example shows how `insert()` is used.,insert__range_object}\n\n    @since version 3.0.0\n    */\n    void insert(const_iterator first, const_iterator last)\n    {\n        // insert only works for objects\n        if (JSON_UNLIKELY(not is_object()))\n        {\n            JSON_THROW(type_error::create(309, \"cannot use insert() with \" + std::string(type_name())));\n        }\n\n        // check if range iterators belong to the same JSON object\n        if (JSON_UNLIKELY(first.m_object != last.m_object))\n        {\n            JSON_THROW(invalid_iterator::create(210, \"iterators do not fit\"));\n        }\n\n        // passed iterators must belong to objects\n        if (JSON_UNLIKELY(not first.m_object->is_object()))\n        {\n            JSON_THROW(invalid_iterator::create(202, \"iterators first and last must point to objects\"));\n        }\n\n        m_value.object->insert(first.m_it.object_iterator, last.m_it.object_iterator);\n    }\n\n    /*!\n    @brief updates a JSON object from another object, overwriting existing keys\n\n    Inserts all values from JSON object @a j and overwrites existing keys.\n\n    @param[in] j  JSON object to read values from\n\n    @throw type_error.312 if called on JSON values other than objects; example:\n    `\"cannot use update() with string\"`\n\n    @complexity O(N*log(size() + N)), where N is the number of elements to\n                insert.\n\n    @liveexample{The example shows how `update()` is used.,update}\n\n    @sa https://docs.python.org/3.6/library/stdtypes.html#dict.update\n\n    @since version 3.0.0\n    */\n    void update(const_reference j)\n    {\n        // implicitly convert null value to an empty object\n        if (is_null())\n        {\n            m_type = value_t::object;\n            m_value.object = create<object_t>();\n            assert_invariant();\n        }\n\n        if (JSON_UNLIKELY(not is_object()))\n        {\n            JSON_THROW(type_error::create(312, \"cannot use update() with \" + std::string(type_name())));\n        }\n        if (JSON_UNLIKELY(not j.is_object()))\n        {\n            JSON_THROW(type_error::create(312, \"cannot use update() with \" + std::string(j.type_name())));\n        }\n\n        for (auto it = j.cbegin(); it != j.cend(); ++it)\n        {\n            m_value.object->operator[](it.key()) = it.value();\n        }\n    }\n\n    /*!\n    @brief updates a JSON object from another object, overwriting existing keys\n\n    Inserts all values from from range `[first, last)` and overwrites existing\n    keys.\n\n    @param[in] first begin of the range of elements to insert\n    @param[in] last end of the range of elements to insert\n\n    @throw type_error.312 if called on JSON values other than objects; example:\n    `\"cannot use update() with string\"`\n    @throw invalid_iterator.202 if iterator @a first or @a last does does not\n    point to an object; example: `\"iterators first and last must point to\n    objects\"`\n    @throw invalid_iterator.210 if @a first and @a last do not belong to the\n    same JSON value; example: `\"iterators do not fit\"`\n\n    @complexity O(N*log(size() + N)), where N is the number of elements to\n                insert.\n\n    @liveexample{The example shows how `update()` is used__range.,update}\n\n    @sa https://docs.python.org/3.6/library/stdtypes.html#dict.update\n\n    @since version 3.0.0\n    */\n    void update(const_iterator first, const_iterator last)\n    {\n        // implicitly convert null value to an empty object\n        if (is_null())\n        {\n            m_type = value_t::object;\n            m_value.object = create<object_t>();\n            assert_invariant();\n        }\n\n        if (JSON_UNLIKELY(not is_object()))\n        {\n            JSON_THROW(type_error::create(312, \"cannot use update() with \" + std::string(type_name())));\n        }\n\n        // check if range iterators belong to the same JSON object\n        if (JSON_UNLIKELY(first.m_object != last.m_object))\n        {\n            JSON_THROW(invalid_iterator::create(210, \"iterators do not fit\"));\n        }\n\n        // passed iterators must belong to objects\n        if (JSON_UNLIKELY(not first.m_object->is_object()\n                          or not last.m_object->is_object()))\n        {\n            JSON_THROW(invalid_iterator::create(202, \"iterators first and last must point to objects\"));\n        }\n\n        for (auto it = first; it != last; ++it)\n        {\n            m_value.object->operator[](it.key()) = it.value();\n        }\n    }\n\n    /*!\n    @brief exchanges the values\n\n    Exchanges the contents of the JSON value with those of @a other. Does not\n    invoke any move, copy, or swap operations on individual elements. All\n    iterators and references remain valid. The past-the-end iterator is\n    invalidated.\n\n    @param[in,out] other JSON value to exchange the contents with\n\n    @complexity Constant.\n\n    @liveexample{The example below shows how JSON values can be swapped with\n    `swap()`.,swap__reference}\n\n    @since version 1.0.0\n    */\n    void swap(reference other) noexcept (\n        std::is_nothrow_move_constructible<value_t>::value and\n        std::is_nothrow_move_assignable<value_t>::value and\n        std::is_nothrow_move_constructible<json_value>::value and\n        std::is_nothrow_move_assignable<json_value>::value\n    )\n    {\n        std::swap(m_type, other.m_type);\n        std::swap(m_value, other.m_value);\n        assert_invariant();\n    }\n\n    /*!\n    @brief exchanges the values\n\n    Exchanges the contents of a JSON array with those of @a other. Does not\n    invoke any move, copy, or swap operations on individual elements. All\n    iterators and references remain valid. The past-the-end iterator is\n    invalidated.\n\n    @param[in,out] other array to exchange the contents with\n\n    @throw type_error.310 when JSON value is not an array; example: `\"cannot\n    use swap() with string\"`\n\n    @complexity Constant.\n\n    @liveexample{The example below shows how arrays can be swapped with\n    `swap()`.,swap__array_t}\n\n    @since version 1.0.0\n    */\n    void swap(array_t& other)\n    {\n        // swap only works for arrays\n        if (JSON_LIKELY(is_array()))\n        {\n            std::swap(*(m_value.array), other);\n        }\n        else\n        {\n            JSON_THROW(type_error::create(310, \"cannot use swap() with \" + std::string(type_name())));\n        }\n    }\n\n    /*!\n    @brief exchanges the values\n\n    Exchanges the contents of a JSON object with those of @a other. Does not\n    invoke any move, copy, or swap operations on individual elements. All\n    iterators and references remain valid. The past-the-end iterator is\n    invalidated.\n\n    @param[in,out] other object to exchange the contents with\n\n    @throw type_error.310 when JSON value is not an object; example:\n    `\"cannot use swap() with string\"`\n\n    @complexity Constant.\n\n    @liveexample{The example below shows how objects can be swapped with\n    `swap()`.,swap__object_t}\n\n    @since version 1.0.0\n    */\n    void swap(object_t& other)\n    {\n        // swap only works for objects\n        if (JSON_LIKELY(is_object()))\n        {\n            std::swap(*(m_value.object), other);\n        }\n        else\n        {\n            JSON_THROW(type_error::create(310, \"cannot use swap() with \" + std::string(type_name())));\n        }\n    }\n\n    /*!\n    @brief exchanges the values\n\n    Exchanges the contents of a JSON string with those of @a other. Does not\n    invoke any move, copy, or swap operations on individual elements. All\n    iterators and references remain valid. The past-the-end iterator is\n    invalidated.\n\n    @param[in,out] other string to exchange the contents with\n\n    @throw type_error.310 when JSON value is not a string; example: `\"cannot\n    use swap() with boolean\"`\n\n    @complexity Constant.\n\n    @liveexample{The example below shows how strings can be swapped with\n    `swap()`.,swap__string_t}\n\n    @since version 1.0.0\n    */\n    void swap(string_t& other)\n    {\n        // swap only works for strings\n        if (JSON_LIKELY(is_string()))\n        {\n            std::swap(*(m_value.string), other);\n        }\n        else\n        {\n            JSON_THROW(type_error::create(310, \"cannot use swap() with \" + std::string(type_name())));\n        }\n    }\n\n    /// @}\n\n  public:\n    //////////////////////////////////////////\n    // lexicographical comparison operators //\n    //////////////////////////////////////////\n\n    /// @name lexicographical comparison operators\n    /// @{\n\n    /*!\n    @brief comparison: equal\n\n    Compares two JSON values for equality according to the following rules:\n    - Two JSON values are equal if (1) they are from the same type and (2)\n      their stored values are the same according to their respective\n      `operator==`.\n    - Integer and floating-point numbers are automatically converted before\n      comparison. Note than two NaN values are always treated as unequal.\n    - Two JSON null values are equal.\n\n    @note Floating-point inside JSON values numbers are compared with\n    `json::number_float_t::operator==` which is `double::operator==` by\n    default. To compare floating-point while respecting an epsilon, an alternative\n    [comparison function](https://github.com/mariokonrad/marnav/blob/master/src/marnav/math/floatingpoint.hpp#L34-#L39)\n    could be used, for instance\n    @code {.cpp}\n    template<typename T, typename = typename std::enable_if<std::is_floating_point<T>::value, T>::type>\n    inline bool is_same(T a, T b, T epsilon = std::numeric_limits<T>::epsilon()) noexcept\n    {\n        return std::abs(a - b) <= epsilon;\n    }\n    @endcode\n\n    @note NaN values never compare equal to themselves or to other NaN values.\n\n    @param[in] lhs  first JSON value to consider\n    @param[in] rhs  second JSON value to consider\n    @return whether the values @a lhs and @a rhs are equal\n\n    @exceptionsafety No-throw guarantee: this function never throws exceptions.\n\n    @complexity Linear.\n\n    @liveexample{The example demonstrates comparing several JSON\n    types.,operator__equal}\n\n    @since version 1.0.0\n    */\n    friend bool operator==(const_reference lhs, const_reference rhs) noexcept\n    {\n        const auto lhs_type = lhs.type();\n        const auto rhs_type = rhs.type();\n\n        if (lhs_type == rhs_type)\n        {\n            switch (lhs_type)\n            {\n                case value_t::array:\n                    return (*lhs.m_value.array == *rhs.m_value.array);\n\n                case value_t::object:\n                    return (*lhs.m_value.object == *rhs.m_value.object);\n\n                case value_t::null:\n                    return true;\n\n                case value_t::string:\n                    return (*lhs.m_value.string == *rhs.m_value.string);\n\n                case value_t::boolean:\n                    return (lhs.m_value.boolean == rhs.m_value.boolean);\n\n                case value_t::number_integer:\n                    return (lhs.m_value.number_integer == rhs.m_value.number_integer);\n\n                case value_t::number_unsigned:\n                    return (lhs.m_value.number_unsigned == rhs.m_value.number_unsigned);\n\n                case value_t::number_float:\n                    return (lhs.m_value.number_float == rhs.m_value.number_float);\n\n                default:\n                    return false;\n            }\n        }\n        else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float)\n        {\n            return (static_cast<number_float_t>(lhs.m_value.number_integer) == rhs.m_value.number_float);\n        }\n        else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer)\n        {\n            return (lhs.m_value.number_float == static_cast<number_float_t>(rhs.m_value.number_integer));\n        }\n        else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float)\n        {\n            return (static_cast<number_float_t>(lhs.m_value.number_unsigned) == rhs.m_value.number_float);\n        }\n        else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned)\n        {\n            return (lhs.m_value.number_float == static_cast<number_float_t>(rhs.m_value.number_unsigned));\n        }\n        else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer)\n        {\n            return (static_cast<number_integer_t>(lhs.m_value.number_unsigned) == rhs.m_value.number_integer);\n        }\n        else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned)\n        {\n            return (lhs.m_value.number_integer == static_cast<number_integer_t>(rhs.m_value.number_unsigned));\n        }\n\n        return false;\n    }\n\n    /*!\n    @brief comparison: equal\n    @copydoc operator==(const_reference, const_reference)\n    */\n    template<typename ScalarType, typename std::enable_if<\n                 std::is_scalar<ScalarType>::value, int>::type = 0>\n    friend bool operator==(const_reference lhs, const ScalarType rhs) noexcept\n    {\n        return (lhs == basic_json(rhs));\n    }\n\n    /*!\n    @brief comparison: equal\n    @copydoc operator==(const_reference, const_reference)\n    */\n    template<typename ScalarType, typename std::enable_if<\n                 std::is_scalar<ScalarType>::value, int>::type = 0>\n    friend bool operator==(const ScalarType lhs, const_reference rhs) noexcept\n    {\n        return (basic_json(lhs) == rhs);\n    }\n\n    /*!\n    @brief comparison: not equal\n\n    Compares two JSON values for inequality by calculating `not (lhs == rhs)`.\n\n    @param[in] lhs  first JSON value to consider\n    @param[in] rhs  second JSON value to consider\n    @return whether the values @a lhs and @a rhs are not equal\n\n    @complexity Linear.\n\n    @exceptionsafety No-throw guarantee: this function never throws exceptions.\n\n    @liveexample{The example demonstrates comparing several JSON\n    types.,operator__notequal}\n\n    @since version 1.0.0\n    */\n    friend bool operator!=(const_reference lhs, const_reference rhs) noexcept\n    {\n        return not (lhs == rhs);\n    }\n\n    /*!\n    @brief comparison: not equal\n    @copydoc operator!=(const_reference, const_reference)\n    */\n    template<typename ScalarType, typename std::enable_if<\n                 std::is_scalar<ScalarType>::value, int>::type = 0>\n    friend bool operator!=(const_reference lhs, const ScalarType rhs) noexcept\n    {\n        return (lhs != basic_json(rhs));\n    }\n\n    /*!\n    @brief comparison: not equal\n    @copydoc operator!=(const_reference, const_reference)\n    */\n    template<typename ScalarType, typename std::enable_if<\n                 std::is_scalar<ScalarType>::value, int>::type = 0>\n    friend bool operator!=(const ScalarType lhs, const_reference rhs) noexcept\n    {\n        return (basic_json(lhs) != rhs);\n    }\n\n    /*!\n    @brief comparison: less than\n\n    Compares whether one JSON value @a lhs is less than another JSON value @a\n    rhs according to the following rules:\n    - If @a lhs and @a rhs have the same type, the values are compared using\n      the default `<` operator.\n    - Integer and floating-point numbers are automatically converted before\n      comparison\n    - In case @a lhs and @a rhs have different types, the values are ignored\n      and the order of the types is considered, see\n      @ref operator<(const value_t, const value_t).\n\n    @param[in] lhs  first JSON value to consider\n    @param[in] rhs  second JSON value to consider\n    @return whether @a lhs is less than @a rhs\n\n    @complexity Linear.\n\n    @exceptionsafety No-throw guarantee: this function never throws exceptions.\n\n    @liveexample{The example demonstrates comparing several JSON\n    types.,operator__less}\n\n    @since version 1.0.0\n    */\n    friend bool operator<(const_reference lhs, const_reference rhs) noexcept\n    {\n        const auto lhs_type = lhs.type();\n        const auto rhs_type = rhs.type();\n\n        if (lhs_type == rhs_type)\n        {\n            switch (lhs_type)\n            {\n                case value_t::array:\n                    return (*lhs.m_value.array) < (*rhs.m_value.array);\n\n                case value_t::object:\n                    return *lhs.m_value.object < *rhs.m_value.object;\n\n                case value_t::null:\n                    return false;\n\n                case value_t::string:\n                    return *lhs.m_value.string < *rhs.m_value.string;\n\n                case value_t::boolean:\n                    return lhs.m_value.boolean < rhs.m_value.boolean;\n\n                case value_t::number_integer:\n                    return lhs.m_value.number_integer < rhs.m_value.number_integer;\n\n                case value_t::number_unsigned:\n                    return lhs.m_value.number_unsigned < rhs.m_value.number_unsigned;\n\n                case value_t::number_float:\n                    return lhs.m_value.number_float < rhs.m_value.number_float;\n\n                default:\n                    return false;\n            }\n        }\n        else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float)\n        {\n            return static_cast<number_float_t>(lhs.m_value.number_integer) < rhs.m_value.number_float;\n        }\n        else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer)\n        {\n            return lhs.m_value.number_float < static_cast<number_float_t>(rhs.m_value.number_integer);\n        }\n        else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float)\n        {\n            return static_cast<number_float_t>(lhs.m_value.number_unsigned) < rhs.m_value.number_float;\n        }\n        else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned)\n        {\n            return lhs.m_value.number_float < static_cast<number_float_t>(rhs.m_value.number_unsigned);\n        }\n        else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned)\n        {\n            return lhs.m_value.number_integer < static_cast<number_integer_t>(rhs.m_value.number_unsigned);\n        }\n        else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer)\n        {\n            return static_cast<number_integer_t>(lhs.m_value.number_unsigned) < rhs.m_value.number_integer;\n        }\n\n        // We only reach this line if we cannot compare values. In that case,\n        // we compare types. Note we have to call the operator explicitly,\n        // because MSVC has problems otherwise.\n        return operator<(lhs_type, rhs_type);\n    }\n\n    /*!\n    @brief comparison: less than\n    @copydoc operator<(const_reference, const_reference)\n    */\n    template<typename ScalarType, typename std::enable_if<\n                 std::is_scalar<ScalarType>::value, int>::type = 0>\n    friend bool operator<(const_reference lhs, const ScalarType rhs) noexcept\n    {\n        return (lhs < basic_json(rhs));\n    }\n\n    /*!\n    @brief comparison: less than\n    @copydoc operator<(const_reference, const_reference)\n    */\n    template<typename ScalarType, typename std::enable_if<\n                 std::is_scalar<ScalarType>::value, int>::type = 0>\n    friend bool operator<(const ScalarType lhs, const_reference rhs) noexcept\n    {\n        return (basic_json(lhs) < rhs);\n    }\n\n    /*!\n    @brief comparison: less than or equal\n\n    Compares whether one JSON value @a lhs is less than or equal to another\n    JSON value by calculating `not (rhs < lhs)`.\n\n    @param[in] lhs  first JSON value to consider\n    @param[in] rhs  second JSON value to consider\n    @return whether @a lhs is less than or equal to @a rhs\n\n    @complexity Linear.\n\n    @exceptionsafety No-throw guarantee: this function never throws exceptions.\n\n    @liveexample{The example demonstrates comparing several JSON\n    types.,operator__greater}\n\n    @since version 1.0.0\n    */\n    friend bool operator<=(const_reference lhs, const_reference rhs) noexcept\n    {\n        return not (rhs < lhs);\n    }\n\n    /*!\n    @brief comparison: less than or equal\n    @copydoc operator<=(const_reference, const_reference)\n    */\n    template<typename ScalarType, typename std::enable_if<\n                 std::is_scalar<ScalarType>::value, int>::type = 0>\n    friend bool operator<=(const_reference lhs, const ScalarType rhs) noexcept\n    {\n        return (lhs <= basic_json(rhs));\n    }\n\n    /*!\n    @brief comparison: less than or equal\n    @copydoc operator<=(const_reference, const_reference)\n    */\n    template<typename ScalarType, typename std::enable_if<\n                 std::is_scalar<ScalarType>::value, int>::type = 0>\n    friend bool operator<=(const ScalarType lhs, const_reference rhs) noexcept\n    {\n        return (basic_json(lhs) <= rhs);\n    }\n\n    /*!\n    @brief comparison: greater than\n\n    Compares whether one JSON value @a lhs is greater than another\n    JSON value by calculating `not (lhs <= rhs)`.\n\n    @param[in] lhs  first JSON value to consider\n    @param[in] rhs  second JSON value to consider\n    @return whether @a lhs is greater than to @a rhs\n\n    @complexity Linear.\n\n    @exceptionsafety No-throw guarantee: this function never throws exceptions.\n\n    @liveexample{The example demonstrates comparing several JSON\n    types.,operator__lessequal}\n\n    @since version 1.0.0\n    */\n    friend bool operator>(const_reference lhs, const_reference rhs) noexcept\n    {\n        return not (lhs <= rhs);\n    }\n\n    /*!\n    @brief comparison: greater than\n    @copydoc operator>(const_reference, const_reference)\n    */\n    template<typename ScalarType, typename std::enable_if<\n                 std::is_scalar<ScalarType>::value, int>::type = 0>\n    friend bool operator>(const_reference lhs, const ScalarType rhs) noexcept\n    {\n        return (lhs > basic_json(rhs));\n    }\n\n    /*!\n    @brief comparison: greater than\n    @copydoc operator>(const_reference, const_reference)\n    */\n    template<typename ScalarType, typename std::enable_if<\n                 std::is_scalar<ScalarType>::value, int>::type = 0>\n    friend bool operator>(const ScalarType lhs, const_reference rhs) noexcept\n    {\n        return (basic_json(lhs) > rhs);\n    }\n\n    /*!\n    @brief comparison: greater than or equal\n\n    Compares whether one JSON value @a lhs is greater than or equal to another\n    JSON value by calculating `not (lhs < rhs)`.\n\n    @param[in] lhs  first JSON value to consider\n    @param[in] rhs  second JSON value to consider\n    @return whether @a lhs is greater than or equal to @a rhs\n\n    @complexity Linear.\n\n    @exceptionsafety No-throw guarantee: this function never throws exceptions.\n\n    @liveexample{The example demonstrates comparing several JSON\n    types.,operator__greaterequal}\n\n    @since version 1.0.0\n    */\n    friend bool operator>=(const_reference lhs, const_reference rhs) noexcept\n    {\n        return not (lhs < rhs);\n    }\n\n    /*!\n    @brief comparison: greater than or equal\n    @copydoc operator>=(const_reference, const_reference)\n    */\n    template<typename ScalarType, typename std::enable_if<\n                 std::is_scalar<ScalarType>::value, int>::type = 0>\n    friend bool operator>=(const_reference lhs, const ScalarType rhs) noexcept\n    {\n        return (lhs >= basic_json(rhs));\n    }\n\n    /*!\n    @brief comparison: greater than or equal\n    @copydoc operator>=(const_reference, const_reference)\n    */\n    template<typename ScalarType, typename std::enable_if<\n                 std::is_scalar<ScalarType>::value, int>::type = 0>\n    friend bool operator>=(const ScalarType lhs, const_reference rhs) noexcept\n    {\n        return (basic_json(lhs) >= rhs);\n    }\n\n    /// @}\n\n    ///////////////////\n    // serialization //\n    ///////////////////\n\n    /// @name serialization\n    /// @{\n\n    /*!\n    @brief serialize to stream\n\n    Serialize the given JSON value @a j to the output stream @a o. The JSON\n    value will be serialized using the @ref dump member function.\n\n    - The indentation of the output can be controlled with the member variable\n      `width` of the output stream @a o. For instance, using the manipulator\n      `std::setw(4)` on @a o sets the indentation level to `4` and the\n      serialization result is the same as calling `dump(4)`.\n\n    - The indentation character can be controlled with the member variable\n      `fill` of the output stream @a o. For instance, the manipulator\n      `std::setfill('\\\\t')` sets indentation to use a tab character rather than\n      the default space character.\n\n    @param[in,out] o  stream to serialize to\n    @param[in] j  JSON value to serialize\n\n    @return the stream @a o\n\n    @throw type_error.316 if a string stored inside the JSON value is not\n                          UTF-8 encoded\n\n    @complexity Linear.\n\n    @liveexample{The example below shows the serialization with different\n    parameters to `width` to adjust the indentation level.,operator_serialize}\n\n    @since version 1.0.0; indentation character added in version 3.0.0\n    */\n    friend std::ostream& operator<<(std::ostream& o, const basic_json& j)\n    {\n        // read width member and use it as indentation parameter if nonzero\n        const bool pretty_print = (o.width() > 0);\n        const auto indentation = (pretty_print ? o.width() : 0);\n\n        // reset width to 0 for subsequent calls to this stream\n        o.width(0);\n\n        // do the actual serialization\n        serializer s(detail::output_adapter<char>(o), o.fill());\n        s.dump(j, pretty_print, false, static_cast<unsigned int>(indentation));\n        return o;\n    }\n\n    /*!\n    @brief serialize to stream\n    @deprecated This stream operator is deprecated and will be removed in\n                future 4.0.0 of the library. Please use\n                @ref operator<<(std::ostream&, const basic_json&)\n                instead; that is, replace calls like `j >> o;` with `o << j;`.\n    @since version 1.0.0; deprecated since version 3.0.0\n    */\n    JSON_DEPRECATED\n    friend std::ostream& operator>>(const basic_json& j, std::ostream& o)\n    {\n        return o << j;\n    }\n\n    /// @}\n\n\n    /////////////////////\n    // deserialization //\n    /////////////////////\n\n    /// @name deserialization\n    /// @{\n\n    /*!\n    @brief deserialize from a compatible input\n\n    This function reads from a compatible input. Examples are:\n    - an array of 1-byte values\n    - strings with character/literal type with size of 1 byte\n    - input streams\n    - container with contiguous storage of 1-byte values. Compatible container\n      types include `std::vector`, `std::string`, `std::array`,\n      `std::valarray`, and `std::initializer_list`. Furthermore, C-style\n      arrays can be used with `std::begin()`/`std::end()`. User-defined\n      containers can be used as long as they implement random-access iterators\n      and a contiguous storage.\n\n    @pre Each element of the container has a size of 1 byte. Violating this\n    precondition yields undefined behavior. **This precondition is enforced\n    with a static assertion.**\n\n    @pre The container storage is contiguous. Violating this precondition\n    yields undefined behavior. **This precondition is enforced with an\n    assertion.**\n    @pre Each element of the container has a size of 1 byte. Violating this\n    precondition yields undefined behavior. **This precondition is enforced\n    with a static assertion.**\n\n    @warning There is no way to enforce all preconditions at compile-time. If\n             the function is called with a noncompliant container and with\n             assertions switched off, the behavior is undefined and will most\n             likely yield segmentation violation.\n\n    @param[in] i  input to read from\n    @param[in] cb  a parser callback function of type @ref parser_callback_t\n    which is used to control the deserialization by filtering unwanted values\n    (optional)\n    @param[in] allow_exceptions  whether to throw exceptions in case of a\n    parse error (optional, true by default)\n\n    @return result of the deserialization\n\n    @throw parse_error.101 if a parse error occurs; example: `\"\"unexpected end\n    of input; expected string literal\"\"`\n    @throw parse_error.102 if to_unicode fails or surrogate error\n    @throw parse_error.103 if to_unicode fails\n\n    @complexity Linear in the length of the input. The parser is a predictive\n    LL(1) parser. The complexity can be higher if the parser callback function\n    @a cb has a super-linear complexity.\n\n    @note A UTF-8 byte order mark is silently ignored.\n\n    @liveexample{The example below demonstrates the `parse()` function reading\n    from an array.,parse__array__parser_callback_t}\n\n    @liveexample{The example below demonstrates the `parse()` function with\n    and without callback function.,parse__string__parser_callback_t}\n\n    @liveexample{The example below demonstrates the `parse()` function with\n    and without callback function.,parse__istream__parser_callback_t}\n\n    @liveexample{The example below demonstrates the `parse()` function reading\n    from a contiguous container.,parse__contiguouscontainer__parser_callback_t}\n\n    @since version 2.0.3 (contiguous containers)\n    */\n    static basic_json parse(detail::input_adapter&& i,\n                            const parser_callback_t cb = nullptr,\n                            const bool allow_exceptions = true)\n    {\n        basic_json result;\n        parser(i, cb, allow_exceptions).parse(true, result);\n        return result;\n    }\n\n    static bool accept(detail::input_adapter&& i)\n    {\n        return parser(i).accept(true);\n    }\n\n    /*!\n    @brief generate SAX events\n\n    The SAX event lister must follow the interface of @ref json_sax.\n\n    This function reads from a compatible input. Examples are:\n    - an array of 1-byte values\n    - strings with character/literal type with size of 1 byte\n    - input streams\n    - container with contiguous storage of 1-byte values. Compatible container\n      types include `std::vector`, `std::string`, `std::array`,\n      `std::valarray`, and `std::initializer_list`. Furthermore, C-style\n      arrays can be used with `std::begin()`/`std::end()`. User-defined\n      containers can be used as long as they implement random-access iterators\n      and a contiguous storage.\n\n    @pre Each element of the container has a size of 1 byte. Violating this\n    precondition yields undefined behavior. **This precondition is enforced\n    with a static assertion.**\n\n    @pre The container storage is contiguous. Violating this precondition\n    yields undefined behavior. **This precondition is enforced with an\n    assertion.**\n    @pre Each element of the container has a size of 1 byte. Violating this\n    precondition yields undefined behavior. **This precondition is enforced\n    with a static assertion.**\n\n    @warning There is no way to enforce all preconditions at compile-time. If\n             the function is called with a noncompliant container and with\n             assertions switched off, the behavior is undefined and will most\n             likely yield segmentation violation.\n\n    @param[in] i  input to read from\n    @param[in,out] sax  SAX event listener\n    @param[in] format  the format to parse (JSON, CBOR, MessagePack, or UBJSON)\n    @param[in] strict  whether the input has to be consumed completely\n\n    @return return value of the last processed SAX event\n\n    @throw parse_error.101 if a parse error occurs; example: `\"\"unexpected end\n    of input; expected string literal\"\"`\n    @throw parse_error.102 if to_unicode fails or surrogate error\n    @throw parse_error.103 if to_unicode fails\n\n    @complexity Linear in the length of the input. The parser is a predictive\n    LL(1) parser. The complexity can be higher if the SAX consumer @a sax has\n    a super-linear complexity.\n\n    @note A UTF-8 byte order mark is silently ignored.\n\n    @liveexample{The example below demonstrates the `sax_parse()` function\n    reading from string and processing the events with a user-defined SAX\n    event consumer.,sax_parse}\n\n    @since version 3.2.0\n    */\n    template <typename SAX>\n    static bool sax_parse(detail::input_adapter&& i, SAX* sax,\n                          input_format_t format = input_format_t::json,\n                          const bool strict = true)\n    {\n        assert(sax);\n        switch (format)\n        {\n            case input_format_t::json:\n                return parser(std::move(i)).sax_parse(sax, strict);\n            default:\n                return detail::binary_reader<basic_json, SAX>(std::move(i)).sax_parse(format, sax, strict);\n        }\n    }\n\n    /*!\n    @brief deserialize from an iterator range with contiguous storage\n\n    This function reads from an iterator range of a container with contiguous\n    storage of 1-byte values. Compatible container types include\n    `std::vector`, `std::string`, `std::array`, `std::valarray`, and\n    `std::initializer_list`. Furthermore, C-style arrays can be used with\n    `std::begin()`/`std::end()`. User-defined containers can be used as long\n    as they implement random-access iterators and a contiguous storage.\n\n    @pre The iterator range is contiguous. Violating this precondition yields\n    undefined behavior. **This precondition is enforced with an assertion.**\n    @pre Each element in the range has a size of 1 byte. Violating this\n    precondition yields undefined behavior. **This precondition is enforced\n    with a static assertion.**\n\n    @warning There is no way to enforce all preconditions at compile-time. If\n             the function is called with noncompliant iterators and with\n             assertions switched off, the behavior is undefined and will most\n             likely yield segmentation violation.\n\n    @tparam IteratorType iterator of container with contiguous storage\n    @param[in] first  begin of the range to parse (included)\n    @param[in] last  end of the range to parse (excluded)\n    @param[in] cb  a parser callback function of type @ref parser_callback_t\n    which is used to control the deserialization by filtering unwanted values\n    (optional)\n    @param[in] allow_exceptions  whether to throw exceptions in case of a\n    parse error (optional, true by default)\n\n    @return result of the deserialization\n\n    @throw parse_error.101 in case of an unexpected token\n    @throw parse_error.102 if to_unicode fails or surrogate error\n    @throw parse_error.103 if to_unicode fails\n\n    @complexity Linear in the length of the input. The parser is a predictive\n    LL(1) parser. The complexity can be higher if the parser callback function\n    @a cb has a super-linear complexity.\n\n    @note A UTF-8 byte order mark is silently ignored.\n\n    @liveexample{The example below demonstrates the `parse()` function reading\n    from an iterator range.,parse__iteratortype__parser_callback_t}\n\n    @since version 2.0.3\n    */\n    template<class IteratorType, typename std::enable_if<\n                 std::is_base_of<\n                     std::random_access_iterator_tag,\n                     typename std::iterator_traits<IteratorType>::iterator_category>::value, int>::type = 0>\n    static basic_json parse(IteratorType first, IteratorType last,\n                            const parser_callback_t cb = nullptr,\n                            const bool allow_exceptions = true)\n    {\n        basic_json result;\n        parser(detail::input_adapter(first, last), cb, allow_exceptions).parse(true, result);\n        return result;\n    }\n\n    template<class IteratorType, typename std::enable_if<\n                 std::is_base_of<\n                     std::random_access_iterator_tag,\n                     typename std::iterator_traits<IteratorType>::iterator_category>::value, int>::type = 0>\n    static bool accept(IteratorType first, IteratorType last)\n    {\n        return parser(detail::input_adapter(first, last)).accept(true);\n    }\n\n    template<class IteratorType, class SAX, typename std::enable_if<\n                 std::is_base_of<\n                     std::random_access_iterator_tag,\n                     typename std::iterator_traits<IteratorType>::iterator_category>::value, int>::type = 0>\n    static bool sax_parse(IteratorType first, IteratorType last, SAX* sax)\n    {\n        return parser(detail::input_adapter(first, last)).sax_parse(sax);\n    }\n\n    /*!\n    @brief deserialize from stream\n    @deprecated This stream operator is deprecated and will be removed in\n                version 4.0.0 of the library. Please use\n                @ref operator>>(std::istream&, basic_json&)\n                instead; that is, replace calls like `j << i;` with `i >> j;`.\n    @since version 1.0.0; deprecated since version 3.0.0\n    */\n    JSON_DEPRECATED\n    friend std::istream& operator<<(basic_json& j, std::istream& i)\n    {\n        return operator>>(i, j);\n    }\n\n    /*!\n    @brief deserialize from stream\n\n    Deserializes an input stream to a JSON value.\n\n    @param[in,out] i  input stream to read a serialized JSON value from\n    @param[in,out] j  JSON value to write the deserialized input to\n\n    @throw parse_error.101 in case of an unexpected token\n    @throw parse_error.102 if to_unicode fails or surrogate error\n    @throw parse_error.103 if to_unicode fails\n\n    @complexity Linear in the length of the input. The parser is a predictive\n    LL(1) parser.\n\n    @note A UTF-8 byte order mark is silently ignored.\n\n    @liveexample{The example below shows how a JSON value is constructed by\n    reading a serialization from a stream.,operator_deserialize}\n\n    @sa parse(std::istream&, const parser_callback_t) for a variant with a\n    parser callback function to filter values while parsing\n\n    @since version 1.0.0\n    */\n    friend std::istream& operator>>(std::istream& i, basic_json& j)\n    {\n        parser(detail::input_adapter(i)).parse(false, j);\n        return i;\n    }\n\n    /// @}\n\n    ///////////////////////////\n    // convenience functions //\n    ///////////////////////////\n\n    /*!\n    @brief return the type as string\n\n    Returns the type name as string to be used in error messages - usually to\n    indicate that a function was called on a wrong JSON type.\n\n    @return a string representation of a the @a m_type member:\n            Value type  | return value\n            ----------- | -------------\n            null        | `\"null\"`\n            boolean     | `\"boolean\"`\n            string      | `\"string\"`\n            number      | `\"number\"` (for all number types)\n            object      | `\"object\"`\n            array       | `\"array\"`\n            discarded   | `\"discarded\"`\n\n    @exceptionsafety No-throw guarantee: this function never throws exceptions.\n\n    @complexity Constant.\n\n    @liveexample{The following code exemplifies `type_name()` for all JSON\n    types.,type_name}\n\n    @sa @ref type() -- return the type of the JSON value\n    @sa @ref operator value_t() -- return the type of the JSON value (implicit)\n\n    @since version 1.0.0, public since 2.1.0, `const char*` and `noexcept`\n    since 3.0.0\n    */\n    const char* type_name() const noexcept\n    {\n        {\n            switch (m_type)\n            {\n                case value_t::null:\n                    return \"null\";\n                case value_t::object:\n                    return \"object\";\n                case value_t::array:\n                    return \"array\";\n                case value_t::string:\n                    return \"string\";\n                case value_t::boolean:\n                    return \"boolean\";\n                case value_t::discarded:\n                    return \"discarded\";\n                default:\n                    return \"number\";\n            }\n        }\n    }\n\n\n  private:\n    //////////////////////\n    // member variables //\n    //////////////////////\n\n    /// the type of the current element\n    value_t m_type = value_t::null;\n\n    /// the value of the current element\n    json_value m_value = {};\n\n    //////////////////////////////////////////\n    // binary serialization/deserialization //\n    //////////////////////////////////////////\n\n    /// @name binary serialization/deserialization support\n    /// @{\n\n  public:\n    /*!\n    @brief create a CBOR serialization of a given JSON value\n\n    Serializes a given JSON value @a j to a byte vector using the CBOR (Concise\n    Binary Object Representation) serialization format. CBOR is a binary\n    serialization format which aims to be more compact than JSON itself, yet\n    more efficient to parse.\n\n    The library uses the following mapping from JSON values types to\n    CBOR types according to the CBOR specification (RFC 7049):\n\n    JSON value type | value/range                                | CBOR type                          | first byte\n    --------------- | ------------------------------------------ | ---------------------------------- | ---------------\n    null            | `null`                                     | Null                               | 0xF6\n    boolean         | `true`                                     | True                               | 0xF5\n    boolean         | `false`                                    | False                              | 0xF4\n    number_integer  | -9223372036854775808..-2147483649          | Negative integer (8 bytes follow)  | 0x3B\n    number_integer  | -2147483648..-32769                        | Negative integer (4 bytes follow)  | 0x3A\n    number_integer  | -32768..-129                               | Negative integer (2 bytes follow)  | 0x39\n    number_integer  | -128..-25                                  | Negative integer (1 byte follow)   | 0x38\n    number_integer  | -24..-1                                    | Negative integer                   | 0x20..0x37\n    number_integer  | 0..23                                      | Integer                            | 0x00..0x17\n    number_integer  | 24..255                                    | Unsigned integer (1 byte follow)   | 0x18\n    number_integer  | 256..65535                                 | Unsigned integer (2 bytes follow)  | 0x19\n    number_integer  | 65536..4294967295                          | Unsigned integer (4 bytes follow)  | 0x1A\n    number_integer  | 4294967296..18446744073709551615           | Unsigned integer (8 bytes follow)  | 0x1B\n    number_unsigned | 0..23                                      | Integer                            | 0x00..0x17\n    number_unsigned | 24..255                                    | Unsigned integer (1 byte follow)   | 0x18\n    number_unsigned | 256..65535                                 | Unsigned integer (2 bytes follow)  | 0x19\n    number_unsigned | 65536..4294967295                          | Unsigned integer (4 bytes follow)  | 0x1A\n    number_unsigned | 4294967296..18446744073709551615           | Unsigned integer (8 bytes follow)  | 0x1B\n    number_float    | *any value*                                | Double-Precision Float             | 0xFB\n    string          | *length*: 0..23                            | UTF-8 string                       | 0x60..0x77\n    string          | *length*: 23..255                          | UTF-8 string (1 byte follow)       | 0x78\n    string          | *length*: 256..65535                       | UTF-8 string (2 bytes follow)      | 0x79\n    string          | *length*: 65536..4294967295                | UTF-8 string (4 bytes follow)      | 0x7A\n    string          | *length*: 4294967296..18446744073709551615 | UTF-8 string (8 bytes follow)      | 0x7B\n    array           | *size*: 0..23                              | array                              | 0x80..0x97\n    array           | *size*: 23..255                            | array (1 byte follow)              | 0x98\n    array           | *size*: 256..65535                         | array (2 bytes follow)             | 0x99\n    array           | *size*: 65536..4294967295                  | array (4 bytes follow)             | 0x9A\n    array           | *size*: 4294967296..18446744073709551615   | array (8 bytes follow)             | 0x9B\n    object          | *size*: 0..23                              | map                                | 0xA0..0xB7\n    object          | *size*: 23..255                            | map (1 byte follow)                | 0xB8\n    object          | *size*: 256..65535                         | map (2 bytes follow)               | 0xB9\n    object          | *size*: 65536..4294967295                  | map (4 bytes follow)               | 0xBA\n    object          | *size*: 4294967296..18446744073709551615   | map (8 bytes follow)               | 0xBB\n\n    @note The mapping is **complete** in the sense that any JSON value type\n          can be converted to a CBOR value.\n\n    @note If NaN or Infinity are stored inside a JSON number, they are\n          serialized properly. This behavior differs from the @ref dump()\n          function which serializes NaN or Infinity to `null`.\n\n    @note The following CBOR types are not used in the conversion:\n          - byte strings (0x40..0x5F)\n          - UTF-8 strings terminated by \"break\" (0x7F)\n          - arrays terminated by \"break\" (0x9F)\n          - maps terminated by \"break\" (0xBF)\n          - date/time (0xC0..0xC1)\n          - bignum (0xC2..0xC3)\n          - decimal fraction (0xC4)\n          - bigfloat (0xC5)\n          - tagged items (0xC6..0xD4, 0xD8..0xDB)\n          - expected conversions (0xD5..0xD7)\n          - simple values (0xE0..0xF3, 0xF8)\n          - undefined (0xF7)\n          - half and single-precision floats (0xF9-0xFA)\n          - break (0xFF)\n\n    @param[in] j  JSON value to serialize\n    @return MessagePack serialization as byte vector\n\n    @complexity Linear in the size of the JSON value @a j.\n\n    @liveexample{The example shows the serialization of a JSON value to a byte\n    vector in CBOR format.,to_cbor}\n\n    @sa http://cbor.io\n    @sa @ref from_cbor(detail::input_adapter&&, const bool, const bool) for the\n        analogous deserialization\n    @sa @ref to_msgpack(const basic_json&) for the related MessagePack format\n    @sa @ref to_ubjson(const basic_json&, const bool, const bool) for the\n             related UBJSON format\n\n    @since version 2.0.9\n    */\n    static std::vector<uint8_t> to_cbor(const basic_json& j)\n    {\n        std::vector<uint8_t> result;\n        to_cbor(j, result);\n        return result;\n    }\n\n    static void to_cbor(const basic_json& j, detail::output_adapter<uint8_t> o)\n    {\n        binary_writer<uint8_t>(o).write_cbor(j);\n    }\n\n    static void to_cbor(const basic_json& j, detail::output_adapter<char> o)\n    {\n        binary_writer<char>(o).write_cbor(j);\n    }\n\n    /*!\n    @brief create a MessagePack serialization of a given JSON value\n\n    Serializes a given JSON value @a j to a byte vector using the MessagePack\n    serialization format. MessagePack is a binary serialization format which\n    aims to be more compact than JSON itself, yet more efficient to parse.\n\n    The library uses the following mapping from JSON values types to\n    MessagePack types according to the MessagePack specification:\n\n    JSON value type | value/range                       | MessagePack type | first byte\n    --------------- | --------------------------------- | ---------------- | ----------\n    null            | `null`                            | nil              | 0xC0\n    boolean         | `true`                            | true             | 0xC3\n    boolean         | `false`                           | false            | 0xC2\n    number_integer  | -9223372036854775808..-2147483649 | int64            | 0xD3\n    number_integer  | -2147483648..-32769               | int32            | 0xD2\n    number_integer  | -32768..-129                      | int16            | 0xD1\n    number_integer  | -128..-33                         | int8             | 0xD0\n    number_integer  | -32..-1                           | negative fixint  | 0xE0..0xFF\n    number_integer  | 0..127                            | positive fixint  | 0x00..0x7F\n    number_integer  | 128..255                          | uint 8           | 0xCC\n    number_integer  | 256..65535                        | uint 16          | 0xCD\n    number_integer  | 65536..4294967295                 | uint 32          | 0xCE\n    number_integer  | 4294967296..18446744073709551615  | uint 64          | 0xCF\n    number_unsigned | 0..127                            | positive fixint  | 0x00..0x7F\n    number_unsigned | 128..255                          | uint 8           | 0xCC\n    number_unsigned | 256..65535                        | uint 16          | 0xCD\n    number_unsigned | 65536..4294967295                 | uint 32          | 0xCE\n    number_unsigned | 4294967296..18446744073709551615  | uint 64          | 0xCF\n    number_float    | *any value*                       | float 64         | 0xCB\n    string          | *length*: 0..31                   | fixstr           | 0xA0..0xBF\n    string          | *length*: 32..255                 | str 8            | 0xD9\n    string          | *length*: 256..65535              | str 16           | 0xDA\n    string          | *length*: 65536..4294967295       | str 32           | 0xDB\n    array           | *size*: 0..15                     | fixarray         | 0x90..0x9F\n    array           | *size*: 16..65535                 | array 16         | 0xDC\n    array           | *size*: 65536..4294967295         | array 32         | 0xDD\n    object          | *size*: 0..15                     | fix map          | 0x80..0x8F\n    object          | *size*: 16..65535                 | map 16           | 0xDE\n    object          | *size*: 65536..4294967295         | map 32           | 0xDF\n\n    @note The mapping is **complete** in the sense that any JSON value type\n          can be converted to a MessagePack value.\n\n    @note The following values can **not** be converted to a MessagePack value:\n          - strings with more than 4294967295 bytes\n          - arrays with more than 4294967295 elements\n          - objects with more than 4294967295 elements\n\n    @note The following MessagePack types are not used in the conversion:\n          - bin 8 - bin 32 (0xC4..0xC6)\n          - ext 8 - ext 32 (0xC7..0xC9)\n          - float 32 (0xCA)\n          - fixext 1 - fixext 16 (0xD4..0xD8)\n\n    @note Any MessagePack output created @ref to_msgpack can be successfully\n          parsed by @ref from_msgpack.\n\n    @note If NaN or Infinity are stored inside a JSON number, they are\n          serialized properly. This behavior differs from the @ref dump()\n          function which serializes NaN or Infinity to `null`.\n\n    @param[in] j  JSON value to serialize\n    @return MessagePack serialization as byte vector\n\n    @complexity Linear in the size of the JSON value @a j.\n\n    @liveexample{The example shows the serialization of a JSON value to a byte\n    vector in MessagePack format.,to_msgpack}\n\n    @sa http://msgpack.org\n    @sa @ref from_msgpack for the analogous deserialization\n    @sa @ref to_cbor(const basic_json& for the related CBOR format\n    @sa @ref to_ubjson(const basic_json&, const bool, const bool) for the\n             related UBJSON format\n\n    @since version 2.0.9\n    */\n    static std::vector<uint8_t> to_msgpack(const basic_json& j)\n    {\n        std::vector<uint8_t> result;\n        to_msgpack(j, result);\n        return result;\n    }\n\n    static void to_msgpack(const basic_json& j, detail::output_adapter<uint8_t> o)\n    {\n        binary_writer<uint8_t>(o).write_msgpack(j);\n    }\n\n    static void to_msgpack(const basic_json& j, detail::output_adapter<char> o)\n    {\n        binary_writer<char>(o).write_msgpack(j);\n    }\n\n    /*!\n    @brief create a UBJSON serialization of a given JSON value\n\n    Serializes a given JSON value @a j to a byte vector using the UBJSON\n    (Universal Binary JSON) serialization format. UBJSON aims to be more compact\n    than JSON itself, yet more efficient to parse.\n\n    The library uses the following mapping from JSON values types to\n    UBJSON types according to the UBJSON specification:\n\n    JSON value type | value/range                       | UBJSON type | marker\n    --------------- | --------------------------------- | ----------- | ------\n    null            | `null`                            | null        | `Z`\n    boolean         | `true`                            | true        | `T`\n    boolean         | `false`                           | false       | `F`\n    number_integer  | -9223372036854775808..-2147483649 | int64       | `L`\n    number_integer  | -2147483648..-32769               | int32       | `l`\n    number_integer  | -32768..-129                      | int16       | `I`\n    number_integer  | -128..127                         | int8        | `i`\n    number_integer  | 128..255                          | uint8       | `U`\n    number_integer  | 256..32767                        | int16       | `I`\n    number_integer  | 32768..2147483647                 | int32       | `l`\n    number_integer  | 2147483648..9223372036854775807   | int64       | `L`\n    number_unsigned | 0..127                            | int8        | `i`\n    number_unsigned | 128..255                          | uint8       | `U`\n    number_unsigned | 256..32767                        | int16       | `I`\n    number_unsigned | 32768..2147483647                 | int32       | `l`\n    number_unsigned | 2147483648..9223372036854775807   | int64       | `L`\n    number_float    | *any value*                       | float64     | `D`\n    string          | *with shortest length indicator*  | string      | `S`\n    array           | *see notes on optimized format*   | array       | `[`\n    object          | *see notes on optimized format*   | map         | `{`\n\n    @note The mapping is **complete** in the sense that any JSON value type\n          can be converted to a UBJSON value.\n\n    @note The following values can **not** be converted to a UBJSON value:\n          - strings with more than 9223372036854775807 bytes (theoretical)\n          - unsigned integer numbers above 9223372036854775807\n\n    @note The following markers are not used in the conversion:\n          - `Z`: no-op values are not created.\n          - `C`: single-byte strings are serialized with `S` markers.\n\n    @note Any UBJSON output created @ref to_ubjson can be successfully parsed\n          by @ref from_ubjson.\n\n    @note If NaN or Infinity are stored inside a JSON number, they are\n          serialized properly. This behavior differs from the @ref dump()\n          function which serializes NaN or Infinity to `null`.\n\n    @note The optimized formats for containers are supported: Parameter\n          @a use_size adds size information to the beginning of a container and\n          removes the closing marker. Parameter @a use_type further checks\n          whether all elements of a container have the same type and adds the\n          type marker to the beginning of the container. The @a use_type\n          parameter must only be used together with @a use_size = true. Note\n          that @a use_size = true alone may result in larger representations -\n          the benefit of this parameter is that the receiving side is\n          immediately informed on the number of elements of the container.\n\n    @param[in] j  JSON value to serialize\n    @param[in] use_size  whether to add size annotations to container types\n    @param[in] use_type  whether to add type annotations to container types\n                         (must be combined with @a use_size = true)\n    @return UBJSON serialization as byte vector\n\n    @complexity Linear in the size of the JSON value @a j.\n\n    @liveexample{The example shows the serialization of a JSON value to a byte\n    vector in UBJSON format.,to_ubjson}\n\n    @sa http://ubjson.org\n    @sa @ref from_ubjson(detail::input_adapter&&, const bool, const bool) for the\n        analogous deserialization\n    @sa @ref to_cbor(const basic_json& for the related CBOR format\n    @sa @ref to_msgpack(const basic_json&) for the related MessagePack format\n\n    @since version 3.1.0\n    */\n    static std::vector<uint8_t> to_ubjson(const basic_json& j,\n                                          const bool use_size = false,\n                                          const bool use_type = false)\n    {\n        std::vector<uint8_t> result;\n        to_ubjson(j, result, use_size, use_type);\n        return result;\n    }\n\n    static void to_ubjson(const basic_json& j, detail::output_adapter<uint8_t> o,\n                          const bool use_size = false, const bool use_type = false)\n    {\n        binary_writer<uint8_t>(o).write_ubjson(j, use_size, use_type);\n    }\n\n    static void to_ubjson(const basic_json& j, detail::output_adapter<char> o,\n                          const bool use_size = false, const bool use_type = false)\n    {\n        binary_writer<char>(o).write_ubjson(j, use_size, use_type);\n    }\n\n\n    /*!\n    @brief Serializes the given JSON object `j` to BSON and returns a vector\n           containing the corresponding BSON-representation.\n\n    BSON (Binary JSON) is a binary format in which zero or more ordered key/value pairs are\n    stored as a single entity (a so-called document).\n\n    The library uses the following mapping from JSON values types to BSON types:\n\n    JSON value type | value/range                       | BSON type   | marker\n    --------------- | --------------------------------- | ----------- | ------\n    null            | `null`                            | null        | 0x0A\n    boolean         | `true`, `false`                   | boolean     | 0x08\n    number_integer  | -9223372036854775808..-2147483649 | int64       | 0x12\n    number_integer  | -2147483648..2147483647           | int32       | 0x10\n    number_integer  | 2147483648..9223372036854775807   | int64       | 0x12\n    number_unsigned | 0..2147483647                     | int32       | 0x10\n    number_unsigned | 2147483648..9223372036854775807   | int64       | 0x12\n    number_unsigned | 9223372036854775808..18446744073709551615| --   | --\n    number_float    | *any value*                       | double      | 0x01\n    string          | *any value*                       | string      | 0x02\n    array           | *any value*                       | document    | 0x04\n    object          | *any value*                       | document    | 0x03\n\n    @warning The mapping is **incomplete**, since only JSON-objects (and things\n    contained therein) can be serialized to BSON.\n    Also, integers larger than 9223372036854775807 cannot be serialized to BSON,\n    and the keys may not contain U+0000, since they are serialized a\n    zero-terminated c-strings.\n\n    @throw out_of_range.407  if `j.is_number_unsigned() && j.get<std::uint64_t>() > 9223372036854775807`\n    @throw out_of_range.409  if a key in `j` contains a NULL (U+0000)\n    @throw type_error.317    if `!j.is_object()`\n\n    @pre The input `j` is required to be an object: `j.is_object() == true`.\n\n    @note Any BSON output created via @ref to_bson can be successfully parsed\n          by @ref from_bson.\n\n    @param[in] j  JSON value to serialize\n    @return BSON serialization as byte vector\n\n    @complexity Linear in the size of the JSON value @a j.\n\n    @liveexample{The example shows the serialization of a JSON value to a byte\n    vector in BSON format.,to_bson}\n\n    @sa http://bsonspec.org/spec.html\n    @sa @ref from_bson(detail::input_adapter&&, const bool strict) for the\n        analogous deserialization\n    @sa @ref to_ubjson(const basic_json&, const bool, const bool) for the\n             related UBJSON format\n    @sa @ref to_cbor(const basic_json&) for the related CBOR format\n    @sa @ref to_msgpack(const basic_json&) for the related MessagePack format\n    */\n    static std::vector<uint8_t> to_bson(const basic_json& j)\n    {\n        std::vector<uint8_t> result;\n        to_bson(j, result);\n        return result;\n    }\n\n    /*!\n    @brief Serializes the given JSON object `j` to BSON and forwards the\n           corresponding BSON-representation to the given output_adapter `o`.\n    @param j The JSON object to convert to BSON.\n    @param o The output adapter that receives the binary BSON representation.\n    @pre The input `j` shall be an object: `j.is_object() == true`\n    @sa @ref to_bson(const basic_json&)\n    */\n    static void to_bson(const basic_json& j, detail::output_adapter<uint8_t> o)\n    {\n        binary_writer<uint8_t>(o).write_bson(j);\n    }\n\n    /*!\n    @copydoc to_bson(const basic_json&, detail::output_adapter<uint8_t>)\n    */\n    static void to_bson(const basic_json& j, detail::output_adapter<char> o)\n    {\n        binary_writer<char>(o).write_bson(j);\n    }\n\n\n    /*!\n    @brief create a JSON value from an input in CBOR format\n\n    Deserializes a given input @a i to a JSON value using the CBOR (Concise\n    Binary Object Representation) serialization format.\n\n    The library maps CBOR types to JSON value types as follows:\n\n    CBOR type              | JSON value type | first byte\n    ---------------------- | --------------- | ----------\n    Integer                | number_unsigned | 0x00..0x17\n    Unsigned integer       | number_unsigned | 0x18\n    Unsigned integer       | number_unsigned | 0x19\n    Unsigned integer       | number_unsigned | 0x1A\n    Unsigned integer       | number_unsigned | 0x1B\n    Negative integer       | number_integer  | 0x20..0x37\n    Negative integer       | number_integer  | 0x38\n    Negative integer       | number_integer  | 0x39\n    Negative integer       | number_integer  | 0x3A\n    Negative integer       | number_integer  | 0x3B\n    Negative integer       | number_integer  | 0x40..0x57\n    UTF-8 string           | string          | 0x60..0x77\n    UTF-8 string           | string          | 0x78\n    UTF-8 string           | string          | 0x79\n    UTF-8 string           | string          | 0x7A\n    UTF-8 string           | string          | 0x7B\n    UTF-8 string           | string          | 0x7F\n    array                  | array           | 0x80..0x97\n    array                  | array           | 0x98\n    array                  | array           | 0x99\n    array                  | array           | 0x9A\n    array                  | array           | 0x9B\n    array                  | array           | 0x9F\n    map                    | object          | 0xA0..0xB7\n    map                    | object          | 0xB8\n    map                    | object          | 0xB9\n    map                    | object          | 0xBA\n    map                    | object          | 0xBB\n    map                    | object          | 0xBF\n    False                  | `false`         | 0xF4\n    True                   | `true`          | 0xF5\n    Null                   | `null`          | 0xF6\n    Half-Precision Float   | number_float    | 0xF9\n    Single-Precision Float | number_float    | 0xFA\n    Double-Precision Float | number_float    | 0xFB\n\n    @warning The mapping is **incomplete** in the sense that not all CBOR\n             types can be converted to a JSON value. The following CBOR types\n             are not supported and will yield parse errors (parse_error.112):\n             - byte strings (0x40..0x5F)\n             - date/time (0xC0..0xC1)\n             - bignum (0xC2..0xC3)\n             - decimal fraction (0xC4)\n             - bigfloat (0xC5)\n             - tagged items (0xC6..0xD4, 0xD8..0xDB)\n             - expected conversions (0xD5..0xD7)\n             - simple values (0xE0..0xF3, 0xF8)\n             - undefined (0xF7)\n\n    @warning CBOR allows map keys of any type, whereas JSON only allows\n             strings as keys in object values. Therefore, CBOR maps with keys\n             other than UTF-8 strings are rejected (parse_error.113).\n\n    @note Any CBOR output created @ref to_cbor can be successfully parsed by\n          @ref from_cbor.\n\n    @param[in] i  an input in CBOR format convertible to an input adapter\n    @param[in] strict  whether to expect the input to be consumed until EOF\n                       (true by default)\n    @param[in] allow_exceptions  whether to throw exceptions in case of a\n    parse error (optional, true by default)\n\n    @return deserialized JSON value\n\n    @throw parse_error.110 if the given input ends prematurely or the end of\n    file was not reached when @a strict was set to true\n    @throw parse_error.112 if unsupported features from CBOR were\n    used in the given input @a v or if the input is not valid CBOR\n    @throw parse_error.113 if a string was expected as map key, but not found\n\n    @complexity Linear in the size of the input @a i.\n\n    @liveexample{The example shows the deserialization of a byte vector in CBOR\n    format to a JSON value.,from_cbor}\n\n    @sa http://cbor.io\n    @sa @ref to_cbor(const basic_json&) for the analogous serialization\n    @sa @ref from_msgpack(detail::input_adapter&&, const bool, const bool) for the\n        related MessagePack format\n    @sa @ref from_ubjson(detail::input_adapter&&, const bool, const bool) for the\n        related UBJSON format\n\n    @since version 2.0.9; parameter @a start_index since 2.1.1; changed to\n           consume input adapters, removed start_index parameter, and added\n           @a strict parameter since 3.0.0; added @a allow_exceptions parameter\n           since 3.2.0\n    */\n    static basic_json from_cbor(detail::input_adapter&& i,\n                                const bool strict = true,\n                                const bool allow_exceptions = true)\n    {\n        basic_json result;\n        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);\n        const bool res = binary_reader(detail::input_adapter(i)).sax_parse(input_format_t::cbor, &sdp, strict);\n        return res ? result : basic_json(value_t::discarded);\n    }\n\n    /*!\n    @copydoc from_cbor(detail::input_adapter&&, const bool, const bool)\n    */\n    template<typename A1, typename A2,\n             detail::enable_if_t<std::is_constructible<detail::input_adapter, A1, A2>::value, int> = 0>\n    static basic_json from_cbor(A1 && a1, A2 && a2,\n                                const bool strict = true,\n                                const bool allow_exceptions = true)\n    {\n        basic_json result;\n        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);\n        const bool res = binary_reader(detail::input_adapter(std::forward<A1>(a1), std::forward<A2>(a2))).sax_parse(input_format_t::cbor, &sdp, strict);\n        return res ? result : basic_json(value_t::discarded);\n    }\n\n    /*!\n    @brief create a JSON value from an input in MessagePack format\n\n    Deserializes a given input @a i to a JSON value using the MessagePack\n    serialization format.\n\n    The library maps MessagePack types to JSON value types as follows:\n\n    MessagePack type | JSON value type | first byte\n    ---------------- | --------------- | ----------\n    positive fixint  | number_unsigned | 0x00..0x7F\n    fixmap           | object          | 0x80..0x8F\n    fixarray         | array           | 0x90..0x9F\n    fixstr           | string          | 0xA0..0xBF\n    nil              | `null`          | 0xC0\n    false            | `false`         | 0xC2\n    true             | `true`          | 0xC3\n    float 32         | number_float    | 0xCA\n    float 64         | number_float    | 0xCB\n    uint 8           | number_unsigned | 0xCC\n    uint 16          | number_unsigned | 0xCD\n    uint 32          | number_unsigned | 0xCE\n    uint 64          | number_unsigned | 0xCF\n    int 8            | number_integer  | 0xD0\n    int 16           | number_integer  | 0xD1\n    int 32           | number_integer  | 0xD2\n    int 64           | number_integer  | 0xD3\n    str 8            | string          | 0xD9\n    str 16           | string          | 0xDA\n    str 32           | string          | 0xDB\n    array 16         | array           | 0xDC\n    array 32         | array           | 0xDD\n    map 16           | object          | 0xDE\n    map 32           | object          | 0xDF\n    negative fixint  | number_integer  | 0xE0-0xFF\n\n    @warning The mapping is **incomplete** in the sense that not all\n             MessagePack types can be converted to a JSON value. The following\n             MessagePack types are not supported and will yield parse errors:\n              - bin 8 - bin 32 (0xC4..0xC6)\n              - ext 8 - ext 32 (0xC7..0xC9)\n              - fixext 1 - fixext 16 (0xD4..0xD8)\n\n    @note Any MessagePack output created @ref to_msgpack can be successfully\n          parsed by @ref from_msgpack.\n\n    @param[in] i  an input in MessagePack format convertible to an input\n                  adapter\n    @param[in] strict  whether to expect the input to be consumed until EOF\n                       (true by default)\n    @param[in] allow_exceptions  whether to throw exceptions in case of a\n    parse error (optional, true by default)\n\n    @return deserialized JSON value\n\n    @throw parse_error.110 if the given input ends prematurely or the end of\n    file was not reached when @a strict was set to true\n    @throw parse_error.112 if unsupported features from MessagePack were\n    used in the given input @a i or if the input is not valid MessagePack\n    @throw parse_error.113 if a string was expected as map key, but not found\n\n    @complexity Linear in the size of the input @a i.\n\n    @liveexample{The example shows the deserialization of a byte vector in\n    MessagePack format to a JSON value.,from_msgpack}\n\n    @sa http://msgpack.org\n    @sa @ref to_msgpack(const basic_json&) for the analogous serialization\n    @sa @ref from_cbor(detail::input_adapter&&, const bool, const bool) for the\n        related CBOR format\n    @sa @ref from_ubjson(detail::input_adapter&&, const bool, const bool) for\n        the related UBJSON format\n    @sa @ref from_bson(detail::input_adapter&&, const bool, const bool) for\n        the related BSON format\n\n    @since version 2.0.9; parameter @a start_index since 2.1.1; changed to\n           consume input adapters, removed start_index parameter, and added\n           @a strict parameter since 3.0.0; added @a allow_exceptions parameter\n           since 3.2.0\n    */\n    static basic_json from_msgpack(detail::input_adapter&& i,\n                                   const bool strict = true,\n                                   const bool allow_exceptions = true)\n    {\n        basic_json result;\n        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);\n        const bool res = binary_reader(detail::input_adapter(i)).sax_parse(input_format_t::msgpack, &sdp, strict);\n        return res ? result : basic_json(value_t::discarded);\n    }\n\n    /*!\n    @copydoc from_msgpack(detail::input_adapter&&, const bool, const bool)\n    */\n    template<typename A1, typename A2,\n             detail::enable_if_t<std::is_constructible<detail::input_adapter, A1, A2>::value, int> = 0>\n    static basic_json from_msgpack(A1 && a1, A2 && a2,\n                                   const bool strict = true,\n                                   const bool allow_exceptions = true)\n    {\n        basic_json result;\n        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);\n        const bool res = binary_reader(detail::input_adapter(std::forward<A1>(a1), std::forward<A2>(a2))).sax_parse(input_format_t::msgpack, &sdp, strict);\n        return res ? result : basic_json(value_t::discarded);\n    }\n\n    /*!\n    @brief create a JSON value from an input in UBJSON format\n\n    Deserializes a given input @a i to a JSON value using the UBJSON (Universal\n    Binary JSON) serialization format.\n\n    The library maps UBJSON types to JSON value types as follows:\n\n    UBJSON type | JSON value type                         | marker\n    ----------- | --------------------------------------- | ------\n    no-op       | *no value, next value is read*          | `N`\n    null        | `null`                                  | `Z`\n    false       | `false`                                 | `F`\n    true        | `true`                                  | `T`\n    float32     | number_float                            | `d`\n    float64     | number_float                            | `D`\n    uint8       | number_unsigned                         | `U`\n    int8        | number_integer                          | `i`\n    int16       | number_integer                          | `I`\n    int32       | number_integer                          | `l`\n    int64       | number_integer                          | `L`\n    string      | string                                  | `S`\n    char        | string                                  | `C`\n    array       | array (optimized values are supported)  | `[`\n    object      | object (optimized values are supported) | `{`\n\n    @note The mapping is **complete** in the sense that any UBJSON value can\n          be converted to a JSON value.\n\n    @param[in] i  an input in UBJSON format convertible to an input adapter\n    @param[in] strict  whether to expect the input to be consumed until EOF\n                       (true by default)\n    @param[in] allow_exceptions  whether to throw exceptions in case of a\n    parse error (optional, true by default)\n\n    @return deserialized JSON value\n\n    @throw parse_error.110 if the given input ends prematurely or the end of\n    file was not reached when @a strict was set to true\n    @throw parse_error.112 if a parse error occurs\n    @throw parse_error.113 if a string could not be parsed successfully\n\n    @complexity Linear in the size of the input @a i.\n\n    @liveexample{The example shows the deserialization of a byte vector in\n    UBJSON format to a JSON value.,from_ubjson}\n\n    @sa http://ubjson.org\n    @sa @ref to_ubjson(const basic_json&, const bool, const bool) for the\n             analogous serialization\n    @sa @ref from_cbor(detail::input_adapter&&, const bool, const bool) for the\n        related CBOR format\n    @sa @ref from_msgpack(detail::input_adapter&&, const bool, const bool) for\n        the related MessagePack format\n    @sa @ref from_bson(detail::input_adapter&&, const bool, const bool) for\n        the related BSON format\n\n    @since version 3.1.0; added @a allow_exceptions parameter since 3.2.0\n    */\n    static basic_json from_ubjson(detail::input_adapter&& i,\n                                  const bool strict = true,\n                                  const bool allow_exceptions = true)\n    {\n        basic_json result;\n        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);\n        const bool res = binary_reader(detail::input_adapter(i)).sax_parse(input_format_t::ubjson, &sdp, strict);\n        return res ? result : basic_json(value_t::discarded);\n    }\n\n    /*!\n    @copydoc from_ubjson(detail::input_adapter&&, const bool, const bool)\n    */\n    template<typename A1, typename A2,\n             detail::enable_if_t<std::is_constructible<detail::input_adapter, A1, A2>::value, int> = 0>\n    static basic_json from_ubjson(A1 && a1, A2 && a2,\n                                  const bool strict = true,\n                                  const bool allow_exceptions = true)\n    {\n        basic_json result;\n        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);\n        const bool res = binary_reader(detail::input_adapter(std::forward<A1>(a1), std::forward<A2>(a2))).sax_parse(input_format_t::ubjson, &sdp, strict);\n        return res ? result : basic_json(value_t::discarded);\n    }\n\n    /*!\n    @brief Create a JSON value from an input in BSON format\n\n    Deserializes a given input @a i to a JSON value using the BSON (Binary JSON)\n    serialization format.\n\n    The library maps BSON record types to JSON value types as follows:\n\n    BSON type       | BSON marker byte | JSON value type\n    --------------- | ---------------- | ---------------------------\n    double          | 0x01             | number_float\n    string          | 0x02             | string\n    document        | 0x03             | object\n    array           | 0x04             | array\n    binary          | 0x05             | still unsupported\n    undefined       | 0x06             | still unsupported\n    ObjectId        | 0x07             | still unsupported\n    boolean         | 0x08             | boolean\n    UTC Date-Time   | 0x09             | still unsupported\n    null            | 0x0A             | null\n    Regular Expr.   | 0x0B             | still unsupported\n    DB Pointer      | 0x0C             | still unsupported\n    JavaScript Code | 0x0D             | still unsupported\n    Symbol          | 0x0E             | still unsupported\n    JavaScript Code | 0x0F             | still unsupported\n    int32           | 0x10             | number_integer\n    Timestamp       | 0x11             | still unsupported\n    128-bit decimal float | 0x13       | still unsupported\n    Max Key         | 0x7F             | still unsupported\n    Min Key         | 0xFF             | still unsupported\n\n    @warning The mapping is **incomplete**. The unsupported mappings\n             are indicated in the table above.\n\n    @param[in] i  an input in BSON format convertible to an input adapter\n    @param[in] strict  whether to expect the input to be consumed until EOF\n                       (true by default)\n    @param[in] allow_exceptions  whether to throw exceptions in case of a\n    parse error (optional, true by default)\n\n    @return deserialized JSON value\n\n    @throw parse_error.114 if an unsupported BSON record type is encountered\n\n    @complexity Linear in the size of the input @a i.\n\n    @liveexample{The example shows the deserialization of a byte vector in\n    BSON format to a JSON value.,from_bson}\n\n    @sa http://bsonspec.org/spec.html\n    @sa @ref to_bson(const basic_json&) for the analogous serialization\n    @sa @ref from_cbor(detail::input_adapter&&, const bool, const bool) for the\n        related CBOR format\n    @sa @ref from_msgpack(detail::input_adapter&&, const bool, const bool) for\n        the related MessagePack format\n    @sa @ref from_ubjson(detail::input_adapter&&, const bool, const bool) for the\n        related UBJSON format\n    */\n    static basic_json from_bson(detail::input_adapter&& i,\n                                const bool strict = true,\n                                const bool allow_exceptions = true)\n    {\n        basic_json result;\n        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);\n        const bool res = binary_reader(detail::input_adapter(i)).sax_parse(input_format_t::bson, &sdp, strict);\n        return res ? result : basic_json(value_t::discarded);\n    }\n\n    /*!\n    @copydoc from_bson(detail::input_adapter&&, const bool, const bool)\n    */\n    template<typename A1, typename A2,\n             detail::enable_if_t<std::is_constructible<detail::input_adapter, A1, A2>::value, int> = 0>\n    static basic_json from_bson(A1 && a1, A2 && a2,\n                                const bool strict = true,\n                                const bool allow_exceptions = true)\n    {\n        basic_json result;\n        detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);\n        const bool res = binary_reader(detail::input_adapter(std::forward<A1>(a1), std::forward<A2>(a2))).sax_parse(input_format_t::bson, &sdp, strict);\n        return res ? result : basic_json(value_t::discarded);\n    }\n\n\n\n    /// @}\n\n    //////////////////////////\n    // JSON Pointer support //\n    //////////////////////////\n\n    /// @name JSON Pointer functions\n    /// @{\n\n    /*!\n    @brief access specified element via JSON Pointer\n\n    Uses a JSON pointer to retrieve a reference to the respective JSON value.\n    No bound checking is performed. Similar to @ref operator[](const typename\n    object_t::key_type&), `null` values are created in arrays and objects if\n    necessary.\n\n    In particular:\n    - If the JSON pointer points to an object key that does not exist, it\n      is created an filled with a `null` value before a reference to it\n      is returned.\n    - If the JSON pointer points to an array index that does not exist, it\n      is created an filled with a `null` value before a reference to it\n      is returned. All indices between the current maximum and the given\n      index are also filled with `null`.\n    - The special value `-` is treated as a synonym for the index past the\n      end.\n\n    @param[in] ptr  a JSON pointer\n\n    @return reference to the element pointed to by @a ptr\n\n    @complexity Constant.\n\n    @throw parse_error.106   if an array index begins with '0'\n    @throw parse_error.109   if an array index was not a number\n    @throw out_of_range.404  if the JSON pointer can not be resolved\n\n    @liveexample{The behavior is shown in the example.,operatorjson_pointer}\n\n    @since version 2.0.0\n    */\n    reference operator[](const json_pointer& ptr)\n    {\n        return ptr.get_unchecked(this);\n    }\n\n    /*!\n    @brief access specified element via JSON Pointer\n\n    Uses a JSON pointer to retrieve a reference to the respective JSON value.\n    No bound checking is performed. The function does not change the JSON\n    value; no `null` values are created. In particular, the the special value\n    `-` yields an exception.\n\n    @param[in] ptr  JSON pointer to the desired element\n\n    @return const reference to the element pointed to by @a ptr\n\n    @complexity Constant.\n\n    @throw parse_error.106   if an array index begins with '0'\n    @throw parse_error.109   if an array index was not a number\n    @throw out_of_range.402  if the array index '-' is used\n    @throw out_of_range.404  if the JSON pointer can not be resolved\n\n    @liveexample{The behavior is shown in the example.,operatorjson_pointer_const}\n\n    @since version 2.0.0\n    */\n    const_reference operator[](const json_pointer& ptr) const\n    {\n        return ptr.get_unchecked(this);\n    }\n\n    /*!\n    @brief access specified element via JSON Pointer\n\n    Returns a reference to the element at with specified JSON pointer @a ptr,\n    with bounds checking.\n\n    @param[in] ptr  JSON pointer to the desired element\n\n    @return reference to the element pointed to by @a ptr\n\n    @throw parse_error.106 if an array index in the passed JSON pointer @a ptr\n    begins with '0'. See example below.\n\n    @throw parse_error.109 if an array index in the passed JSON pointer @a ptr\n    is not a number. See example below.\n\n    @throw out_of_range.401 if an array index in the passed JSON pointer @a ptr\n    is out of range. See example below.\n\n    @throw out_of_range.402 if the array index '-' is used in the passed JSON\n    pointer @a ptr. As `at` provides checked access (and no elements are\n    implicitly inserted), the index '-' is always invalid. See example below.\n\n    @throw out_of_range.403 if the JSON pointer describes a key of an object\n    which cannot be found. See example below.\n\n    @throw out_of_range.404 if the JSON pointer @a ptr can not be resolved.\n    See example below.\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes in the JSON value.\n\n    @complexity Constant.\n\n    @since version 2.0.0\n\n    @liveexample{The behavior is shown in the example.,at_json_pointer}\n    */\n    reference at(const json_pointer& ptr)\n    {\n        return ptr.get_checked(this);\n    }\n\n    /*!\n    @brief access specified element via JSON Pointer\n\n    Returns a const reference to the element at with specified JSON pointer @a\n    ptr, with bounds checking.\n\n    @param[in] ptr  JSON pointer to the desired element\n\n    @return reference to the element pointed to by @a ptr\n\n    @throw parse_error.106 if an array index in the passed JSON pointer @a ptr\n    begins with '0'. See example below.\n\n    @throw parse_error.109 if an array index in the passed JSON pointer @a ptr\n    is not a number. See example below.\n\n    @throw out_of_range.401 if an array index in the passed JSON pointer @a ptr\n    is out of range. See example below.\n\n    @throw out_of_range.402 if the array index '-' is used in the passed JSON\n    pointer @a ptr. As `at` provides checked access (and no elements are\n    implicitly inserted), the index '-' is always invalid. See example below.\n\n    @throw out_of_range.403 if the JSON pointer describes a key of an object\n    which cannot be found. See example below.\n\n    @throw out_of_range.404 if the JSON pointer @a ptr can not be resolved.\n    See example below.\n\n    @exceptionsafety Strong guarantee: if an exception is thrown, there are no\n    changes in the JSON value.\n\n    @complexity Constant.\n\n    @since version 2.0.0\n\n    @liveexample{The behavior is shown in the example.,at_json_pointer_const}\n    */\n    const_reference at(const json_pointer& ptr) const\n    {\n        return ptr.get_checked(this);\n    }\n\n    /*!\n    @brief return flattened JSON value\n\n    The function creates a JSON object whose keys are JSON pointers (see [RFC\n    6901](https://tools.ietf.org/html/rfc6901)) and whose values are all\n    primitive. The original JSON value can be restored using the @ref\n    unflatten() function.\n\n    @return an object that maps JSON pointers to primitive values\n\n    @note Empty objects and arrays are flattened to `null` and will not be\n          reconstructed correctly by the @ref unflatten() function.\n\n    @complexity Linear in the size the JSON value.\n\n    @liveexample{The following code shows how a JSON object is flattened to an\n    object whose keys consist of JSON pointers.,flatten}\n\n    @sa @ref unflatten() for the reverse function\n\n    @since version 2.0.0\n    */\n    basic_json flatten() const\n    {\n        basic_json result(value_t::object);\n        json_pointer::flatten(\"\", *this, result);\n        return result;\n    }\n\n    /*!\n    @brief unflatten a previously flattened JSON value\n\n    The function restores the arbitrary nesting of a JSON value that has been\n    flattened before using the @ref flatten() function. The JSON value must\n    meet certain constraints:\n    1. The value must be an object.\n    2. The keys must be JSON pointers (see\n       [RFC 6901](https://tools.ietf.org/html/rfc6901))\n    3. The mapped values must be primitive JSON types.\n\n    @return the original JSON from a flattened version\n\n    @note Empty objects and arrays are flattened by @ref flatten() to `null`\n          values and can not unflattened to their original type. Apart from\n          this example, for a JSON value `j`, the following is always true:\n          `j == j.flatten().unflatten()`.\n\n    @complexity Linear in the size the JSON value.\n\n    @throw type_error.314  if value is not an object\n    @throw type_error.315  if object values are not primitive\n\n    @liveexample{The following code shows how a flattened JSON object is\n    unflattened into the original nested JSON object.,unflatten}\n\n    @sa @ref flatten() for the reverse function\n\n    @since version 2.0.0\n    */\n    basic_json unflatten() const\n    {\n        return json_pointer::unflatten(*this);\n    }\n\n    /// @}\n\n    //////////////////////////\n    // JSON Patch functions //\n    //////////////////////////\n\n    /// @name JSON Patch functions\n    /// @{\n\n    /*!\n    @brief applies a JSON patch\n\n    [JSON Patch](http://jsonpatch.com) defines a JSON document structure for\n    expressing a sequence of operations to apply to a JSON) document. With\n    this function, a JSON Patch is applied to the current JSON value by\n    executing all operations from the patch.\n\n    @param[in] json_patch  JSON patch document\n    @return patched document\n\n    @note The application of a patch is atomic: Either all operations succeed\n          and the patched document is returned or an exception is thrown. In\n          any case, the original value is not changed: the patch is applied\n          to a copy of the value.\n\n    @throw parse_error.104 if the JSON patch does not consist of an array of\n    objects\n\n    @throw parse_error.105 if the JSON patch is malformed (e.g., mandatory\n    attributes are missing); example: `\"operation add must have member path\"`\n\n    @throw out_of_range.401 if an array index is out of range.\n\n    @throw out_of_range.403 if a JSON pointer inside the patch could not be\n    resolved successfully in the current JSON value; example: `\"key baz not\n    found\"`\n\n    @throw out_of_range.405 if JSON pointer has no parent (\"add\", \"remove\",\n    \"move\")\n\n    @throw other_error.501 if \"test\" operation was unsuccessful\n\n    @complexity Linear in the size of the JSON value and the length of the\n    JSON patch. As usually only a fraction of the JSON value is affected by\n    the patch, the complexity can usually be neglected.\n\n    @liveexample{The following code shows how a JSON patch is applied to a\n    value.,patch}\n\n    @sa @ref diff -- create a JSON patch by comparing two JSON values\n\n    @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902)\n    @sa [RFC 6901 (JSON Pointer)](https://tools.ietf.org/html/rfc6901)\n\n    @since version 2.0.0\n    */\n    basic_json patch(const basic_json& json_patch) const\n    {\n        // make a working copy to apply the patch to\n        basic_json result = *this;\n\n        // the valid JSON Patch operations\n        enum class patch_operations {add, remove, replace, move, copy, test, invalid};\n\n        const auto get_op = [](const std::string & op)\n        {\n            if (op == \"add\")\n            {\n                return patch_operations::add;\n            }\n            if (op == \"remove\")\n            {\n                return patch_operations::remove;\n            }\n            if (op == \"replace\")\n            {\n                return patch_operations::replace;\n            }\n            if (op == \"move\")\n            {\n                return patch_operations::move;\n            }\n            if (op == \"copy\")\n            {\n                return patch_operations::copy;\n            }\n            if (op == \"test\")\n            {\n                return patch_operations::test;\n            }\n\n            return patch_operations::invalid;\n        };\n\n        // wrapper for \"add\" operation; add value at ptr\n        const auto operation_add = [&result](json_pointer & ptr, basic_json val)\n        {\n            // adding to the root of the target document means replacing it\n            if (ptr.is_root())\n            {\n                result = val;\n            }\n            else\n            {\n                // make sure the top element of the pointer exists\n                json_pointer top_pointer = ptr.top();\n                if (top_pointer != ptr)\n                {\n                    result.at(top_pointer);\n                }\n\n                // get reference to parent of JSON pointer ptr\n                const auto last_path = ptr.pop_back();\n                basic_json& parent = result[ptr];\n\n                switch (parent.m_type)\n                {\n                    case value_t::null:\n                    case value_t::object:\n                    {\n                        // use operator[] to add value\n                        parent[last_path] = val;\n                        break;\n                    }\n\n                    case value_t::array:\n                    {\n                        if (last_path == \"-\")\n                        {\n                            // special case: append to back\n                            parent.push_back(val);\n                        }\n                        else\n                        {\n                            const auto idx = json_pointer::array_index(last_path);\n                            if (JSON_UNLIKELY(static_cast<size_type>(idx) > parent.size()))\n                            {\n                                // avoid undefined behavior\n                                JSON_THROW(out_of_range::create(401, \"array index \" + std::to_string(idx) + \" is out of range\"));\n                            }\n\n                            // default case: insert add offset\n                            parent.insert(parent.begin() + static_cast<difference_type>(idx), val);\n                        }\n                        break;\n                    }\n\n                    // LCOV_EXCL_START\n                    default:\n                    {\n                        // if there exists a parent it cannot be primitive\n                        assert(false);\n                    }\n                        // LCOV_EXCL_STOP\n                }\n            }\n        };\n\n        // wrapper for \"remove\" operation; remove value at ptr\n        const auto operation_remove = [&result](json_pointer & ptr)\n        {\n            // get reference to parent of JSON pointer ptr\n            const auto last_path = ptr.pop_back();\n            basic_json& parent = result.at(ptr);\n\n            // remove child\n            if (parent.is_object())\n            {\n                // perform range check\n                auto it = parent.find(last_path);\n                if (JSON_LIKELY(it != parent.end()))\n                {\n                    parent.erase(it);\n                }\n                else\n                {\n                    JSON_THROW(out_of_range::create(403, \"key '\" + last_path + \"' not found\"));\n                }\n            }\n            else if (parent.is_array())\n            {\n                // note erase performs range check\n                parent.erase(static_cast<size_type>(json_pointer::array_index(last_path)));\n            }\n        };\n\n        // type check: top level value must be an array\n        if (JSON_UNLIKELY(not json_patch.is_array()))\n        {\n            JSON_THROW(parse_error::create(104, 0, \"JSON patch must be an array of objects\"));\n        }\n\n        // iterate and apply the operations\n        for (const auto& val : json_patch)\n        {\n            // wrapper to get a value for an operation\n            const auto get_value = [&val](const std::string & op,\n                                          const std::string & member,\n                                          bool string_type) -> basic_json &\n            {\n                // find value\n                auto it = val.m_value.object->find(member);\n\n                // context-sensitive error message\n                const auto error_msg = (op == \"op\") ? \"operation\" : \"operation '\" + op + \"'\";\n\n                // check if desired value is present\n                if (JSON_UNLIKELY(it == val.m_value.object->end()))\n                {\n                    JSON_THROW(parse_error::create(105, 0, error_msg + \" must have member '\" + member + \"'\"));\n                }\n\n                // check if result is of type string\n                if (JSON_UNLIKELY(string_type and not it->second.is_string()))\n                {\n                    JSON_THROW(parse_error::create(105, 0, error_msg + \" must have string member '\" + member + \"'\"));\n                }\n\n                // no error: return value\n                return it->second;\n            };\n\n            // type check: every element of the array must be an object\n            if (JSON_UNLIKELY(not val.is_object()))\n            {\n                JSON_THROW(parse_error::create(104, 0, \"JSON patch must be an array of objects\"));\n            }\n\n            // collect mandatory members\n            const std::string op = get_value(\"op\", \"op\", true);\n            const std::string path = get_value(op, \"path\", true);\n            json_pointer ptr(path);\n\n            switch (get_op(op))\n            {\n                case patch_operations::add:\n                {\n                    operation_add(ptr, get_value(\"add\", \"value\", false));\n                    break;\n                }\n\n                case patch_operations::remove:\n                {\n                    operation_remove(ptr);\n                    break;\n                }\n\n                case patch_operations::replace:\n                {\n                    // the \"path\" location must exist - use at()\n                    result.at(ptr) = get_value(\"replace\", \"value\", false);\n                    break;\n                }\n\n                case patch_operations::move:\n                {\n                    const std::string from_path = get_value(\"move\", \"from\", true);\n                    json_pointer from_ptr(from_path);\n\n                    // the \"from\" location must exist - use at()\n                    basic_json v = result.at(from_ptr);\n\n                    // The move operation is functionally identical to a\n                    // \"remove\" operation on the \"from\" location, followed\n                    // immediately by an \"add\" operation at the target\n                    // location with the value that was just removed.\n                    operation_remove(from_ptr);\n                    operation_add(ptr, v);\n                    break;\n                }\n\n                case patch_operations::copy:\n                {\n                    const std::string from_path = get_value(\"copy\", \"from\", true);\n                    const json_pointer from_ptr(from_path);\n\n                    // the \"from\" location must exist - use at()\n                    basic_json v = result.at(from_ptr);\n\n                    // The copy is functionally identical to an \"add\"\n                    // operation at the target location using the value\n                    // specified in the \"from\" member.\n                    operation_add(ptr, v);\n                    break;\n                }\n\n                case patch_operations::test:\n                {\n                    bool success = false;\n                    JSON_TRY\n                    {\n                        // check if \"value\" matches the one at \"path\"\n                        // the \"path\" location must exist - use at()\n                        success = (result.at(ptr) == get_value(\"test\", \"value\", false));\n                    }\n                    JSON_INTERNAL_CATCH (out_of_range&)\n                    {\n                        // ignore out of range errors: success remains false\n                    }\n\n                    // throw an exception if test fails\n                    if (JSON_UNLIKELY(not success))\n                    {\n                        JSON_THROW(other_error::create(501, \"unsuccessful: \" + val.dump()));\n                    }\n\n                    break;\n                }\n\n                case patch_operations::invalid:\n                {\n                    // op must be \"add\", \"remove\", \"replace\", \"move\", \"copy\", or\n                    // \"test\"\n                    JSON_THROW(parse_error::create(105, 0, \"operation value '\" + op + \"' is invalid\"));\n                }\n            }\n        }\n\n        return result;\n    }\n\n    /*!\n    @brief creates a diff as a JSON patch\n\n    Creates a [JSON Patch](http://jsonpatch.com) so that value @a source can\n    be changed into the value @a target by calling @ref patch function.\n\n    @invariant For two JSON values @a source and @a target, the following code\n    yields always `true`:\n    @code {.cpp}\n    source.patch(diff(source, target)) == target;\n    @endcode\n\n    @note Currently, only `remove`, `add`, and `replace` operations are\n          generated.\n\n    @param[in] source  JSON value to compare from\n    @param[in] target  JSON value to compare against\n    @param[in] path    helper value to create JSON pointers\n\n    @return a JSON patch to convert the @a source to @a target\n\n    @complexity Linear in the lengths of @a source and @a target.\n\n    @liveexample{The following code shows how a JSON patch is created as a\n    diff for two JSON values.,diff}\n\n    @sa @ref patch -- apply a JSON patch\n    @sa @ref merge_patch -- apply a JSON Merge Patch\n\n    @sa [RFC 6902 (JSON Patch)](https://tools.ietf.org/html/rfc6902)\n\n    @since version 2.0.0\n    */\n    static basic_json diff(const basic_json& source, const basic_json& target,\n                           const std::string& path = \"\")\n    {\n        // the patch\n        basic_json result(value_t::array);\n\n        // if the values are the same, return empty patch\n        if (source == target)\n        {\n            return result;\n        }\n\n        if (source.type() != target.type())\n        {\n            // different types: replace value\n            result.push_back(\n            {\n                {\"op\", \"replace\"}, {\"path\", path}, {\"value\", target}\n            });\n        }\n        else\n        {\n            switch (source.type())\n            {\n                case value_t::array:\n                {\n                    // first pass: traverse common elements\n                    std::size_t i = 0;\n                    while (i < source.size() and i < target.size())\n                    {\n                        // recursive call to compare array values at index i\n                        auto temp_diff = diff(source[i], target[i], path + \"/\" + std::to_string(i));\n                        result.insert(result.end(), temp_diff.begin(), temp_diff.end());\n                        ++i;\n                    }\n\n                    // i now reached the end of at least one array\n                    // in a second pass, traverse the remaining elements\n\n                    // remove my remaining elements\n                    const auto end_index = static_cast<difference_type>(result.size());\n                    while (i < source.size())\n                    {\n                        // add operations in reverse order to avoid invalid\n                        // indices\n                        result.insert(result.begin() + end_index, object(\n                        {\n                            {\"op\", \"remove\"},\n                            {\"path\", path + \"/\" + std::to_string(i)}\n                        }));\n                        ++i;\n                    }\n\n                    // add other remaining elements\n                    while (i < target.size())\n                    {\n                        result.push_back(\n                        {\n                            {\"op\", \"add\"},\n                            {\"path\", path + \"/\" + std::to_string(i)},\n                            {\"value\", target[i]}\n                        });\n                        ++i;\n                    }\n\n                    break;\n                }\n\n                case value_t::object:\n                {\n                    // first pass: traverse this object's elements\n                    for (auto it = source.cbegin(); it != source.cend(); ++it)\n                    {\n                        // escape the key name to be used in a JSON patch\n                        const auto key = json_pointer::escape(it.key());\n\n                        if (target.find(it.key()) != target.end())\n                        {\n                            // recursive call to compare object values at key it\n                            auto temp_diff = diff(it.value(), target[it.key()], path + \"/\" + key);\n                            result.insert(result.end(), temp_diff.begin(), temp_diff.end());\n                        }\n                        else\n                        {\n                            // found a key that is not in o -> remove it\n                            result.push_back(object(\n                            {\n                                {\"op\", \"remove\"}, {\"path\", path + \"/\" + key}\n                            }));\n                        }\n                    }\n\n                    // second pass: traverse other object's elements\n                    for (auto it = target.cbegin(); it != target.cend(); ++it)\n                    {\n                        if (source.find(it.key()) == source.end())\n                        {\n                            // found a key that is not in this -> add it\n                            const auto key = json_pointer::escape(it.key());\n                            result.push_back(\n                            {\n                                {\"op\", \"add\"}, {\"path\", path + \"/\" + key},\n                                {\"value\", it.value()}\n                            });\n                        }\n                    }\n\n                    break;\n                }\n\n                default:\n                {\n                    // both primitive type: replace value\n                    result.push_back(\n                    {\n                        {\"op\", \"replace\"}, {\"path\", path}, {\"value\", target}\n                    });\n                    break;\n                }\n            }\n        }\n\n        return result;\n    }\n\n    /// @}\n\n    ////////////////////////////////\n    // JSON Merge Patch functions //\n    ////////////////////////////////\n\n    /// @name JSON Merge Patch functions\n    /// @{\n\n    /*!\n    @brief applies a JSON Merge Patch\n\n    The merge patch format is primarily intended for use with the HTTP PATCH\n    method as a means of describing a set of modifications to a target\n    resource's content. This function applies a merge patch to the current\n    JSON value.\n\n    The function implements the following algorithm from Section 2 of\n    [RFC 7396 (JSON Merge Patch)](https://tools.ietf.org/html/rfc7396):\n\n    ```\n    define MergePatch(Target, Patch):\n      if Patch is an Object:\n        if Target is not an Object:\n          Target = {} // Ignore the contents and set it to an empty Object\n        for each Name/Value pair in Patch:\n          if Value is null:\n            if Name exists in Target:\n              remove the Name/Value pair from Target\n          else:\n            Target[Name] = MergePatch(Target[Name], Value)\n        return Target\n      else:\n        return Patch\n    ```\n\n    Thereby, `Target` is the current object; that is, the patch is applied to\n    the current value.\n\n    @param[in] apply_patch  the patch to apply\n\n    @complexity Linear in the lengths of @a patch.\n\n    @liveexample{The following code shows how a JSON Merge Patch is applied to\n    a JSON document.,merge_patch}\n\n    @sa @ref patch -- apply a JSON patch\n    @sa [RFC 7396 (JSON Merge Patch)](https://tools.ietf.org/html/rfc7396)\n\n    @since version 3.0.0\n    */\n    void merge_patch(const basic_json& apply_patch)\n    {\n        if (apply_patch.is_object())\n        {\n            if (not is_object())\n            {\n                *this = object();\n            }\n            for (auto it = apply_patch.begin(); it != apply_patch.end(); ++it)\n            {\n                if (it.value().is_null())\n                {\n                    erase(it.key());\n                }\n                else\n                {\n                    operator[](it.key()).merge_patch(it.value());\n                }\n            }\n        }\n        else\n        {\n            *this = apply_patch;\n        }\n    }\n\n    /// @}\n};\n} // namespace nlohmann\n\n///////////////////////\n// nonmember support //\n///////////////////////\n\n// specialization of std::swap, and std::hash\nnamespace std\n{\n\n/// hash value for JSON objects\ntemplate<>\nstruct hash<nlohmann::json>\n{\n    /*!\n    @brief return a hash value for a JSON object\n\n    @since version 1.0.0\n    */\n    std::size_t operator()(const nlohmann::json& j) const\n    {\n        // a naive hashing via the string representation\n        const auto& h = hash<nlohmann::json::string_t>();\n        return h(j.dump());\n    }\n};\n\n/// specialization for std::less<value_t>\n/// @note: do not remove the space after '<',\n///        see https://github.com/nlohmann/json/pull/679\ntemplate<>\nstruct less< ::nlohmann::detail::value_t>\n{\n    /*!\n    @brief compare two value_t enum values\n    @since version 3.0.0\n    */\n    bool operator()(nlohmann::detail::value_t lhs,\n                    nlohmann::detail::value_t rhs) const noexcept\n    {\n        return nlohmann::detail::operator<(lhs, rhs);\n    }\n};\n\n/*!\n@brief exchanges the values of two JSON objects\n\n@since version 1.0.0\n*/\ntemplate<>\ninline void swap<nlohmann::json>(nlohmann::json& j1, nlohmann::json& j2) noexcept(\n    is_nothrow_move_constructible<nlohmann::json>::value and\n    is_nothrow_move_assignable<nlohmann::json>::value\n)\n{\n    j1.swap(j2);\n}\n\n} // namespace std\n\n/*!\n@brief user-defined string literal for JSON values\n\nThis operator implements a user-defined string literal for JSON objects. It\ncan be used by adding `\"_json\"` to a string literal and returns a JSON object\nif no parse error occurred.\n\n@param[in] s  a string representation of a JSON object\n@param[in] n  the length of string @a s\n@return a JSON object\n\n@since version 1.0.0\n*/\ninline nlohmann::json operator \"\" _json(const char* s, std::size_t n)\n{\n    return nlohmann::json::parse(s, s + n);\n}\n\n/*!\n@brief user-defined string literal for JSON pointer\n\nThis operator implements a user-defined string literal for JSON Pointers. It\ncan be used by adding `\"_json_pointer\"` to a string literal and returns a JSON pointer\nobject if no parse error occurred.\n\n@param[in] s  a string representation of a JSON Pointer\n@param[in] n  the length of string @a s\n@return a JSON pointer object\n\n@since version 2.0.0\n*/\ninline nlohmann::json::json_pointer operator \"\" _json_pointer(const char* s, std::size_t n)\n{\n    return nlohmann::json::json_pointer(std::string(s, n));\n}\n\n// #include <nlohmann/detail/macro_unscope.hpp>\n\n\n// restore GCC/clang diagnostic settings\n#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)\n    #pragma GCC diagnostic pop\n#endif\n#if defined(__clang__)\n    #pragma GCC diagnostic pop\n#endif\n\n// clean up\n#undef JSON_INTERNAL_CATCH\n#undef JSON_CATCH\n#undef JSON_THROW\n#undef JSON_TRY\n#undef JSON_LIKELY\n#undef JSON_UNLIKELY\n#undef JSON_DEPRECATED\n#undef JSON_HAS_CPP_14\n#undef JSON_HAS_CPP_17\n#undef NLOHMANN_BASIC_JSON_TPL_DECLARATION\n#undef NLOHMANN_BASIC_JSON_TPL\n\n\n#endif\n"
  },
  {
    "path": "spdlog/async_logger.h",
    "content": "//\n// Copyright(c) 2015 Gabi Melman.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n//\n\n#pragma once\n\n// Very fast asynchronous logger (millions of logs per second on an average desktop)\n// Uses pre allocated lockfree queue for maximum throughput even under large number of threads.\n// Creates a single back thread to pop messages from the queue and log them.\n//\n// Upon each log write the logger:\n//    1. Checks if its log level is enough to log the message\n//    2. Push a new copy of the message to a queue (or block the caller until space is available in the queue)\n//    3. will throw spdlog_ex upon log exceptions\n// Upon destruction, logs all remaining messages in the queue before destructing..\n\n#include \"common.h\"\n#include \"logger.h\"\n\n#include <chrono>\n#include <functional>\n#include <memory>\n#include <string>\n\nnamespace spdlog {\n\nnamespace details {\nclass async_log_helper;\n}\n\nclass async_logger SPDLOG_FINAL : public logger\n{\npublic:\n    template<class It>\n    async_logger(const std::string &logger_name, const It &begin, const It &end, size_t queue_size,\n        const async_overflow_policy overflow_policy = async_overflow_policy::block_retry,\n        const std::function<void()> &worker_warmup_cb = nullptr,\n        const std::chrono::milliseconds &flush_interval_ms = std::chrono::milliseconds::zero(),\n        const std::function<void()> &worker_teardown_cb = nullptr);\n\n    async_logger(const std::string &logger_name, sinks_init_list sinks, size_t queue_size,\n        const async_overflow_policy overflow_policy = async_overflow_policy::block_retry,\n        const std::function<void()> &worker_warmup_cb = nullptr,\n        const std::chrono::milliseconds &flush_interval_ms = std::chrono::milliseconds::zero(),\n        const std::function<void()> &worker_teardown_cb = nullptr);\n\n    async_logger(const std::string &logger_name, sink_ptr single_sink, size_t queue_size,\n        const async_overflow_policy overflow_policy = async_overflow_policy::block_retry,\n        const std::function<void()> &worker_warmup_cb = nullptr,\n        const std::chrono::milliseconds &flush_interval_ms = std::chrono::milliseconds::zero(),\n        const std::function<void()> &worker_teardown_cb = nullptr);\n\n    // Wait for the queue to be empty, and flush synchronously\n    // Warning: this can potentially last forever as we wait it to complete\n    void flush() override;\n\n    // Error handler\n    void set_error_handler(log_err_handler) override;\n    log_err_handler error_handler() override;\n\nprotected:\n    void _sink_it(details::log_msg &msg) override;\n    void _set_formatter(spdlog::formatter_ptr msg_formatter) override;\n    void _set_pattern(const std::string &pattern, pattern_time_type pattern_time) override;\n\nprivate:\n    std::unique_ptr<details::async_log_helper> _async_log_helper;\n};\n} // namespace spdlog\n\n#include \"details/async_logger_impl.h\"\n"
  },
  {
    "path": "spdlog/common.h",
    "content": "//\n// Copyright(c) 2015 Gabi Melman.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n//\n\n#pragma once\n\n#define SPDLOG_VERSION \"0.17.0\"\n\n#include \"tweakme.h\"\n\n#include <atomic>\n#include <chrono>\n#include <exception>\n#include <functional>\n#include <initializer_list>\n#include <memory>\n#include <string>\n#include <unordered_map>\n\n#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)\n#include <codecvt>\n#include <locale>\n#endif\n\n#include \"details/null_mutex.h\"\n\n// visual studio upto 2013 does not support noexcept nor constexpr\n#if defined(_MSC_VER) && (_MSC_VER < 1900)\n#define SPDLOG_NOEXCEPT throw()\n#define SPDLOG_CONSTEXPR\n#else\n#define SPDLOG_NOEXCEPT noexcept\n#define SPDLOG_CONSTEXPR constexpr\n#endif\n\n// final keyword support. On by default. See tweakme.h\n#if defined(SPDLOG_NO_FINAL)\n#define SPDLOG_FINAL\n#else\n#define SPDLOG_FINAL final\n#endif\n\n#if defined(__GNUC__) || defined(__clang__)\n#define SPDLOG_DEPRECATED __attribute__((deprecated))\n#elif defined(_MSC_VER)\n#define SPDLOG_DEPRECATED __declspec(deprecated)\n#else\n#define SPDLOG_DEPRECATED\n#endif\n\n#include \"fmt/fmt.h\"\n\nnamespace spdlog {\n\nclass formatter;\n\nnamespace sinks {\nclass sink;\n}\n\nusing log_clock = std::chrono::system_clock;\nusing sink_ptr = std::shared_ptr<sinks::sink>;\nusing sinks_init_list = std::initializer_list<sink_ptr>;\nusing formatter_ptr = std::shared_ptr<spdlog::formatter>;\n#if defined(SPDLOG_NO_ATOMIC_LEVELS)\nusing level_t = details::null_atomic_int;\n#else\nusing level_t = std::atomic<int>;\n#endif\n\nusing log_err_handler = std::function<void(const std::string &err_msg)>;\n\n// Log level enum\nnamespace level {\nenum level_enum\n{\n    trace = 0,\n    debug = 1,\n    info = 2,\n    warn = 3,\n    err = 4,\n    critical = 5,\n    off = 6\n};\n\n#if !defined(SPDLOG_LEVEL_NAMES)\n#define SPDLOG_LEVEL_NAMES                                                                                                                 \\\n    {                                                                                                                                      \\\n        \"trace\", \"debug\", \"info\", \"warning\", \"error\", \"critical\", \"off\"                                                                    \\\n    }\n#endif\nstatic const char *level_names[] SPDLOG_LEVEL_NAMES;\n\nstatic const char *short_level_names[]{\"T\", \"D\", \"I\", \"W\", \"E\", \"C\", \"O\"};\n\ninline const char *to_str(spdlog::level::level_enum l)\n{\n    return level_names[l];\n}\n\ninline const char *to_short_str(spdlog::level::level_enum l)\n{\n    return short_level_names[l];\n}\ninline spdlog::level::level_enum from_str(const std::string &name)\n{\n    static std::unordered_map<std::string, level_enum> name_to_level = // map string->level\n        {{level_names[0], level::trace},                               // trace\n            {level_names[1], level::debug},                            // debug\n            {level_names[2], level::info},                             // info\n            {level_names[3], level::warn},                             // warn\n            {level_names[4], level::err},                              // err\n            {level_names[5], level::critical},                         // critical\n            {level_names[6], level::off}};                             // off\n\n    auto lvl_it = name_to_level.find(name);\n    return lvl_it != name_to_level.end() ? lvl_it->second : level::off;\n}\n\nusing level_hasher = std::hash<int>;\n} // namespace level\n\n//\n// Async overflow policy - block by default.\n//\nenum class async_overflow_policy\n{\n    block_retry,    // Block / yield / sleep until message can be enqueued\n    discard_log_msg // Discard the message it enqueue fails\n};\n\n//\n// Pattern time - specific time getting to use for pattern_formatter.\n// local time by default\n//\nenum class pattern_time_type\n{\n    local, // log localtime\n    utc    // log utc\n};\n\n//\n// Log exception\n//\nclass spdlog_ex : public std::exception\n{\npublic:\n    explicit spdlog_ex(std::string msg)\n        : _msg(std::move(msg))\n    {\n    }\n\n    spdlog_ex(const std::string &msg, int last_errno)\n    {\n        fmt::MemoryWriter writer;\n        fmt::format_system_error(writer, last_errno, msg);\n        _msg = writer.str();\n    }\n\n    const char *what() const SPDLOG_NOEXCEPT override\n    {\n        return _msg.c_str();\n    }\n\nprivate:\n    std::string _msg;\n};\n\n//\n// wchar support for windows file names (SPDLOG_WCHAR_FILENAMES must be defined)\n//\n#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)\nusing filename_t = std::wstring;\n#else\nusing filename_t = std::string;\n#endif\n\n#define SPDLOG_CATCH_AND_HANDLE                                                                                                            \\\n    catch (const std::exception &ex)                                                                                                       \\\n    {                                                                                                                                      \\\n        _err_handler(ex.what());                                                                                                           \\\n    }                                                                                                                                      \\\n    catch (...)                                                                                                                            \\\n    {                                                                                                                                      \\\n        _err_handler(\"Unknown exeption in logger\");                                                                                        \\\n    }\n} // namespace spdlog\n"
  },
  {
    "path": "spdlog/contrib/README.md",
    "content": "Please put here your contribs. Popular contribs will be moved to main tree after stablization\n"
  },
  {
    "path": "spdlog/contrib/sinks/.gitignore",
    "content": "\n"
  },
  {
    "path": "spdlog/contrib/sinks/step_file_sink.h",
    "content": "#pragma once\n\n#include \"../../details/file_helper.h\"\n#include \"../../details/null_mutex.h\"\n#include \"../../fmt/fmt.h\"\n#include \"../../sinks/base_sink.h\"\n\n#include <algorithm>\n#include <cerrno>\n#include <chrono>\n#include <cstdio>\n#include <ctime>\n#include <mutex>\n#include <string>\n\n// Example for spdlog.h\n//\n// Create a file logger which creates new files with a specified time step and fixed file size:\n//\n// std::shared_ptr<logger> step_logger_mt(const std::string &logger_name, const filename_t &filename, unsigned seconds = 60, const\n// filename_t &tmp_ext = \".tmp\", unsigned max_file_size = std::numeric_limits<unsigned>::max(), bool delete_empty_files = true, const\n// filename_t &file_header = \"\"); std::shared_ptr<logger> step_logger_st(const std::string &logger_name, const filename_t &filename,\n// unsigned seconds = 60, const filename_t &tmp_ext = \".tmp\", unsigned max_file_size = std::numeric_limits<unsigned>::max());\n\n// Example for spdlog_impl.h\n// Create a file logger that creates new files with a specified increment\n// inline std::shared_ptr<spdlog::logger> spdlog::step_logger_mt(\n//     const std::string &logger_name, const filename_t &filename_fmt, unsigned seconds, const filename_t &tmp_ext, unsigned max_file_size,\n//     bool delete_empty_files, const filename_t &file_header)\n// {\n//     return create<spdlog::sinks::step_file_sink_mt>(logger_name, filename_fmt, seconds, tmp_ext, max_file_size, delete_empty_files,\n//     file_header);\n// }\n\n// inline std::shared_ptr<spdlog::logger> spdlog::step_logger_st(\n//     const std::string &logger_name, const filename_t &filename_fmt, unsigned seconds, const filename_t &tmp_ext, unsigned max_file_size,\n//     bool delete_empty_files, const filename_t &file_header)\n// {\n//     return create<spdlog::sinks::step_file_sink_st>(logger_name, filename_fmt, seconds, tmp_ext, max_file_size, delete_empty_files,\n//     file_header);\n// }\n\nnamespace spdlog {\nnamespace sinks {\n\n/*\n * Default generator of step log file names.\n */\nstruct default_step_file_name_calculator\n{\n    // Create filename for the form filename_YYYY-MM-DD_hh-mm-ss.ext\n    static std::tuple<filename_t, filename_t> calc_filename(const filename_t &filename, const filename_t &tmp_ext)\n    {\n        std::tm tm = spdlog::details::os::localtime();\n        filename_t basename, ext;\n        std::tie(basename, ext) = details::file_helper::split_by_extenstion(filename);\n        std::conditional<std::is_same<filename_t::value_type, char>::value, fmt::MemoryWriter, fmt::WMemoryWriter>::type w;\n        w.write(SPDLOG_FILENAME_T(\"{}_{:04d}-{:02d}-{:02d}_{:02d}-{:02d}-{:02d}{}\"), basename, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,\n            tm.tm_hour, tm.tm_min, tm.tm_sec, tmp_ext);\n        return std::make_tuple(w.str(), ext);\n    }\n};\n\n/*\n * Rotating file sink based on size and a specified time step\n */\ntemplate<class Mutex, class FileNameCalc = default_step_file_name_calculator>\nclass step_file_sink SPDLOG_FINAL : public base_sink<Mutex>\n{\npublic:\n    step_file_sink(filename_t base_filename, unsigned step_seconds, filename_t tmp_ext, unsigned max_size, bool delete_empty_files,\n        filename_t file_header)\n        : _base_filename(std::move(base_filename))\n        , _tmp_ext(std::move(tmp_ext))\n        , _step_seconds(step_seconds)\n        , _max_size(max_size)\n        , _delete_empty_files(delete_empty_files)\n    {\n        if (step_seconds == 0)\n        {\n            throw spdlog_ex(\"step_file_sink: Invalid time step in ctor\");\n        }\n\n        if (!file_header.empty())\n        {\n            pattern_formatter formatter_for_file_header(\"%v\");\n            _file_header.raw << file_header;\n            formatter_for_file_header.format(_file_header);\n        }\n\n        if (max_size <= _file_header.formatted.size())\n        {\n            throw spdlog_ex(\"step_file_sink: Invalid max log size in ctor\");\n        }\n\n        _tp = _next_tp();\n        std::tie(_current_filename, _ext) = FileNameCalc::calc_filename(_base_filename, _tmp_ext);\n\n        if (_tmp_ext == _ext)\n        {\n            throw spdlog_ex(\"step_file_sink: The temporary extension matches the specified in ctor\");\n        }\n\n        _file_helper.open(_current_filename);\n        _current_size = _file_helper.size(); // expensive. called only once\n\n        if (!_current_size)\n        {\n            _current_size += _file_header.formatted.size();\n            if (_current_size)\n                _file_helper.write(_file_header);\n        }\n    }\n\n    ~step_file_sink()\n    {\n        try\n        {\n            close_current_file();\n        }\n        catch (...)\n        {\n        }\n    }\n\nprotected:\n    void _sink_it(const details::log_msg &msg) override\n    {\n        auto msg_size = msg.formatted.size();\n\n        if (std::chrono::system_clock::now() >= _tp || _current_size + msg_size > _max_size)\n        {\n            filename_t new_filename;\n            std::tie(new_filename, std::ignore) = FileNameCalc::calc_filename(_base_filename, _tmp_ext);\n\n            bool change_occured = !details::file_helper::file_exists(new_filename);\n            if (change_occured)\n            {\n                close_current_file();\n\n                _current_filename = std::move(new_filename);\n\n                _file_helper.open(_current_filename);\n            }\n\n            _tp = _next_tp();\n\n            if (change_occured)\n            {\n                _current_size = _file_header.formatted.size();\n                if (_current_size)\n                    _file_helper.write(_file_header);\n            }\n        }\n\n        _current_size += msg_size;\n        _file_helper.write(msg);\n    }\n\n    void _flush() override\n    {\n        _file_helper.flush();\n    }\n\nprivate:\n    std::chrono::system_clock::time_point _next_tp()\n    {\n        return std::chrono::system_clock::now() + _step_seconds;\n    }\n\n    void close_current_file()\n    {\n        using details::os::filename_to_str;\n\n        // Delete empty files, if required\n        if (_delete_empty_files && _current_size <= _file_header.formatted.size())\n        {\n            if (details::os::remove(_current_filename) != 0)\n            {\n                throw spdlog_ex(\"step_file_sink: not remove \" + filename_to_str(_current_filename), errno);\n            }\n\n            return;\n        }\n\n        filename_t target;\n        std::tie(target, std::ignore) = details::file_helper::split_by_extenstion(_current_filename);\n        target += _ext;\n\n        if (details::file_helper::file_exists(_current_filename) && details::os::rename(_current_filename, target) != 0)\n        {\n            throw spdlog_ex(\n                \"step_file_sink: failed renaming \" + filename_to_str(_current_filename) + \" to \" + filename_to_str(target), errno);\n        }\n    }\n\n    const filename_t _base_filename;\n    const filename_t _tmp_ext;\n    const std::chrono::seconds _step_seconds;\n    const unsigned _max_size;\n    const bool _delete_empty_files;\n\n    std::chrono::system_clock::time_point _tp;\n    filename_t _current_filename;\n    filename_t _ext;\n    unsigned _current_size;\n\n    details::file_helper _file_helper;\n    details::log_msg _file_header;\n};\n\nusing step_file_sink_mt = step_file_sink<std::mutex>;\nusing step_file_sink_st = step_file_sink<details::null_mutex>;\n\n} // namespace sinks\n} // namespace spdlog\n"
  },
  {
    "path": "spdlog/details/async_log_helper.h",
    "content": "//\n// Copyright(c) 2015 Gabi Melman.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n//\n\n// async log helper :\n// Process logs asynchronously using a back thread.\n//\n// If the internal queue of log messages reaches its max size,\n// then the client call will block until there is more room.\n//\n\n#pragma once\n\n#include \"../common.h\"\n#include \"../details/log_msg.h\"\n#include \"../details/mpmc_blocking_q.h\"\n#include \"../details/os.h\"\n#include \"../formatter.h\"\n#include \"../sinks/sink.h\"\n\n#include <chrono>\n#include <condition_variable>\n#include <exception>\n#include <functional>\n#include <memory>\n#include <string>\n#include <thread>\n#include <utility>\n#include <vector>\n\nnamespace spdlog {\nnamespace details {\n\nclass async_log_helper\n{\n    // Async msg to move to/from the queue\n    // Movable only. should never be copied\n    enum class async_msg_type\n    {\n        log,\n        flush,\n        terminate\n    };\n\n    struct async_msg\n    {\n        level::level_enum level;\n        log_clock::time_point time;\n        size_t thread_id;\n        std::string txt;\n        async_msg_type msg_type;\n        size_t msg_id;\n\n        async_msg() = default;\n        ~async_msg() = default;\n\n        explicit async_msg(async_msg_type m_type)\n            : level(level::info)\n            , thread_id(0)\n            , msg_type(m_type)\n            , msg_id(0)\n        {\n        }\n\n        async_msg(async_msg &&other) = default;\n        async_msg &operator=(async_msg &&other) = default;\n\n        // never copy or assign. should only be moved..\n        async_msg(const async_msg &) = delete;\n        async_msg &operator=(const async_msg &other) = delete;\n\n        // construct from log_msg\n        explicit async_msg(const details::log_msg &m)\n            : level(m.level)\n            , time(m.time)\n            , thread_id(m.thread_id)\n            , txt(m.raw.data(), m.raw.size())\n            , msg_type(async_msg_type::log)\n            , msg_id(m.msg_id)\n        {\n        }\n\n        // copy into log_msg\n        void fill_log_msg(log_msg &msg, std::string *logger_name)\n        {\n            msg.logger_name = logger_name;\n            msg.level = level;\n            msg.time = time;\n            msg.thread_id = thread_id;\n            msg.raw.clear();\n            msg.raw << txt;\n            msg.msg_id = msg_id;\n        }\n    };\n\npublic:\n    using item_type = async_msg;\n    using q_type = details::mpmc_bounded_queue<item_type>;\n\n    using clock = std::chrono::steady_clock;\n\n    async_log_helper(std::string logger_name, formatter_ptr formatter, std::vector<sink_ptr> sinks, size_t queue_size,\n        const log_err_handler err_handler, const async_overflow_policy overflow_policy = async_overflow_policy::block_retry,\n        std::function<void()> worker_warmup_cb = nullptr,\n        const std::chrono::milliseconds &flush_interval_ms = std::chrono::milliseconds::zero(),\n        std::function<void()> worker_teardown_cb = nullptr);\n\n    void log(const details::log_msg &msg);\n\n    // stop logging and join the back thread\n    ~async_log_helper();\n\n    async_log_helper(const async_log_helper &) = delete;\n    async_log_helper &operator=(const async_log_helper &) = delete;\n\n    void set_formatter(formatter_ptr msg_formatter);\n\n    void flush();\n\n    void set_error_handler(spdlog::log_err_handler err_handler);\n\nprivate:\n    std::string _logger_name;\n    formatter_ptr _formatter;\n    std::vector<std::shared_ptr<sinks::sink>> _sinks;\n\n    // queue of messages to log\n    q_type _q;\n\n    log_err_handler _err_handler;\n\n    std::chrono::time_point<log_clock> _last_flush;\n\n    // overflow policy\n    const async_overflow_policy _overflow_policy;\n\n    // worker thread warmup callback - one can set thread priority, affinity, etc\n    const std::function<void()> _worker_warmup_cb;\n\n    // auto periodic sink flush parameter\n    const std::chrono::milliseconds _flush_interval_ms;\n\n    // worker thread teardown callback\n    const std::function<void()> _worker_teardown_cb;\n\n    std::mutex null_mutex_;\n    // null_mutex null_mutex_;\n    std::condition_variable_any not_empty_cv_;\n    std::condition_variable_any not_full_cv_;\n\n    // worker thread\n    std::thread _worker_thread;\n\n    void enqueue_msg(async_msg &&new_msg, async_overflow_policy policy);\n\n    // worker thread main loop\n    void worker_loop();\n\n    // dequeue next message from the queue and process it.\n    // return false if termination of the queue is required\n    bool process_next_msg();\n\n    void handle_flush_interval();\n\n    void flush_sinks();\n};\n} // namespace details\n} // namespace spdlog\n\n///////////////////////////////////////////////////////////////////////////////\n// async_sink class implementation\n///////////////////////////////////////////////////////////////////////////////\ninline spdlog::details::async_log_helper::async_log_helper(std::string logger_name, formatter_ptr formatter, std::vector<sink_ptr> sinks,\n    size_t queue_size, log_err_handler err_handler, const async_overflow_policy overflow_policy, std::function<void()> worker_warmup_cb,\n    const std::chrono::milliseconds &flush_interval_ms, std::function<void()> worker_teardown_cb)\n    : _logger_name(std::move(logger_name))\n    , _formatter(std::move(formatter))\n    , _sinks(std::move(sinks))\n    , _q(queue_size)\n    , _err_handler(std::move(err_handler))\n    , _last_flush(os::now())\n    , _overflow_policy(overflow_policy)\n    , _worker_warmup_cb(std::move(worker_warmup_cb))\n    , _flush_interval_ms(flush_interval_ms)\n    , _worker_teardown_cb(std::move(worker_teardown_cb))\n{\n    _worker_thread = std::thread(&async_log_helper::worker_loop, this);\n}\n\n// send to the worker thread terminate message, and join it.\ninline spdlog::details::async_log_helper::~async_log_helper()\n{\n    try\n    {\n        enqueue_msg(async_msg(async_msg_type::terminate), async_overflow_policy::block_retry);\n        _worker_thread.join();\n    }\n    catch (...) // don't crash in destructor\n    {\n    }\n}\n\n// try to push and block until succeeded (if the policy is not to discard when the queue is full)\ninline void spdlog::details::async_log_helper::log(const details::log_msg &msg)\n{\n    enqueue_msg(async_msg(msg), _overflow_policy);\n}\n\ninline void spdlog::details::async_log_helper::enqueue_msg(details::async_log_helper::async_msg &&new_msg, async_overflow_policy policy)\n{\n\n    // block until succeeded pushing to the queue\n    if (policy == async_overflow_policy::block_retry)\n    {\n        _q.enqueue(std::move(new_msg));\n    }\n    else\n    {\n        _q.enqueue_nowait(std::move(new_msg));\n    }\n}\n\n// optionally wait for the queue be empty and request flush from the sinks\ninline void spdlog::details::async_log_helper::flush()\n{\n    enqueue_msg(async_msg(async_msg_type::flush), _overflow_policy);\n}\n\ninline void spdlog::details::async_log_helper::worker_loop()\n{\n    if (_worker_warmup_cb)\n    {\n        _worker_warmup_cb();\n    }\n    auto active = true;\n    while (active)\n    {\n        try\n        {\n            active = process_next_msg();\n        }\n        SPDLOG_CATCH_AND_HANDLE\n    }\n    if (_worker_teardown_cb)\n    {\n        _worker_teardown_cb();\n    }\n}\n\n// process next message in the queue\n// return true if this thread should still be active (while no terminate msg was received)\ninline bool spdlog::details::async_log_helper::process_next_msg()\n{\n    async_msg incoming_async_msg;\n    bool dequeued = _q.dequeue_for(incoming_async_msg, std::chrono::seconds(2));\n    if (!dequeued)\n    {\n        handle_flush_interval();\n        return true;\n    }\n\n    switch (incoming_async_msg.msg_type)\n    {\n    case async_msg_type::flush:\n        flush_sinks();\n        return true;\n\n    case async_msg_type::terminate:\n        flush_sinks();\n        return false;\n\n    default:\n        log_msg incoming_log_msg;\n        incoming_async_msg.fill_log_msg(incoming_log_msg, &_logger_name);\n        _formatter->format(incoming_log_msg);\n        for (auto &s : _sinks)\n        {\n            if (s->should_log(incoming_log_msg.level))\n            {\n                try\n                {\n                    s->log(incoming_log_msg);\n                }\n                SPDLOG_CATCH_AND_HANDLE\n            }\n        }\n        handle_flush_interval();\n        return true;\n    }\n    assert(false);\n    return true; // should not be reached\n}\n\ninline void spdlog::details::async_log_helper::set_formatter(formatter_ptr msg_formatter)\n{\n    _formatter = std::move(msg_formatter);\n}\n\ninline void spdlog::details::async_log_helper::set_error_handler(spdlog::log_err_handler err_handler)\n{\n    _err_handler = std::move(err_handler);\n}\n\n// flush all sinks if _flush_interval_ms has expired.\ninline void spdlog::details::async_log_helper::handle_flush_interval()\n{\n    if (_flush_interval_ms == std::chrono::milliseconds::zero())\n    {\n        return;\n    }\n    auto delta = details::os::now() - _last_flush;\n    ;\n    if (delta >= _flush_interval_ms)\n    {\n        flush_sinks();\n    }\n}\n\n// flush all sinks if _flush_interval_ms has expired. only called if queue is empty\ninline void spdlog::details::async_log_helper::flush_sinks()\n{\n\n    for (auto &s : _sinks)\n    {\n        try\n        {\n            s->flush();\n        }\n        SPDLOG_CATCH_AND_HANDLE\n    }\n    _last_flush = os::now();\n}\n"
  },
  {
    "path": "spdlog/details/async_logger_impl.h",
    "content": "//\n// Copyright(c) 2015 Gabi Melman.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n//\n\n#pragma once\n\n// Async Logger implementation\n// Use an async_sink (queue per logger) to perform the logging in a worker thread\n\n#include \"../async_logger.h\"\n#include \"../details/async_log_helper.h\"\n\n#include <chrono>\n#include <functional>\n#include <memory>\n#include <string>\n\ntemplate<class It>\ninline spdlog::async_logger::async_logger(const std::string &logger_name, const It &begin, const It &end, size_t queue_size,\n    const async_overflow_policy overflow_policy, const std::function<void()> &worker_warmup_cb,\n    const std::chrono::milliseconds &flush_interval_ms, const std::function<void()> &worker_teardown_cb)\n    : logger(logger_name, begin, end)\n    , _async_log_helper(new details::async_log_helper(logger_name, _formatter, _sinks, queue_size, _err_handler, overflow_policy,\n          worker_warmup_cb, flush_interval_ms, worker_teardown_cb))\n{\n}\n\ninline spdlog::async_logger::async_logger(const std::string &logger_name, sinks_init_list sinks_list, size_t queue_size,\n    const async_overflow_policy overflow_policy, const std::function<void()> &worker_warmup_cb,\n    const std::chrono::milliseconds &flush_interval_ms, const std::function<void()> &worker_teardown_cb)\n    : async_logger(logger_name, sinks_list.begin(), sinks_list.end(), queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms,\n          worker_teardown_cb)\n{\n}\n\ninline spdlog::async_logger::async_logger(const std::string &logger_name, sink_ptr single_sink, size_t queue_size,\n    const async_overflow_policy overflow_policy, const std::function<void()> &worker_warmup_cb,\n    const std::chrono::milliseconds &flush_interval_ms, const std::function<void()> &worker_teardown_cb)\n    : async_logger(\n          logger_name, {std::move(single_sink)}, queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms, worker_teardown_cb)\n{\n}\n\ninline void spdlog::async_logger::flush()\n{\n    _async_log_helper->flush();\n}\n\n// Error handler\ninline void spdlog::async_logger::set_error_handler(spdlog::log_err_handler err_handler)\n{\n    _err_handler = err_handler;\n    _async_log_helper->set_error_handler(err_handler);\n}\ninline spdlog::log_err_handler spdlog::async_logger::error_handler()\n{\n    return _err_handler;\n}\n\ninline void spdlog::async_logger::_set_formatter(spdlog::formatter_ptr msg_formatter)\n{\n    _formatter = msg_formatter;\n    _async_log_helper->set_formatter(_formatter);\n}\n\ninline void spdlog::async_logger::_set_pattern(const std::string &pattern, pattern_time_type pattern_time)\n{\n    _formatter = std::make_shared<pattern_formatter>(pattern, pattern_time);\n    _async_log_helper->set_formatter(_formatter);\n}\n\ninline void spdlog::async_logger::_sink_it(details::log_msg &msg)\n{\n    try\n    {\n#if defined(SPDLOG_ENABLE_MESSAGE_COUNTER)\n        _incr_msg_counter(msg);\n#endif\n        _async_log_helper->log(msg);\n        if (_should_flush_on(msg))\n        {\n            _async_log_helper->flush(); // do async flush\n        }\n    }\n    catch (const std::exception &ex)\n    {\n        _err_handler(ex.what());\n    }\n    catch (...)\n    {\n        _err_handler(\"Unknown exception in logger \" + _name);\n        throw;\n    }\n}\n"
  },
  {
    "path": "spdlog/details/file_helper.h",
    "content": "//\n// Copyright(c) 2015 Gabi Melman.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n//\n\n#pragma once\n\n// Helper class for file sink\n// When failing to open a file, retry several times(5) with small delay between the tries(10 ms)\n// Throw spdlog_ex exception on errors\n\n#include \"../details/log_msg.h\"\n#include \"../details/os.h\"\n\n#include <cerrno>\n#include <chrono>\n#include <cstdio>\n#include <string>\n#include <thread>\n#include <tuple>\n\nnamespace spdlog {\nnamespace details {\n\nclass file_helper\n{\n\npublic:\n    const int open_tries = 5;\n    const int open_interval = 10;\n\n    explicit file_helper() = default;\n\n    file_helper(const file_helper &) = delete;\n    file_helper &operator=(const file_helper &) = delete;\n\n    ~file_helper()\n    {\n        close();\n    }\n\n    void open(const filename_t &fname, bool truncate = false)\n    {\n        close();\n        auto *mode = truncate ? SPDLOG_FILENAME_T(\"wb\") : SPDLOG_FILENAME_T(\"ab\");\n        _filename = fname;\n        for (int tries = 0; tries < open_tries; ++tries)\n        {\n            if (!os::fopen_s(&_fd, fname, mode))\n            {\n                return;\n            }\n\n            details::os::sleep_for_millis(open_interval);\n        }\n\n        throw spdlog_ex(\"Failed opening file \" + os::filename_to_str(_filename) + \" for writing\", errno);\n    }\n\n    void reopen(bool truncate)\n    {\n        if (_filename.empty())\n        {\n            throw spdlog_ex(\"Failed re opening file - was not opened before\");\n        }\n        open(_filename, truncate);\n    }\n\n    void flush()\n    {\n        std::fflush(_fd);\n    }\n\n    void close()\n    {\n        if (_fd != nullptr)\n        {\n            std::fclose(_fd);\n            _fd = nullptr;\n        }\n    }\n\n    void write(const log_msg &msg)\n    {\n        size_t msg_size = msg.formatted.size();\n        auto data = msg.formatted.data();\n        if (std::fwrite(data, 1, msg_size, _fd) != msg_size)\n        {\n            throw spdlog_ex(\"Failed writing to file \" + os::filename_to_str(_filename), errno);\n        }\n    }\n\n    size_t size() const\n    {\n        if (_fd == nullptr)\n        {\n            throw spdlog_ex(\"Cannot use size() on closed file \" + os::filename_to_str(_filename));\n        }\n        return os::filesize(_fd);\n    }\n\n    const filename_t &filename() const\n    {\n        return _filename;\n    }\n\n    static bool file_exists(const filename_t &fname)\n    {\n        return os::file_exists(fname);\n    }\n\n    //\n    // return file path and its extension:\n    //\n    // \"mylog.txt\" => (\"mylog\", \".txt\")\n    // \"mylog\" => (\"mylog\", \"\")\n    // \"mylog.\" => (\"mylog.\", \"\")\n    // \"/dir1/dir2/mylog.txt\" => (\"/dir1/dir2/mylog\", \".txt\")\n    //\n    // the starting dot in filenames is ignored (hidden files):\n    //\n    // \".mylog\" => (\".mylog\". \"\")\n    // \"my_folder/.mylog\" => (\"my_folder/.mylog\", \"\")\n    // \"my_folder/.mylog.txt\" => (\"my_folder/.mylog\", \".txt\")\n    static std::tuple<filename_t, filename_t> split_by_extenstion(const spdlog::filename_t &fname)\n    {\n        auto ext_index = fname.rfind('.');\n\n        // no valid extension found - return whole path and empty string as extension\n        if (ext_index == filename_t::npos || ext_index == 0 || ext_index == fname.size() - 1)\n        {\n            return std::make_tuple(fname, spdlog::filename_t());\n        }\n\n        // treat casese like \"/etc/rc.d/somelogfile or \"/abc/.hiddenfile\"\n        auto folder_index = fname.rfind(details::os::folder_sep);\n        if (folder_index != fname.npos && folder_index >= ext_index - 1)\n        {\n            return std::make_tuple(fname, spdlog::filename_t());\n        }\n\n        // finally - return a valid base and extension tuple\n        return std::make_tuple(fname.substr(0, ext_index), fname.substr(ext_index));\n    }\n\nprivate:\n    FILE *_fd{nullptr};\n    filename_t _filename;\n};\n} // namespace details\n} // namespace spdlog\n"
  },
  {
    "path": "spdlog/details/log_msg.h",
    "content": "//\n// Copyright(c) 2015 Gabi Melman.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n//\n\n#pragma once\n\n#include \"../common.h\"\n#include \"../details/os.h\"\n\n#include <string>\n#include <utility>\n\nnamespace spdlog {\nnamespace details {\nstruct log_msg\n{\n    log_msg() = default;\n    log_msg(const std::string *loggers_name, level::level_enum lvl)\n        : logger_name(loggers_name)\n        , level(lvl)\n    {\n#ifndef SPDLOG_NO_DATETIME\n        time = os::now();\n#endif\n\n#ifndef SPDLOG_NO_THREAD_ID\n        thread_id = os::thread_id();\n#endif\n    }\n\n    log_msg(const log_msg &other) = delete;\n    log_msg &operator=(log_msg &&other) = delete;\n    log_msg(log_msg &&other) = delete;\n\n    const std::string *logger_name{nullptr};\n    level::level_enum level;\n    log_clock::time_point time;\n    size_t thread_id;\n    fmt::MemoryWriter raw;\n    fmt::MemoryWriter formatted;\n    size_t msg_id{0};\n    // wrap this range with color codes\n    size_t color_range_start{0};\n    size_t color_range_end{0};\n};\n} // namespace details\n} // namespace spdlog\n"
  },
  {
    "path": "spdlog/details/logger_impl.h",
    "content": "//\n// Copyright(c) 2015 Gabi Melman.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n//\n\n#pragma once\n\n#include \"../logger.h\"\n\n#include <memory>\n#include <string>\n\n// create logger with given name, sinks and the default pattern formatter\n// all other ctors will call this one\ntemplate<class It>\ninline spdlog::logger::logger(std::string logger_name, const It &begin, const It &end)\n    : _name(std::move(logger_name))\n    , _sinks(begin, end)\n    , _formatter(std::make_shared<pattern_formatter>(\"%+\"))\n    , _level(level::info)\n    , _flush_level(level::off)\n    , _last_err_time(0)\n    , _msg_counter(1) // message counter will start from 1. 0-message id will be reserved for controll messages\n{\n    _err_handler = [this](const std::string &msg) { this->_default_err_handler(msg); };\n}\n\n// ctor with sinks as init list\ninline spdlog::logger::logger(const std::string &logger_name, sinks_init_list sinks_list)\n    : logger(logger_name, sinks_list.begin(), sinks_list.end())\n{\n}\n\n// ctor with single sink\ninline spdlog::logger::logger(const std::string &logger_name, spdlog::sink_ptr single_sink)\n    : logger(logger_name, {std::move(single_sink)})\n{\n}\n\ninline spdlog::logger::~logger() = default;\n\ninline void spdlog::logger::set_formatter(spdlog::formatter_ptr msg_formatter)\n{\n    _set_formatter(std::move(msg_formatter));\n}\n\ninline void spdlog::logger::set_pattern(const std::string &pattern, pattern_time_type pattern_time)\n{\n    _set_pattern(pattern, pattern_time);\n}\n\ntemplate<typename... Args>\ninline void spdlog::logger::log(level::level_enum lvl, const char *fmt, const Args &... args)\n{\n    if (!should_log(lvl))\n    {\n        return;\n    }\n\n    try\n    {\n        details::log_msg log_msg(&_name, lvl);\n\n#if defined(SPDLOG_FMT_PRINTF)\n        fmt::printf(log_msg.raw, fmt, args...);\n#else\n        log_msg.raw.write(fmt, args...);\n#endif\n        _sink_it(log_msg);\n    }\n    SPDLOG_CATCH_AND_HANDLE\n}\n\ntemplate<typename... Args>\ninline void spdlog::logger::log(level::level_enum lvl, const char *msg)\n{\n    if (!should_log(lvl))\n    {\n        return;\n    }\n    try\n    {\n        details::log_msg log_msg(&_name, lvl);\n        log_msg.raw << msg;\n        _sink_it(log_msg);\n    }\n    SPDLOG_CATCH_AND_HANDLE\n}\n\ntemplate<typename T>\ninline void spdlog::logger::log(level::level_enum lvl, const T &msg)\n{\n    if (!should_log(lvl))\n    {\n        return;\n    }\n    try\n    {\n        details::log_msg log_msg(&_name, lvl);\n        log_msg.raw << msg;\n        _sink_it(log_msg);\n    }\n    SPDLOG_CATCH_AND_HANDLE\n}\n\ntemplate<typename Arg1, typename... Args>\ninline void spdlog::logger::trace(const char *fmt, const Arg1 &arg1, const Args &... args)\n{\n    log(level::trace, fmt, arg1, args...);\n}\n\ntemplate<typename Arg1, typename... Args>\ninline void spdlog::logger::debug(const char *fmt, const Arg1 &arg1, const Args &... args)\n{\n    log(level::debug, fmt, arg1, args...);\n}\n\ntemplate<typename Arg1, typename... Args>\ninline void spdlog::logger::info(const char *fmt, const Arg1 &arg1, const Args &... args)\n{\n    log(level::info, fmt, arg1, args...);\n}\n\ntemplate<typename Arg1, typename... Args>\ninline void spdlog::logger::warn(const char *fmt, const Arg1 &arg1, const Args &... args)\n{\n    log(level::warn, fmt, arg1, args...);\n}\n\ntemplate<typename Arg1, typename... Args>\ninline void spdlog::logger::error(const char *fmt, const Arg1 &arg1, const Args &... args)\n{\n    log(level::err, fmt, arg1, args...);\n}\n\ntemplate<typename Arg1, typename... Args>\ninline void spdlog::logger::critical(const char *fmt, const Arg1 &arg1, const Args &... args)\n{\n    log(level::critical, fmt, arg1, args...);\n}\n\ntemplate<typename T>\ninline void spdlog::logger::trace(const T &msg)\n{\n    log(level::trace, msg);\n}\n\ntemplate<typename T>\ninline void spdlog::logger::debug(const T &msg)\n{\n    log(level::debug, msg);\n}\n\ntemplate<typename T>\ninline void spdlog::logger::info(const T &msg)\n{\n    log(level::info, msg);\n}\n\ntemplate<typename T>\ninline void spdlog::logger::warn(const T &msg)\n{\n    log(level::warn, msg);\n}\n\ntemplate<typename T>\ninline void spdlog::logger::error(const T &msg)\n{\n    log(level::err, msg);\n}\n\ntemplate<typename T>\ninline void spdlog::logger::critical(const T &msg)\n{\n    log(level::critical, msg);\n}\n\n#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT\n#include <codecvt>\n#include <locale>\n\ntemplate<typename... Args>\ninline void spdlog::logger::log(level::level_enum lvl, const wchar_t *msg)\n{\n    std::wstring_convert<std::codecvt_utf8<wchar_t>> conv;\n\n    log(lvl, conv.to_bytes(msg));\n}\n\ntemplate<typename... Args>\ninline void spdlog::logger::log(level::level_enum lvl, const wchar_t *fmt, const Args &... args)\n{\n    fmt::WMemoryWriter wWriter;\n\n    wWriter.write(fmt, args...);\n    log(lvl, wWriter.c_str());\n}\n\ntemplate<typename... Args>\ninline void spdlog::logger::trace(const wchar_t *fmt, const Args &... args)\n{\n    log(level::trace, fmt, args...);\n}\n\ntemplate<typename... Args>\ninline void spdlog::logger::debug(const wchar_t *fmt, const Args &... args)\n{\n    log(level::debug, fmt, args...);\n}\n\ntemplate<typename... Args>\ninline void spdlog::logger::info(const wchar_t *fmt, const Args &... args)\n{\n    log(level::info, fmt, args...);\n}\n\ntemplate<typename... Args>\ninline void spdlog::logger::warn(const wchar_t *fmt, const Args &... args)\n{\n    log(level::warn, fmt, args...);\n}\n\ntemplate<typename... Args>\ninline void spdlog::logger::error(const wchar_t *fmt, const Args &... args)\n{\n    log(level::err, fmt, args...);\n}\n\ntemplate<typename... Args>\ninline void spdlog::logger::critical(const wchar_t *fmt, const Args &... args)\n{\n    log(level::critical, fmt, args...);\n}\n\n#endif // SPDLOG_WCHAR_TO_UTF8_SUPPORT\n\n//\n// name and level\n//\ninline const std::string &spdlog::logger::name() const\n{\n    return _name;\n}\n\ninline void spdlog::logger::set_level(spdlog::level::level_enum log_level)\n{\n    _level.store(log_level);\n}\n\ninline void spdlog::logger::set_error_handler(spdlog::log_err_handler err_handler)\n{\n    _err_handler = std::move(err_handler);\n}\n\ninline spdlog::log_err_handler spdlog::logger::error_handler()\n{\n    return _err_handler;\n}\n\ninline void spdlog::logger::flush_on(level::level_enum log_level)\n{\n    _flush_level.store(log_level);\n}\n\ninline spdlog::level::level_enum spdlog::logger::level() const\n{\n    return static_cast<spdlog::level::level_enum>(_level.load(std::memory_order_relaxed));\n}\n\ninline bool spdlog::logger::should_log(spdlog::level::level_enum msg_level) const\n{\n    return msg_level >= _level.load(std::memory_order_relaxed);\n}\n\n//\n// protected virtual called at end of each user log call (if enabled) by the line_logger\n//\ninline void spdlog::logger::_sink_it(details::log_msg &msg)\n{\n#if defined(SPDLOG_ENABLE_MESSAGE_COUNTER)\n    _incr_msg_counter(msg);\n#endif\n    _formatter->format(msg);\n    for (auto &sink : _sinks)\n    {\n        if (sink->should_log(msg.level))\n        {\n            sink->log(msg);\n        }\n    }\n\n    if (_should_flush_on(msg))\n    {\n        flush();\n    }\n}\n\ninline void spdlog::logger::_set_pattern(const std::string &pattern, pattern_time_type pattern_time)\n{\n    _formatter = std::make_shared<pattern_formatter>(pattern, pattern_time);\n}\n\ninline void spdlog::logger::_set_formatter(formatter_ptr msg_formatter)\n{\n    _formatter = std::move(msg_formatter);\n}\n\ninline void spdlog::logger::flush()\n{\n    try\n    {\n        for (auto &sink : _sinks)\n        {\n            sink->flush();\n        }\n    }\n    SPDLOG_CATCH_AND_HANDLE\n}\n\ninline void spdlog::logger::_default_err_handler(const std::string &msg)\n{\n    auto now = time(nullptr);\n    if (now - _last_err_time < 60)\n    {\n        return;\n    }\n    _last_err_time = now;\n    auto tm_time = details::os::localtime(now);\n    char date_buf[100];\n    std::strftime(date_buf, sizeof(date_buf), \"%Y-%m-%d %H:%M:%S\", &tm_time);\n    fmt::print(stderr, \"[*** LOG ERROR ***] [{}] [{}] {}\\n\", date_buf, name(), msg);\n}\n\ninline bool spdlog::logger::_should_flush_on(const details::log_msg &msg)\n{\n    const auto flush_level = _flush_level.load(std::memory_order_relaxed);\n    return (msg.level >= flush_level) && (msg.level != level::off);\n}\n\ninline void spdlog::logger::_incr_msg_counter(details::log_msg &msg)\n{\n    msg.msg_id = _msg_counter.fetch_add(1, std::memory_order_relaxed);\n}\n\ninline const std::vector<spdlog::sink_ptr> &spdlog::logger::sinks() const\n{\n    return _sinks;\n}\n"
  },
  {
    "path": "spdlog/details/mpmc_blocking_q.h",
    "content": "#pragma once\n\n//\n// Copyright(c) 2018 Gabi Melman.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n//\n\n// async log helper :\n// multi producer-multi consumer blocking queue\n// enqueue(..) - will block until room found to put the new message\n// enqueue_nowait(..) - will return immediatly with false if no room left in the queue\n// dequeue_for(..) - will block until the queue is not empty or timeout passed\n\n#include <condition_variable>\n#include <mutex>\n#include <queue>\n\nnamespace spdlog {\nnamespace details {\n\ntemplate<typename T>\nclass mpmc_bounded_queue\n{\npublic:\n    using item_type = T;\n    explicit mpmc_bounded_queue(size_t max_items)\n        : max_items_(max_items)\n    {\n    }\n\n    // try to enqueue and block if no room left\n    void enqueue(T &&item)\n    {\n        {\n            std::unique_lock<std::mutex> lock(queue_mutex_);\n            pop_cv_.wait(lock, [this] { return this->q_.size() < this->max_items_; });\n            q_.push(std::move(item));\n        }\n        push_cv_.notify_one();\n    }\n\n    // try to enqueue and return immdeialty false if no room left\n    bool enqueue_nowait(T &&item)\n    {\n        {\n            std::unique_lock<std::mutex> lock(queue_mutex_);\n            if (q_.size() == this->max_items_)\n            {\n                return false;\n            }\n            q_.push(std::forward<T>(item));\n        }\n        push_cv_.notify_one();\n        return true;\n    }\n\n    // try to dequeue item. if no item found. wait upto timeout and try again\n    // Return true, if succeeded dequeue item, false otherwise\n    bool dequeue_for(T &popped_item, std::chrono::milliseconds wait_duration)\n    {\n        {\n            std::unique_lock<std::mutex> lock(queue_mutex_);\n            if (!push_cv_.wait_for(lock, wait_duration, [this] { return this->q_.size() > 0; }))\n            {\n                return false;\n            }\n\n            popped_item = std::move(q_.front());\n            q_.pop();\n        }\n        pop_cv_.notify_one();\n        return true;\n    }\n\nprivate:\n    size_t max_items_;\n    std::mutex queue_mutex_;\n    std::condition_variable push_cv_;\n    std::condition_variable pop_cv_;\n\n    std::queue<T> q_;\n};\n} // namespace details\n} // namespace spdlog\n"
  },
  {
    "path": "spdlog/details/null_mutex.h",
    "content": "//\n// Copyright(c) 2015 Gabi Melman.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n//\n\n#pragma once\n\n#include <atomic>\n// null, no cost dummy \"mutex\" and dummy \"atomic\" int\n\nnamespace spdlog {\nnamespace details {\nstruct null_mutex\n{\n    void lock() {}\n    void unlock() {}\n    bool try_lock()\n    {\n        return true;\n    }\n};\n\nstruct null_atomic_int\n{\n    int value;\n    null_atomic_int() = default;\n\n    explicit null_atomic_int(int val)\n        : value(val)\n    {\n    }\n\n    int load(std::memory_order) const\n    {\n        return value;\n    }\n\n    void store(int val)\n    {\n        value = val;\n    }\n};\n\n} // namespace details\n} // namespace spdlog\n"
  },
  {
    "path": "spdlog/details/os.h",
    "content": "//\n// Copyright(c) 2015 Gabi Melman.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n//\n#pragma once\n\n#include \"../common.h\"\n\n#include <algorithm>\n#include <chrono>\n#include <cstdio>\n#include <cstdlib>\n#include <cstring>\n#include <ctime>\n#include <functional>\n#include <string>\n#include <sys/stat.h>\n#include <sys/types.h>\n#include <thread>\n\n#ifdef _WIN32\n\n#ifndef NOMINMAX\n#define NOMINMAX // prevent windows redefining min/max\n#endif\n\n#ifndef WIN32_LEAN_AND_MEAN\n#define WIN32_LEAN_AND_MEAN\n#endif\n#include <io.h>      // _get_osfhandle and _isatty support\n#include <process.h> //  _get_pid support\n#include <windows.h>\n\n#ifdef __MINGW32__\n#include <share.h>\n#endif\n\n#else // unix\n\n#include <fcntl.h>\n#include <unistd.h>\n\n#ifdef __linux__\n#include <sys/syscall.h> //Use gettid() syscall under linux to get thread id\n\n#elif __FreeBSD__\n#include <sys/thr.h> //Use thr_self() syscall under FreeBSD to get thread id\n#endif\n\n#endif // unix\n\n#ifndef __has_feature      // Clang - feature checking macros.\n#define __has_feature(x) 0 // Compatibility with non-clang compilers.\n#endif\n\nnamespace spdlog {\nnamespace details {\nnamespace os {\n\ninline spdlog::log_clock::time_point now()\n{\n\n#if defined __linux__ && defined SPDLOG_CLOCK_COARSE\n    timespec ts;\n    ::clock_gettime(CLOCK_REALTIME_COARSE, &ts);\n    return std::chrono::time_point<log_clock, typename log_clock::duration>(\n        std::chrono::duration_cast<typename log_clock::duration>(std::chrono::seconds(ts.tv_sec) + std::chrono::nanoseconds(ts.tv_nsec)));\n\n#else\n    return log_clock::now();\n#endif\n}\ninline std::tm localtime(const std::time_t &time_tt)\n{\n\n#ifdef _WIN32\n    std::tm tm;\n    localtime_s(&tm, &time_tt);\n#else\n    std::tm tm;\n    localtime_r(&time_tt, &tm);\n#endif\n    return tm;\n}\n\ninline std::tm localtime()\n{\n    std::time_t now_t = time(nullptr);\n    return localtime(now_t);\n}\n\ninline std::tm gmtime(const std::time_t &time_tt)\n{\n\n#ifdef _WIN32\n    std::tm tm;\n    gmtime_s(&tm, &time_tt);\n#else\n    std::tm tm;\n    gmtime_r(&time_tt, &tm);\n#endif\n    return tm;\n}\n\ninline std::tm gmtime()\n{\n    std::time_t now_t = time(nullptr);\n    return gmtime(now_t);\n}\ninline bool operator==(const std::tm &tm1, const std::tm &tm2)\n{\n    return (tm1.tm_sec == tm2.tm_sec && tm1.tm_min == tm2.tm_min && tm1.tm_hour == tm2.tm_hour && tm1.tm_mday == tm2.tm_mday &&\n            tm1.tm_mon == tm2.tm_mon && tm1.tm_year == tm2.tm_year && tm1.tm_isdst == tm2.tm_isdst);\n}\n\ninline bool operator!=(const std::tm &tm1, const std::tm &tm2)\n{\n    return !(tm1 == tm2);\n}\n\n// eol definition\n#if !defined(SPDLOG_EOL)\n#ifdef _WIN32\n#define SPDLOG_EOL \"\\r\\n\"\n#else\n#define SPDLOG_EOL \"\\n\"\n#endif\n#endif\n\nSPDLOG_CONSTEXPR static const char *default_eol = SPDLOG_EOL;\n\n// folder separator\n#ifdef _WIN32\nSPDLOG_CONSTEXPR static const char folder_sep = '\\\\';\n#else\nSPDLOG_CONSTEXPR static const char folder_sep = '/';\n#endif\n\ninline void prevent_child_fd(FILE *f)\n{\n\n#ifdef _WIN32\n#if !defined(__cplusplus_winrt)\n    auto file_handle = (HANDLE)_get_osfhandle(_fileno(f));\n    if (!::SetHandleInformation(file_handle, HANDLE_FLAG_INHERIT, 0))\n        throw spdlog_ex(\"SetHandleInformation failed\", errno);\n#endif\n#else\n    auto fd = fileno(f);\n    if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)\n    {\n        throw spdlog_ex(\"fcntl with FD_CLOEXEC failed\", errno);\n    }\n#endif\n}\n\n// fopen_s on non windows for writing\ninline bool fopen_s(FILE **fp, const filename_t &filename, const filename_t &mode)\n{\n#ifdef _WIN32\n#ifdef SPDLOG_WCHAR_FILENAMES\n    *fp = _wfsopen((filename.c_str()), mode.c_str(), _SH_DENYWR);\n#else\n    *fp = _fsopen((filename.c_str()), mode.c_str(), _SH_DENYWR);\n#endif\n#else // unix\n    *fp = fopen((filename.c_str()), mode.c_str());\n#endif\n\n#ifdef SPDLOG_PREVENT_CHILD_FD\n    if (*fp != nullptr)\n    {\n        prevent_child_fd(*fp);\n    }\n#endif\n    return *fp == nullptr;\n}\n\ninline int remove(const filename_t &filename)\n{\n#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)\n    return _wremove(filename.c_str());\n#else\n    return std::remove(filename.c_str());\n#endif\n}\n\ninline int rename(const filename_t &filename1, const filename_t &filename2)\n{\n#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)\n    return _wrename(filename1.c_str(), filename2.c_str());\n#else\n    return std::rename(filename1.c_str(), filename2.c_str());\n#endif\n}\n\n// Return if file exists\ninline bool file_exists(const filename_t &filename)\n{\n#ifdef _WIN32\n#ifdef SPDLOG_WCHAR_FILENAMES\n    auto attribs = GetFileAttributesW(filename.c_str());\n#else\n    auto attribs = GetFileAttributesA(filename.c_str());\n#endif\n    return (attribs != INVALID_FILE_ATTRIBUTES && !(attribs & FILE_ATTRIBUTE_DIRECTORY));\n#else // common linux/unix all have the stat system call\n    struct stat buffer;\n    return (stat(filename.c_str(), &buffer) == 0);\n#endif\n}\n\n// Return file size according to open FILE* object\ninline size_t filesize(FILE *f)\n{\n    if (f == nullptr)\n    {\n        throw spdlog_ex(\"Failed getting file size. fd is null\");\n    }\n#if defined(_WIN32) && !defined(__CYGWIN__)\n    int fd = _fileno(f);\n#if _WIN64 // 64 bits\n    struct _stat64 st;\n    if (_fstat64(fd, &st) == 0)\n    {\n        return st.st_size;\n    }\n\n#else // windows 32 bits\n    long ret = _filelength(fd);\n    if (ret >= 0)\n    {\n        return static_cast<size_t>(ret);\n    }\n#endif\n\n#else // unix\n    int fd = fileno(f);\n    // 64 bits(but not in osx or cygwin, where fstat64 is deprecated)\n#if !defined(__OpenBSD__) && !defined(__FreeBSD__) && !defined(__APPLE__) && (defined(__x86_64__) || defined(__ppc64__)) && !defined(__CYGWIN__)\n    struct stat64 st;\n    if (fstat64(fd, &st) == 0)\n    {\n        return static_cast<size_t>(st.st_size);\n    }\n#else // unix 32 bits or cygwin\n    struct stat st;\n\n    if (fstat(fd, &st) == 0)\n    {\n        return static_cast<size_t>(st.st_size);\n    }\n#endif\n#endif\n    throw spdlog_ex(\"Failed getting file size from fd\", errno);\n}\n\n// Return utc offset in minutes or throw spdlog_ex on failure\ninline int utc_minutes_offset(const std::tm &tm = details::os::localtime())\n{\n\n#ifdef _WIN32\n#if _WIN32_WINNT < _WIN32_WINNT_WS08\n    TIME_ZONE_INFORMATION tzinfo;\n    auto rv = GetTimeZoneInformation(&tzinfo);\n#else\n    DYNAMIC_TIME_ZONE_INFORMATION tzinfo;\n    auto rv = GetDynamicTimeZoneInformation(&tzinfo);\n#endif\n    if (rv == TIME_ZONE_ID_INVALID)\n        throw spdlog::spdlog_ex(\"Failed getting timezone info. \", errno);\n\n    int offset = -tzinfo.Bias;\n    if (tm.tm_isdst)\n    {\n        offset -= tzinfo.DaylightBias;\n    }\n    else\n    {\n        offset -= tzinfo.StandardBias;\n    }\n    return offset;\n#else\n\n#if defined(sun) || defined(__sun) || defined(_AIX)\n    // 'tm_gmtoff' field is BSD extension and it's missing on SunOS/Solaris\n    struct helper\n    {\n        static long int calculate_gmt_offset(const std::tm &localtm = details::os::localtime(), const std::tm &gmtm = details::os::gmtime())\n        {\n            int local_year = localtm.tm_year + (1900 - 1);\n            int gmt_year = gmtm.tm_year + (1900 - 1);\n\n            long int days = (\n                // difference in day of year\n                localtm.tm_yday -\n                gmtm.tm_yday\n\n                // + intervening leap days\n                + ((local_year >> 2) - (gmt_year >> 2)) - (local_year / 100 - gmt_year / 100) +\n                ((local_year / 100 >> 2) - (gmt_year / 100 >> 2))\n\n                // + difference in years * 365 */\n                + (long int)(local_year - gmt_year) * 365);\n\n            long int hours = (24 * days) + (localtm.tm_hour - gmtm.tm_hour);\n            long int mins = (60 * hours) + (localtm.tm_min - gmtm.tm_min);\n            long int secs = (60 * mins) + (localtm.tm_sec - gmtm.tm_sec);\n\n            return secs;\n        }\n    };\n\n    auto offset_seconds = helper::calculate_gmt_offset(tm);\n#else\n    auto offset_seconds = tm.tm_gmtoff;\n#endif\n\n    return static_cast<int>(offset_seconds / 60);\n#endif\n}\n\n// Return current thread id as size_t\n// It exists because the std::this_thread::get_id() is much slower(especially under VS 2013)\ninline size_t _thread_id()\n{\n#ifdef _WIN32\n    return static_cast<size_t>(::GetCurrentThreadId());\n#elif __linux__\n#if defined(__ANDROID__) && defined(__ANDROID_API__) && (__ANDROID_API__ < 21)\n#define SYS_gettid __NR_gettid\n#endif\n    return static_cast<size_t>(syscall(SYS_gettid));\n#elif __FreeBSD__\n    long tid;\n    thr_self(&tid);\n    return static_cast<size_t>(tid);\n#elif __APPLE__\n    uint64_t tid;\n    pthread_threadid_np(nullptr, &tid);\n    return static_cast<size_t>(tid);\n#else // Default to standard C++11 (other Unix)\n    return static_cast<size_t>(std::hash<std::thread::id>()(std::this_thread::get_id()));\n#endif\n}\n\n// Return current thread id as size_t (from thread local storage)\ninline size_t thread_id()\n{\n#if defined(SPDLOG_DISABLE_TID_CACHING) || (defined(_MSC_VER) && (_MSC_VER < 1900)) || defined(__cplusplus_winrt) ||                       \\\n    (defined(__clang__) && !__has_feature(cxx_thread_local))\n    return _thread_id();\n#else // cache thread id in tls\n    static thread_local const size_t tid = _thread_id();\n    return tid;\n#endif\n}\n\n// This is avoid msvc issue in sleep_for that happens if the clock changes.\n// See https://github.com/gabime/spdlog/issues/609\ninline void sleep_for_millis(int milliseconds)\n{\n#if defined(_WIN32)\n    ::Sleep(milliseconds);\n#else\n    std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds));\n#endif\n}\n\n// wchar support for windows file names (SPDLOG_WCHAR_FILENAMES must be defined)\n#if defined(_WIN32) && defined(SPDLOG_WCHAR_FILENAMES)\n#define SPDLOG_FILENAME_T(s) L##s\ninline std::string filename_to_str(const filename_t &filename)\n{\n    std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> c;\n    return c.to_bytes(filename);\n}\n#else\n#define SPDLOG_FILENAME_T(s) s\ninline std::string filename_to_str(const filename_t &filename)\n{\n    return filename;\n}\n#endif\n\ninline int pid()\n{\n\n#ifdef _WIN32\n    return static_cast<int>(::GetCurrentProcessId());\n#else\n    return static_cast<int>(::getpid());\n#endif\n}\n\n// Determine if the terminal supports colors\n// Source: https://github.com/agauniyal/rang/\ninline bool is_color_terminal()\n{\n#ifdef _WIN32\n    return true;\n#else\n    static constexpr const char *Terms[] = {\n        \"ansi\", \"color\", \"console\", \"cygwin\", \"gnome\", \"konsole\", \"kterm\", \"linux\", \"msys\", \"putty\", \"rxvt\", \"screen\", \"vt100\", \"xterm\"};\n\n    const char *env_p = std::getenv(\"TERM\");\n    if (env_p == nullptr)\n    {\n        return false;\n    }\n\n    static const bool result =\n        std::any_of(std::begin(Terms), std::end(Terms), [&](const char *term) { return std::strstr(env_p, term) != nullptr; });\n    return result;\n#endif\n}\n\n// Detrmine if the terminal attached\n// Source: https://github.com/agauniyal/rang/\ninline bool in_terminal(FILE *file)\n{\n\n#ifdef _WIN32\n    return _isatty(_fileno(file)) != 0;\n#else\n    return isatty(fileno(file)) != 0;\n#endif\n}\n} // namespace os\n} // namespace details\n} // namespace spdlog\n"
  },
  {
    "path": "spdlog/details/pattern_formatter_impl.h",
    "content": "//\n// Copyright(c) 2015 Gabi Melman.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n//\n\n#pragma once\n\n#include \"../details/log_msg.h\"\n#include \"../details/os.h\"\n#include \"../fmt/fmt.h\"\n#include \"../formatter.h\"\n\n#include <array>\n#include <chrono>\n#include <ctime>\n#include <memory>\n#include <mutex>\n#include <string>\n#include <thread>\n#include <utility>\n#include <vector>\n\nnamespace spdlog {\nnamespace details {\nclass flag_formatter\n{\npublic:\n    virtual ~flag_formatter() = default;\n    virtual void format(details::log_msg &msg, const std::tm &tm_time) = 0;\n};\n\n///////////////////////////////////////////////////////////////////////\n// name & level pattern appenders\n///////////////////////////////////////////////////////////////////////\nclass name_formatter : public flag_formatter\n{\n    void format(details::log_msg &msg, const std::tm &) override\n    {\n        msg.formatted << *msg.logger_name;\n    }\n};\n\n// log level appender\nclass level_formatter : public flag_formatter\n{\n    void format(details::log_msg &msg, const std::tm &) override\n    {\n        msg.formatted << level::to_str(msg.level);\n    }\n};\n\n// short log level appender\nclass short_level_formatter : public flag_formatter\n{\n    void format(details::log_msg &msg, const std::tm &) override\n    {\n        msg.formatted << level::to_short_str(msg.level);\n    }\n};\n\n///////////////////////////////////////////////////////////////////////\n// Date time pattern appenders\n///////////////////////////////////////////////////////////////////////\n\nstatic const char *ampm(const tm &t)\n{\n    return t.tm_hour >= 12 ? \"PM\" : \"AM\";\n}\n\nstatic int to12h(const tm &t)\n{\n    return t.tm_hour > 12 ? t.tm_hour - 12 : t.tm_hour;\n}\n\n// Abbreviated weekday name\nstatic const std::string days[]{\"Sun\", \"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\"};\nclass a_formatter : public flag_formatter\n{\n    void format(details::log_msg &msg, const std::tm &tm_time) override\n    {\n        msg.formatted << days[tm_time.tm_wday];\n    }\n};\n\n// Full weekday name\nstatic const std::string full_days[]{\"Sunday\", \"Monday\", \"Tuesday\", \"Wednesday\", \"Thursday\", \"Friday\", \"Saturday\"};\nclass A_formatter : public flag_formatter\n{\n    void format(details::log_msg &msg, const std::tm &tm_time) override\n    {\n        msg.formatted << full_days[tm_time.tm_wday];\n    }\n};\n\n// Abbreviated month\nstatic const std::string months[]{\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\", \"Jul\", \"Aug\", \"Sept\", \"Oct\", \"Nov\", \"Dec\"};\nclass b_formatter : public flag_formatter\n{\n    void format(details::log_msg &msg, const std::tm &tm_time) override\n    {\n        msg.formatted << months[tm_time.tm_mon];\n    }\n};\n\n// Full month name\nstatic const std::string full_months[]{\n    \"January\", \"February\", \"March\", \"April\", \"May\", \"June\", \"July\", \"August\", \"September\", \"October\", \"November\", \"December\"};\nclass B_formatter : public flag_formatter\n{\n    void format(details::log_msg &msg, const std::tm &tm_time) override\n    {\n        msg.formatted << full_months[tm_time.tm_mon];\n    }\n};\n\n// write 2 ints separated by sep with padding of 2\nstatic fmt::MemoryWriter &pad_n_join(fmt::MemoryWriter &w, int v1, int v2, char sep)\n{\n    w << fmt::pad(v1, 2, '0') << sep << fmt::pad(v2, 2, '0');\n    return w;\n}\n\n// write 3 ints separated by sep with padding of 2\nstatic fmt::MemoryWriter &pad_n_join(fmt::MemoryWriter &w, int v1, int v2, int v3, char sep)\n{\n    w << fmt::pad(v1, 2, '0') << sep << fmt::pad(v2, 2, '0') << sep << fmt::pad(v3, 2, '0');\n    return w;\n}\n\n// Date and time representation (Thu Aug 23 15:35:46 2014)\nclass c_formatter SPDLOG_FINAL : public flag_formatter\n{\n    void format(details::log_msg &msg, const std::tm &tm_time) override\n    {\n        msg.formatted << days[tm_time.tm_wday] << ' ' << months[tm_time.tm_mon] << ' ' << tm_time.tm_mday << ' ';\n        pad_n_join(msg.formatted, tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec, ':') << ' ' << tm_time.tm_year + 1900;\n    }\n};\n\n// year - 2 digit\nclass C_formatter SPDLOG_FINAL : public flag_formatter\n{\n    void format(details::log_msg &msg, const std::tm &tm_time) override\n    {\n        msg.formatted << fmt::pad(tm_time.tm_year % 100, 2, '0');\n    }\n};\n\n// Short MM/DD/YY date, equivalent to %m/%d/%y 08/23/01\nclass D_formatter SPDLOG_FINAL : public flag_formatter\n{\n    void format(details::log_msg &msg, const std::tm &tm_time) override\n    {\n        pad_n_join(msg.formatted, tm_time.tm_mon + 1, tm_time.tm_mday, tm_time.tm_year % 100, '/');\n    }\n};\n\n// year - 4 digit\nclass Y_formatter SPDLOG_FINAL : public flag_formatter\n{\n    void format(details::log_msg &msg, const std::tm &tm_time) override\n    {\n        msg.formatted << tm_time.tm_year + 1900;\n    }\n};\n\n// month 1-12\nclass m_formatter SPDLOG_FINAL : public flag_formatter\n{\n    void format(details::log_msg &msg, const std::tm &tm_time) override\n    {\n        msg.formatted << fmt::pad(tm_time.tm_mon + 1, 2, '0');\n    }\n};\n\n// day of month 1-31\nclass d_formatter SPDLOG_FINAL : public flag_formatter\n{\n    void format(details::log_msg &msg, const std::tm &tm_time) override\n    {\n        msg.formatted << fmt::pad(tm_time.tm_mday, 2, '0');\n    }\n};\n\n// hours in 24 format 0-23\nclass H_formatter SPDLOG_FINAL : public flag_formatter\n{\n    void format(details::log_msg &msg, const std::tm &tm_time) override\n    {\n        msg.formatted << fmt::pad(tm_time.tm_hour, 2, '0');\n    }\n};\n\n// hours in 12 format 1-12\nclass I_formatter SPDLOG_FINAL : public flag_formatter\n{\n    void format(details::log_msg &msg, const std::tm &tm_time) override\n    {\n        msg.formatted << fmt::pad(to12h(tm_time), 2, '0');\n    }\n};\n\n// minutes 0-59\nclass M_formatter SPDLOG_FINAL : public flag_formatter\n{\n    void format(details::log_msg &msg, const std::tm &tm_time) override\n    {\n        msg.formatted << fmt::pad(tm_time.tm_min, 2, '0');\n    }\n};\n\n// seconds 0-59\nclass S_formatter SPDLOG_FINAL : public flag_formatter\n{\n    void format(details::log_msg &msg, const std::tm &tm_time) override\n    {\n        msg.formatted << fmt::pad(tm_time.tm_sec, 2, '0');\n    }\n};\n\n// milliseconds\nclass e_formatter SPDLOG_FINAL : public flag_formatter\n{\n    void format(details::log_msg &msg, const std::tm &) override\n    {\n        auto duration = msg.time.time_since_epoch();\n        auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count() % 1000;\n        msg.formatted << fmt::pad(static_cast<int>(millis), 3, '0');\n    }\n};\n\n// microseconds\nclass f_formatter SPDLOG_FINAL : public flag_formatter\n{\n    void format(details::log_msg &msg, const std::tm &) override\n    {\n        auto duration = msg.time.time_since_epoch();\n        auto micros = std::chrono::duration_cast<std::chrono::microseconds>(duration).count() % 1000000;\n        msg.formatted << fmt::pad(static_cast<int>(micros), 6, '0');\n    }\n};\n\n// nanoseconds\nclass F_formatter SPDLOG_FINAL : public flag_formatter\n{\n    void format(details::log_msg &msg, const std::tm &) override\n    {\n        auto duration = msg.time.time_since_epoch();\n        auto ns = std::chrono::duration_cast<std::chrono::nanoseconds>(duration).count() % 1000000000;\n        msg.formatted << fmt::pad(static_cast<int>(ns), 9, '0');\n    }\n};\n\nclass E_formatter SPDLOG_FINAL : public flag_formatter\n{\n    void format(details::log_msg &msg, const std::tm &) override\n    {\n        auto duration = msg.time.time_since_epoch();\n        auto seconds = std::chrono::duration_cast<std::chrono::seconds>(duration).count();\n        msg.formatted << seconds;\n    }\n};\n\n// AM/PM\nclass p_formatter SPDLOG_FINAL : public flag_formatter\n{\n    void format(details::log_msg &msg, const std::tm &tm_time) override\n    {\n        msg.formatted << ampm(tm_time);\n    }\n};\n\n// 12 hour clock 02:55:02 pm\nclass r_formatter SPDLOG_FINAL : public flag_formatter\n{\n    void format(details::log_msg &msg, const std::tm &tm_time) override\n    {\n        pad_n_join(msg.formatted, to12h(tm_time), tm_time.tm_min, tm_time.tm_sec, ':') << ' ' << ampm(tm_time);\n    }\n};\n\n// 24-hour HH:MM time, equivalent to %H:%M\nclass R_formatter SPDLOG_FINAL : public flag_formatter\n{\n    void format(details::log_msg &msg, const std::tm &tm_time) override\n    {\n        pad_n_join(msg.formatted, tm_time.tm_hour, tm_time.tm_min, ':');\n    }\n};\n\n// ISO 8601 time format (HH:MM:SS), equivalent to %H:%M:%S\nclass T_formatter SPDLOG_FINAL : public flag_formatter\n{\n    void format(details::log_msg &msg, const std::tm &tm_time) override\n    {\n        pad_n_join(msg.formatted, tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec, ':');\n    }\n};\n\n// ISO 8601 offset from UTC in timezone (+-HH:MM)\nclass z_formatter SPDLOG_FINAL : public flag_formatter\n{\npublic:\n    const std::chrono::seconds cache_refresh = std::chrono::seconds(5);\n\n    z_formatter() = default;\n    z_formatter(const z_formatter &) = delete;\n    z_formatter &operator=(const z_formatter &) = delete;\n\n    void format(details::log_msg &msg, const std::tm &tm_time) override\n    {\n#ifdef _WIN32\n        int total_minutes = get_cached_offset(msg, tm_time);\n#else\n        // No need to chache under gcc,\n        // it is very fast (already stored in tm.tm_gmtoff)\n        int total_minutes = os::utc_minutes_offset(tm_time);\n#endif\n        bool is_negative = total_minutes < 0;\n        char sign;\n        if (is_negative)\n        {\n            total_minutes = -total_minutes;\n            sign = '-';\n        }\n        else\n        {\n            sign = '+';\n        }\n\n        int h = total_minutes / 60;\n        int m = total_minutes % 60;\n        msg.formatted << sign;\n        pad_n_join(msg.formatted, h, m, ':');\n    }\n\nprivate:\n    log_clock::time_point _last_update{std::chrono::seconds(0)};\n    int _offset_minutes{0};\n    std::mutex _mutex;\n\n    int get_cached_offset(const log_msg &msg, const std::tm &tm_time)\n    {\n        std::lock_guard<std::mutex> l(_mutex);\n        if (msg.time - _last_update >= cache_refresh)\n        {\n            _offset_minutes = os::utc_minutes_offset(tm_time);\n            _last_update = msg.time;\n        }\n        return _offset_minutes;\n    }\n};\n\n// Thread id\nclass t_formatter SPDLOG_FINAL : public flag_formatter\n{\n    void format(details::log_msg &msg, const std::tm &) override\n    {\n        msg.formatted << msg.thread_id;\n    }\n};\n\n// Current pid\nclass pid_formatter SPDLOG_FINAL : public flag_formatter\n{\n    void format(details::log_msg &msg, const std::tm &) override\n    {\n        msg.formatted << details::os::pid();\n    }\n};\n\n// message counter formatter\nclass i_formatter SPDLOG_FINAL : public flag_formatter\n{\n    void format(details::log_msg &msg, const std::tm &) override\n    {\n        msg.formatted << fmt::pad(msg.msg_id, 6, '0');\n    }\n};\n\nclass v_formatter SPDLOG_FINAL : public flag_formatter\n{\n    void format(details::log_msg &msg, const std::tm &) override\n    {\n        msg.formatted << fmt::StringRef(msg.raw.data(), msg.raw.size());\n    }\n};\n\nclass ch_formatter SPDLOG_FINAL : public flag_formatter\n{\npublic:\n    explicit ch_formatter(char ch)\n        : _ch(ch)\n    {\n    }\n    void format(details::log_msg &msg, const std::tm &) override\n    {\n        msg.formatted << _ch;\n    }\n\nprivate:\n    char _ch;\n};\n\n// aggregate user chars to display as is\nclass aggregate_formatter SPDLOG_FINAL : public flag_formatter\n{\npublic:\n    aggregate_formatter() = default;\n\n    void add_ch(char ch)\n    {\n        _str += ch;\n    }\n    void format(details::log_msg &msg, const std::tm &) override\n    {\n        msg.formatted << _str;\n    }\n\nprivate:\n    std::string _str;\n};\n\n// mark the color range. expect it to be in the form of \"%^colored text%$\"\nclass color_start_formatter SPDLOG_FINAL : public flag_formatter\n{\n    void format(details::log_msg &msg, const std::tm &) override\n    {\n        msg.color_range_start = msg.formatted.size();\n    }\n};\nclass color_stop_formatter SPDLOG_FINAL : public flag_formatter\n{\n    void format(details::log_msg &msg, const std::tm &) override\n    {\n        msg.color_range_end = msg.formatted.size();\n    }\n};\n\n// Full info formatter\n// pattern: [%Y-%m-%d %H:%M:%S.%e] [%n] [%l] %v\nclass full_formatter SPDLOG_FINAL : public flag_formatter\n{\n    void format(details::log_msg &msg, const std::tm &tm_time) override\n    {\n#ifndef SPDLOG_NO_DATETIME\n        auto duration = msg.time.time_since_epoch();\n        auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count() % 1000;\n\n        /* Slower version(while still very fast - about 3.2 million lines/sec under 10 threads),\n        msg.formatted.write(\"[{:d}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}.{:03d}] [{}] [{}] {} \",\n        tm_time.tm_year + 1900,\n        tm_time.tm_mon + 1,\n        tm_time.tm_mday,\n        tm_time.tm_hour,\n        tm_time.tm_min,\n        tm_time.tm_sec,\n        static_cast<int>(millis),\n        msg.logger_name,\n        level::to_str(msg.level),\n        msg.raw.str());*/\n\n        // Faster (albeit uglier) way to format the line (5.6 million lines/sec under 10 threads)\n        msg.formatted << '[' << static_cast<unsigned int>(tm_time.tm_year + 1900) << '-'\n                      << fmt::pad(static_cast<unsigned int>(tm_time.tm_mon + 1), 2, '0') << '-'\n                      << fmt::pad(static_cast<unsigned int>(tm_time.tm_mday), 2, '0') << ' '\n                      << fmt::pad(static_cast<unsigned int>(tm_time.tm_hour), 2, '0') << ':'\n                      << fmt::pad(static_cast<unsigned int>(tm_time.tm_min), 2, '0') << ':'\n                      << fmt::pad(static_cast<unsigned int>(tm_time.tm_sec), 2, '0') << '.'\n                      << fmt::pad(static_cast<unsigned int>(millis), 3, '0') << \"] \";\n\n        // no datetime needed\n#else\n        (void)tm_time;\n#endif\n\n#ifndef SPDLOG_NO_NAME\n        msg.formatted << '[' << *msg.logger_name << \"] \";\n#endif\n\n        msg.formatted << '[';\n        // wrap the level name with color\n        msg.color_range_start = msg.formatted.size();\n        msg.formatted << level::to_str(msg.level);\n        msg.color_range_end = msg.formatted.size();\n        msg.formatted << \"] \" << fmt::StringRef(msg.raw.data(), msg.raw.size());\n    }\n};\n\n} // namespace details\n} // namespace spdlog\n///////////////////////////////////////////////////////////////////////////////\n// pattern_formatter inline impl\n///////////////////////////////////////////////////////////////////////////////\ninline spdlog::pattern_formatter::pattern_formatter(const std::string &pattern, pattern_time_type pattern_time, std::string eol)\n    : _eol(std::move(eol))\n    , _pattern_time(pattern_time)\n{\n    compile_pattern(pattern);\n}\n\ninline void spdlog::pattern_formatter::compile_pattern(const std::string &pattern)\n{\n    auto end = pattern.end();\n    std::unique_ptr<details::aggregate_formatter> user_chars;\n    for (auto it = pattern.begin(); it != end; ++it)\n    {\n        if (*it == '%')\n        {\n            if (user_chars) // append user chars found so far\n            {\n                _formatters.push_back(std::move(user_chars));\n            }\n            // if(\n            if (++it != end)\n            {\n                handle_flag(*it);\n            }\n            else\n            {\n                break;\n            }\n        }\n        else // chars not following the % sign should be displayed as is\n        {\n            if (!user_chars)\n            {\n                user_chars = std::unique_ptr<details::aggregate_formatter>(new details::aggregate_formatter());\n            }\n            user_chars->add_ch(*it);\n        }\n    }\n    if (user_chars) // append raw chars found so far\n    {\n        _formatters.push_back(std::move(user_chars));\n    }\n}\ninline void spdlog::pattern_formatter::handle_flag(char flag)\n{\n    switch (flag)\n    {\n    // logger name\n    case 'n':\n        _formatters.emplace_back(new details::name_formatter());\n        break;\n\n    case 'l':\n        _formatters.emplace_back(new details::level_formatter());\n        break;\n\n    case 'L':\n        _formatters.emplace_back(new details::short_level_formatter());\n        break;\n\n    case ('t'):\n        _formatters.emplace_back(new details::t_formatter());\n        break;\n\n    case ('v'):\n        _formatters.emplace_back(new details::v_formatter());\n        break;\n\n    case ('a'):\n        _formatters.emplace_back(new details::a_formatter());\n        break;\n\n    case ('A'):\n        _formatters.emplace_back(new details::A_formatter());\n        break;\n\n    case ('b'):\n    case ('h'):\n        _formatters.emplace_back(new details::b_formatter());\n        break;\n\n    case ('B'):\n        _formatters.emplace_back(new details::B_formatter());\n        break;\n    case ('c'):\n        _formatters.emplace_back(new details::c_formatter());\n        break;\n\n    case ('C'):\n        _formatters.emplace_back(new details::C_formatter());\n        break;\n\n    case ('Y'):\n        _formatters.emplace_back(new details::Y_formatter());\n        break;\n\n    case ('D'):\n    case ('x'):\n\n        _formatters.emplace_back(new details::D_formatter());\n        break;\n\n    case ('m'):\n        _formatters.emplace_back(new details::m_formatter());\n        break;\n\n    case ('d'):\n        _formatters.emplace_back(new details::d_formatter());\n        break;\n\n    case ('H'):\n        _formatters.emplace_back(new details::H_formatter());\n        break;\n\n    case ('I'):\n        _formatters.emplace_back(new details::I_formatter());\n        break;\n\n    case ('M'):\n        _formatters.emplace_back(new details::M_formatter());\n        break;\n\n    case ('S'):\n        _formatters.emplace_back(new details::S_formatter());\n        break;\n\n    case ('e'):\n        _formatters.emplace_back(new details::e_formatter());\n        break;\n\n    case ('f'):\n        _formatters.emplace_back(new details::f_formatter());\n        break;\n    case ('F'):\n        _formatters.emplace_back(new details::F_formatter());\n        break;\n\n    case ('E'):\n        _formatters.emplace_back(new details::E_formatter());\n        break;\n\n    case ('p'):\n        _formatters.emplace_back(new details::p_formatter());\n        break;\n\n    case ('r'):\n        _formatters.emplace_back(new details::r_formatter());\n        break;\n\n    case ('R'):\n        _formatters.emplace_back(new details::R_formatter());\n        break;\n\n    case ('T'):\n    case ('X'):\n        _formatters.emplace_back(new details::T_formatter());\n        break;\n\n    case ('z'):\n        _formatters.emplace_back(new details::z_formatter());\n        break;\n\n    case ('+'):\n        _formatters.emplace_back(new details::full_formatter());\n        break;\n\n    case ('P'):\n        _formatters.emplace_back(new details::pid_formatter());\n        break;\n\n    case ('i'):\n        _formatters.emplace_back(new details::i_formatter());\n        break;\n\n    case ('^'):\n        _formatters.emplace_back(new details::color_start_formatter());\n        break;\n\n    case ('$'):\n        _formatters.emplace_back(new details::color_stop_formatter());\n        break;\n\n    default: // Unknown flag appears as is\n        _formatters.emplace_back(new details::ch_formatter('%'));\n        _formatters.emplace_back(new details::ch_formatter(flag));\n        break;\n    }\n}\n\ninline std::tm spdlog::pattern_formatter::get_time(details::log_msg &msg)\n{\n    if (_pattern_time == pattern_time_type::local)\n    {\n        return details::os::localtime(log_clock::to_time_t(msg.time));\n    }\n    return details::os::gmtime(log_clock::to_time_t(msg.time));\n}\n\ninline void spdlog::pattern_formatter::format(details::log_msg &msg)\n{\n\n#ifndef SPDLOG_NO_DATETIME\n    auto tm_time = get_time(msg);\n#else\n    std::tm tm_time;\n#endif\n    for (auto &f : _formatters)\n    {\n        f->format(msg, tm_time);\n    }\n    // write eol\n    msg.formatted << _eol;\n}\n"
  },
  {
    "path": "spdlog/details/registry.h",
    "content": "//\n// Copyright(c) 2015 Gabi Melman.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n//\n\n#pragma once\n\n// Loggers registy of unique name->logger pointer\n// An attempt to create a logger with an already existing name will be ignored\n// If user requests a non existing logger, nullptr will be returned\n// This class is thread safe\n\n#include \"../async_logger.h\"\n#include \"../common.h\"\n#include \"../details/null_mutex.h\"\n#include \"../logger.h\"\n\n#include <chrono>\n#include <functional>\n#include <memory>\n#include <mutex>\n#include <string>\n#include <unordered_map>\n\nnamespace spdlog {\nnamespace details {\ntemplate<class Mutex>\nclass registry_t\n{\npublic:\n    registry_t<Mutex>(const registry_t<Mutex> &) = delete;\n    registry_t<Mutex> &operator=(const registry_t<Mutex> &) = delete;\n\n    void register_logger(std::shared_ptr<logger> logger)\n    {\n        std::lock_guard<Mutex> lock(_mutex);\n        auto logger_name = logger->name();\n        throw_if_exists(logger_name);\n        _loggers[logger_name] = logger;\n    }\n\n    std::shared_ptr<logger> get(const std::string &logger_name)\n    {\n        std::lock_guard<Mutex> lock(_mutex);\n        auto found = _loggers.find(logger_name);\n        return found == _loggers.end() ? nullptr : found->second;\n    }\n\n    template<class It>\n    std::shared_ptr<logger> create(const std::string &logger_name, const It &sinks_begin, const It &sinks_end)\n    {\n        std::lock_guard<Mutex> lock(_mutex);\n        throw_if_exists(logger_name);\n        std::shared_ptr<logger> new_logger;\n        if (_async_mode)\n        {\n            new_logger = std::make_shared<async_logger>(logger_name, sinks_begin, sinks_end, _async_q_size, _overflow_policy,\n                _worker_warmup_cb, _flush_interval_ms, _worker_teardown_cb);\n        }\n        else\n        {\n            new_logger = std::make_shared<logger>(logger_name, sinks_begin, sinks_end);\n        }\n\n        if (_formatter)\n        {\n            new_logger->set_formatter(_formatter);\n        }\n\n        if (_err_handler)\n        {\n            new_logger->set_error_handler(_err_handler);\n        }\n\n        new_logger->set_level(_level);\n        new_logger->flush_on(_flush_level);\n\n        // Add to registry\n        _loggers[logger_name] = new_logger;\n        return new_logger;\n    }\n\n    template<class It>\n    std::shared_ptr<async_logger> create_async(const std::string &logger_name, size_t queue_size,\n        const async_overflow_policy overflow_policy, const std::function<void()> &worker_warmup_cb,\n        const std::chrono::milliseconds &flush_interval_ms, const std::function<void()> &worker_teardown_cb, const It &sinks_begin,\n        const It &sinks_end)\n    {\n        std::lock_guard<Mutex> lock(_mutex);\n        throw_if_exists(logger_name);\n        auto new_logger = std::make_shared<async_logger>(\n            logger_name, sinks_begin, sinks_end, queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms, worker_teardown_cb);\n\n        if (_formatter)\n        {\n            new_logger->set_formatter(_formatter);\n        }\n\n        if (_err_handler)\n        {\n            new_logger->set_error_handler(_err_handler);\n        }\n\n        new_logger->set_level(_level);\n        new_logger->flush_on(_flush_level);\n\n        // Add to registry\n        _loggers[logger_name] = new_logger;\n        return new_logger;\n    }\n\n    void apply_all(std::function<void(std::shared_ptr<logger>)> fun)\n    {\n        std::lock_guard<Mutex> lock(_mutex);\n        for (auto &l : _loggers)\n        {\n            fun(l.second);\n        }\n    }\n\n    void drop(const std::string &logger_name)\n    {\n        std::lock_guard<Mutex> lock(_mutex);\n        _loggers.erase(logger_name);\n    }\n\n    void drop_all()\n    {\n        std::lock_guard<Mutex> lock(_mutex);\n        _loggers.clear();\n    }\n\n    std::shared_ptr<logger> create(const std::string &logger_name, sinks_init_list sinks)\n    {\n        return create(logger_name, sinks.begin(), sinks.end());\n    }\n\n    std::shared_ptr<logger> create(const std::string &logger_name, sink_ptr sink)\n    {\n        return create(logger_name, {sink});\n    }\n\n    std::shared_ptr<async_logger> create_async(const std::string &logger_name, size_t queue_size,\n        const async_overflow_policy overflow_policy, const std::function<void()> &worker_warmup_cb,\n        const std::chrono::milliseconds &flush_interval_ms, const std::function<void()> &worker_teardown_cb, sinks_init_list sinks)\n    {\n        return create_async(\n            logger_name, queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms, worker_teardown_cb, sinks.begin(), sinks.end());\n    }\n\n    std::shared_ptr<async_logger> create_async(const std::string &logger_name, size_t queue_size,\n        const async_overflow_policy overflow_policy, const std::function<void()> &worker_warmup_cb,\n        const std::chrono::milliseconds &flush_interval_ms, const std::function<void()> &worker_teardown_cb, sink_ptr sink)\n    {\n        return create_async(logger_name, queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms, worker_teardown_cb, {sink});\n    }\n\n    void formatter(formatter_ptr f)\n    {\n        std::lock_guard<Mutex> lock(_mutex);\n        _formatter = f;\n        for (auto &l : _loggers)\n        {\n            l.second->set_formatter(_formatter);\n        }\n    }\n\n    void set_pattern(const std::string &pattern)\n    {\n        std::lock_guard<Mutex> lock(_mutex);\n        _formatter = std::make_shared<pattern_formatter>(pattern);\n        for (auto &l : _loggers)\n        {\n            l.second->set_formatter(_formatter);\n        }\n    }\n\n    void set_level(level::level_enum log_level)\n    {\n        std::lock_guard<Mutex> lock(_mutex);\n        for (auto &l : _loggers)\n        {\n            l.second->set_level(log_level);\n        }\n        _level = log_level;\n    }\n\n    void flush_on(level::level_enum log_level)\n    {\n        std::lock_guard<Mutex> lock(_mutex);\n        for (auto &l : _loggers)\n        {\n            l.second->flush_on(log_level);\n        }\n        _flush_level = log_level;\n    }\n\n    void set_error_handler(log_err_handler handler)\n    {\n        for (auto &l : _loggers)\n        {\n            l.second->set_error_handler(handler);\n        }\n        _err_handler = handler;\n    }\n\n    void set_async_mode(size_t q_size, const async_overflow_policy overflow_policy, const std::function<void()> &worker_warmup_cb,\n        const std::chrono::milliseconds &flush_interval_ms, const std::function<void()> &worker_teardown_cb)\n    {\n        std::lock_guard<Mutex> lock(_mutex);\n        _async_mode = true;\n        _async_q_size = q_size;\n        _overflow_policy = overflow_policy;\n        _worker_warmup_cb = worker_warmup_cb;\n        _flush_interval_ms = flush_interval_ms;\n        _worker_teardown_cb = worker_teardown_cb;\n    }\n\n    void set_sync_mode()\n    {\n        std::lock_guard<Mutex> lock(_mutex);\n        _async_mode = false;\n    }\n\n    static registry_t<Mutex> &instance()\n    {\n        static registry_t<Mutex> s_instance;\n        return s_instance;\n    }\n\nprivate:\n    registry_t<Mutex>() = default;\n\n    void throw_if_exists(const std::string &logger_name)\n    {\n        if (_loggers.find(logger_name) != _loggers.end())\n        {\n            throw spdlog_ex(\"logger with name '\" + logger_name + \"' already exists\");\n        }\n    }\n\n    Mutex _mutex;\n    std::unordered_map<std::string, std::shared_ptr<logger>> _loggers;\n    formatter_ptr _formatter;\n    level::level_enum _level = level::info;\n    level::level_enum _flush_level = level::off;\n    log_err_handler _err_handler;\n    bool _async_mode = false;\n    size_t _async_q_size = 0;\n    async_overflow_policy _overflow_policy = async_overflow_policy::block_retry;\n    std::function<void()> _worker_warmup_cb;\n    std::chrono::milliseconds _flush_interval_ms{std::chrono::milliseconds::zero()};\n    std::function<void()> _worker_teardown_cb;\n};\n\n#ifdef SPDLOG_NO_REGISTRY_MUTEX\nusing registry = registry_t<spdlog::details::null_mutex>;\n#else\nusing registry = registry_t<std::mutex>;\n#endif\n\n} // namespace details\n} // namespace spdlog\n"
  },
  {
    "path": "spdlog/details/spdlog_impl.h",
    "content": "//\n// Copyright(c) 2015 Gabi Melman.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n//\n\n#pragma once\n\n//\n// Global registry functions\n//\n#include \"../details/registry.h\"\n#include \"../sinks/file_sinks.h\"\n#include \"../sinks/stdout_sinks.h\"\n#include \"../spdlog.h\"\n#ifdef SPDLOG_ENABLE_SYSLOG\n#include \"../sinks/syslog_sink.h\"\n#endif\n\n#if defined _WIN32 && !defined(__cplusplus_winrt)\n#include \"../sinks/wincolor_sink.h\"\n#else\n#include \"../sinks/ansicolor_sink.h\"\n#endif\n\n#ifdef __ANDROID__\n#include \"../sinks/android_sink.h\"\n#endif\n\n#include <chrono>\n#include <functional>\n#include <memory>\n#include <string>\n\ninline void spdlog::register_logger(std::shared_ptr<logger> logger)\n{\n    return details::registry::instance().register_logger(std::move(logger));\n}\n\ninline std::shared_ptr<spdlog::logger> spdlog::get(const std::string &name)\n{\n    return details::registry::instance().get(name);\n}\n\ninline void spdlog::drop(const std::string &name)\n{\n    details::registry::instance().drop(name);\n}\n\n// Create multi/single threaded simple file logger\ninline std::shared_ptr<spdlog::logger> spdlog::basic_logger_mt(const std::string &logger_name, const filename_t &filename, bool truncate)\n{\n    return create<spdlog::sinks::simple_file_sink_mt>(logger_name, filename, truncate);\n}\n\ninline std::shared_ptr<spdlog::logger> spdlog::basic_logger_st(const std::string &logger_name, const filename_t &filename, bool truncate)\n{\n    return create<spdlog::sinks::simple_file_sink_st>(logger_name, filename, truncate);\n}\n\n// Create multi/single threaded rotating file logger\ninline std::shared_ptr<spdlog::logger> spdlog::rotating_logger_mt(\n    const std::string &logger_name, const filename_t &filename, size_t max_file_size, size_t max_files)\n{\n    return create<spdlog::sinks::rotating_file_sink_mt>(logger_name, filename, max_file_size, max_files);\n}\n\ninline std::shared_ptr<spdlog::logger> spdlog::rotating_logger_st(\n    const std::string &logger_name, const filename_t &filename, size_t max_file_size, size_t max_files)\n{\n    return create<spdlog::sinks::rotating_file_sink_st>(logger_name, filename, max_file_size, max_files);\n}\n\n// Create file logger which creates new file at midnight):\ninline std::shared_ptr<spdlog::logger> spdlog::daily_logger_mt(\n    const std::string &logger_name, const filename_t &filename, int hour, int minute)\n{\n    return create<spdlog::sinks::daily_file_sink_mt>(logger_name, filename, hour, minute);\n}\n\ninline std::shared_ptr<spdlog::logger> spdlog::daily_logger_st(\n    const std::string &logger_name, const filename_t &filename, int hour, int minute)\n{\n    return create<spdlog::sinks::daily_file_sink_st>(logger_name, filename, hour, minute);\n}\n\n//\n// stdout/stderr loggers\n//\ninline std::shared_ptr<spdlog::logger> spdlog::stdout_logger_mt(const std::string &logger_name)\n{\n    return spdlog::details::registry::instance().create(logger_name, spdlog::sinks::stdout_sink_mt::instance());\n}\n\ninline std::shared_ptr<spdlog::logger> spdlog::stdout_logger_st(const std::string &logger_name)\n{\n    return spdlog::details::registry::instance().create(logger_name, spdlog::sinks::stdout_sink_st::instance());\n}\n\ninline std::shared_ptr<spdlog::logger> spdlog::stderr_logger_mt(const std::string &logger_name)\n{\n    return spdlog::details::registry::instance().create(logger_name, spdlog::sinks::stderr_sink_mt::instance());\n}\n\ninline std::shared_ptr<spdlog::logger> spdlog::stderr_logger_st(const std::string &logger_name)\n{\n    return spdlog::details::registry::instance().create(logger_name, spdlog::sinks::stderr_sink_st::instance());\n}\n\n//\n// stdout/stderr color loggers\n//\n#if defined _WIN32 && !defined(__cplusplus_winrt)\n\ninline std::shared_ptr<spdlog::logger> spdlog::stdout_color_mt(const std::string &logger_name)\n{\n    auto sink = std::make_shared<spdlog::sinks::wincolor_stdout_sink_mt>();\n    return spdlog::details::registry::instance().create(logger_name, sink);\n}\n\ninline std::shared_ptr<spdlog::logger> spdlog::stdout_color_st(const std::string &logger_name)\n{\n    auto sink = std::make_shared<spdlog::sinks::wincolor_stdout_sink_st>();\n    return spdlog::details::registry::instance().create(logger_name, sink);\n}\n\ninline std::shared_ptr<spdlog::logger> spdlog::stderr_color_mt(const std::string &logger_name)\n{\n    auto sink = std::make_shared<spdlog::sinks::wincolor_stderr_sink_mt>();\n    return spdlog::details::registry::instance().create(logger_name, sink);\n}\n\ninline std::shared_ptr<spdlog::logger> spdlog::stderr_color_st(const std::string &logger_name)\n{\n    auto sink = std::make_shared<spdlog::sinks::wincolor_stderr_sink_st>();\n    return spdlog::details::registry::instance().create(logger_name, sink);\n}\n\n#else // ansi terminal colors\n\ninline std::shared_ptr<spdlog::logger> spdlog::stdout_color_mt(const std::string &logger_name)\n{\n    auto sink = std::make_shared<spdlog::sinks::ansicolor_stdout_sink_mt>();\n    return spdlog::details::registry::instance().create(logger_name, sink);\n}\n\ninline std::shared_ptr<spdlog::logger> spdlog::stdout_color_st(const std::string &logger_name)\n{\n    auto sink = std::make_shared<spdlog::sinks::ansicolor_stdout_sink_st>();\n    return spdlog::details::registry::instance().create(logger_name, sink);\n}\n\ninline std::shared_ptr<spdlog::logger> spdlog::stderr_color_mt(const std::string &logger_name)\n{\n    auto sink = std::make_shared<spdlog::sinks::ansicolor_stderr_sink_mt>();\n    return spdlog::details::registry::instance().create(logger_name, sink);\n}\n\ninline std::shared_ptr<spdlog::logger> spdlog::stderr_color_st(const std::string &logger_name)\n{\n    auto sink = std::make_shared<spdlog::sinks::ansicolor_stderr_sink_st>();\n    return spdlog::details::registry::instance().create(logger_name, sink);\n}\n#endif\n\n#ifdef SPDLOG_ENABLE_SYSLOG\n// Create syslog logger\ninline std::shared_ptr<spdlog::logger> spdlog::syslog_logger(\n    const std::string &logger_name, const std::string &syslog_ident, int syslog_option, int syslog_facility)\n{\n    return create<spdlog::sinks::syslog_sink>(logger_name, syslog_ident, syslog_option, syslog_facility);\n}\n#endif\n\n#ifdef __ANDROID__\ninline std::shared_ptr<spdlog::logger> spdlog::android_logger(const std::string &logger_name, const std::string &tag)\n{\n    return create<spdlog::sinks::android_sink>(logger_name, tag);\n}\n#endif\n\n// Create and register a logger a single sink\ninline std::shared_ptr<spdlog::logger> spdlog::create(const std::string &logger_name, const spdlog::sink_ptr &sink)\n{\n    return details::registry::instance().create(logger_name, sink);\n}\n\n// Create logger with multiple sinks\ninline std::shared_ptr<spdlog::logger> spdlog::create(const std::string &logger_name, spdlog::sinks_init_list sinks)\n{\n    return details::registry::instance().create(logger_name, sinks);\n}\n\ntemplate<typename Sink, typename... Args>\ninline std::shared_ptr<spdlog::logger> spdlog::create(const std::string &logger_name, Args... args)\n{\n    sink_ptr sink = std::make_shared<Sink>(args...);\n    return details::registry::instance().create(logger_name, {sink});\n}\n\ntemplate<class It>\ninline std::shared_ptr<spdlog::logger> spdlog::create(const std::string &logger_name, const It &sinks_begin, const It &sinks_end)\n{\n    return details::registry::instance().create(logger_name, sinks_begin, sinks_end);\n}\n\n// Create and register an async logger with a single sink\ninline std::shared_ptr<spdlog::logger> spdlog::create_async(const std::string &logger_name, const sink_ptr &sink, size_t queue_size,\n    const async_overflow_policy overflow_policy, const std::function<void()> &worker_warmup_cb,\n    const std::chrono::milliseconds &flush_interval_ms, const std::function<void()> &worker_teardown_cb)\n{\n    return details::registry::instance().create_async(\n        logger_name, queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms, worker_teardown_cb, sink);\n}\n\n// Create and register an async logger with multiple sinks\ninline std::shared_ptr<spdlog::logger> spdlog::create_async(const std::string &logger_name, sinks_init_list sinks, size_t queue_size,\n    const async_overflow_policy overflow_policy, const std::function<void()> &worker_warmup_cb,\n    const std::chrono::milliseconds &flush_interval_ms, const std::function<void()> &worker_teardown_cb)\n{\n    return details::registry::instance().create_async(\n        logger_name, queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms, worker_teardown_cb, sinks);\n}\n\ntemplate<class It>\ninline std::shared_ptr<spdlog::logger> spdlog::create_async(const std::string &logger_name, const It &sinks_begin, const It &sinks_end,\n    size_t queue_size, const async_overflow_policy overflow_policy, const std::function<void()> &worker_warmup_cb,\n    const std::chrono::milliseconds &flush_interval_ms, const std::function<void()> &worker_teardown_cb)\n{\n    return details::registry::instance().create_async(\n        logger_name, queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms, worker_teardown_cb, sinks_begin, sinks_end);\n}\n\ninline void spdlog::set_formatter(spdlog::formatter_ptr f)\n{\n    details::registry::instance().formatter(std::move(f));\n}\n\ninline void spdlog::set_pattern(const std::string &format_string)\n{\n    return details::registry::instance().set_pattern(format_string);\n}\n\ninline void spdlog::set_level(level::level_enum log_level)\n{\n    return details::registry::instance().set_level(log_level);\n}\n\ninline void spdlog::flush_on(level::level_enum log_level)\n{\n    return details::registry::instance().flush_on(log_level);\n}\n\ninline void spdlog::set_error_handler(log_err_handler handler)\n{\n    return details::registry::instance().set_error_handler(std::move(handler));\n}\n\ninline void spdlog::set_async_mode(size_t queue_size, const async_overflow_policy overflow_policy,\n    const std::function<void()> &worker_warmup_cb, const std::chrono::milliseconds &flush_interval_ms,\n    const std::function<void()> &worker_teardown_cb)\n{\n    details::registry::instance().set_async_mode(queue_size, overflow_policy, worker_warmup_cb, flush_interval_ms, worker_teardown_cb);\n}\n\ninline void spdlog::set_sync_mode()\n{\n    details::registry::instance().set_sync_mode();\n}\n\ninline void spdlog::apply_all(std::function<void(std::shared_ptr<logger>)> fun)\n{\n    details::registry::instance().apply_all(std::move(fun));\n}\n\ninline void spdlog::drop_all()\n{\n    details::registry::instance().drop_all();\n}\n"
  },
  {
    "path": "spdlog/fmt/bundled/LICENSE.rst",
    "content": "Copyright (c) 2012 - 2016, Victor Zverovich\n\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this\n   list of conditions and the following disclaimer.\n2. Redistributions in binary form must reproduce the above copyright notice,\n   this list of conditions and the following disclaimer in the documentation\n   and/or other materials provided with the distribution.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\nANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR\nANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\nLOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\nON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\nSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "spdlog/fmt/bundled/format.cc",
    "content": "/*\n Formatting library for C++\n\n Copyright (c) 2012 - 2016, Victor Zverovich\n All rights reserved.\n\n Redistribution and use in source and binary forms, with or without\n modification, are permitted provided that the following conditions are met:\n\n 1. Redistributions of source code must retain the above copyright notice, this\n    list of conditions and the following disclaimer.\n 2. Redistributions in binary form must reproduce the above copyright notice,\n    this list of conditions and the following disclaimer in the documentation\n    and/or other materials provided with the distribution.\n\n THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR\n ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n#include \"format.h\"\n\n#include <string.h>\n\n#include <cctype>\n#include <cerrno>\n#include <climits>\n#include <cmath>\n#include <cstdarg>\n#include <cstddef>  // for std::ptrdiff_t\n\n#if defined(_WIN32) && defined(__MINGW32__)\n# include <cstring>\n#endif\n\n#if FMT_USE_WINDOWS_H\n# if !defined(FMT_HEADER_ONLY) && !defined(WIN32_LEAN_AND_MEAN)\n#  define WIN32_LEAN_AND_MEAN\n# endif\n# if defined(NOMINMAX) || defined(FMT_WIN_MINMAX)\n#  include <windows.h>\n# else\n#  define NOMINMAX\n#  include <windows.h>\n#  undef NOMINMAX\n# endif\n#endif\n\n#if FMT_EXCEPTIONS\n# define FMT_TRY try\n# define FMT_CATCH(x) catch (x)\n#else\n# define FMT_TRY if (true)\n# define FMT_CATCH(x) if (false)\n#endif\n\n#ifdef _MSC_VER\n# pragma warning(push)\n# pragma warning(disable: 4127)  // conditional expression is constant\n# pragma warning(disable: 4702)  // unreachable code\n// Disable deprecation warning for strerror. The latter is not called but\n// MSVC fails to detect it.\n# pragma warning(disable: 4996)\n#endif\n\n// Dummy implementations of strerror_r and strerror_s called if corresponding\n// system functions are not available.\nFMT_MAYBE_UNUSED\nstatic inline fmt::internal::Null<> strerror_r(int, char *, ...) {\n  return fmt::internal::Null<>();\n}\nFMT_MAYBE_UNUSED\nstatic inline fmt::internal::Null<> strerror_s(char *, std::size_t, ...) {\n  return fmt::internal::Null<>();\n}\n\nnamespace fmt {\n\nFMT_FUNC internal::RuntimeError::~RuntimeError() FMT_DTOR_NOEXCEPT {}\nFMT_FUNC FormatError::~FormatError() FMT_DTOR_NOEXCEPT {}\nFMT_FUNC SystemError::~SystemError() FMT_DTOR_NOEXCEPT {}\n\nnamespace {\n\n#ifndef _MSC_VER\n# define FMT_SNPRINTF snprintf\n#else  // _MSC_VER\ninline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) {\n  va_list args;\n  va_start(args, format);\n  int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args);\n  va_end(args);\n  return result;\n}\n# define FMT_SNPRINTF fmt_snprintf\n#endif  // _MSC_VER\n\n#if defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)\n# define FMT_SWPRINTF snwprintf\n#else\n# define FMT_SWPRINTF swprintf\n#endif // defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT)\n\nconst char RESET_COLOR[] = \"\\x1b[0m\";\n\ntypedef void (*FormatFunc)(Writer &, int, StringRef);\n\n// Portable thread-safe version of strerror.\n// Sets buffer to point to a string describing the error code.\n// This can be either a pointer to a string stored in buffer,\n// or a pointer to some static immutable string.\n// Returns one of the following values:\n//   0      - success\n//   ERANGE - buffer is not large enough to store the error message\n//   other  - failure\n// Buffer should be at least of size 1.\nint safe_strerror(\n    int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT {\n  FMT_ASSERT(buffer != FMT_NULL && buffer_size != 0, \"invalid buffer\");\n\n  class StrError {\n   private:\n    int error_code_;\n    char *&buffer_;\n    std::size_t buffer_size_;\n\n    // A noop assignment operator to avoid bogus warnings.\n    void operator=(const StrError &) {}\n\n    // Handle the result of XSI-compliant version of strerror_r.\n    int handle(int result) {\n      // glibc versions before 2.13 return result in errno.\n      return result == -1 ? errno : result;\n    }\n\n    // Handle the result of GNU-specific version of strerror_r.\n    int handle(char *message) {\n      // If the buffer is full then the message is probably truncated.\n      if (message == buffer_ && strlen(buffer_) == buffer_size_ - 1)\n        return ERANGE;\n      buffer_ = message;\n      return 0;\n    }\n\n    // Handle the case when strerror_r is not available.\n    int handle(internal::Null<>) {\n      return fallback(strerror_s(buffer_, buffer_size_, error_code_));\n    }\n\n    // Fallback to strerror_s when strerror_r is not available.\n    int fallback(int result) {\n      // If the buffer is full then the message is probably truncated.\n      return result == 0 && strlen(buffer_) == buffer_size_ - 1 ?\n            ERANGE : result;\n    }\n\n#ifdef __c2__\n# pragma clang diagnostic push\n# pragma clang diagnostic ignored \"-Wdeprecated-declarations\"\n#endif\n\n    // Fallback to strerror if strerror_r and strerror_s are not available.\n    int fallback(internal::Null<>) {\n      errno = 0;\n      buffer_ = strerror(error_code_);\n      return errno;\n    }\n\n#ifdef __c2__\n# pragma clang diagnostic pop\n#endif\n\n   public:\n    StrError(int err_code, char *&buf, std::size_t buf_size)\n      : error_code_(err_code), buffer_(buf), buffer_size_(buf_size) {}\n\n    int run() {\n      return handle(strerror_r(error_code_, buffer_, buffer_size_));\n    }\n  };\n  return StrError(error_code, buffer, buffer_size).run();\n}\n\nvoid format_error_code(Writer &out, int error_code,\n                       StringRef message) FMT_NOEXCEPT {\n  // Report error code making sure that the output fits into\n  // INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential\n  // bad_alloc.\n  out.clear();\n  static const char SEP[] = \": \";\n  static const char ERROR_STR[] = \"error \";\n  // Subtract 2 to account for terminating null characters in SEP and ERROR_STR.\n  std::size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2;\n  typedef internal::IntTraits<int>::MainType MainType;\n  MainType abs_value = static_cast<MainType>(error_code);\n  if (internal::is_negative(error_code)) {\n    abs_value = 0 - abs_value;\n    ++error_code_size;\n  }\n  error_code_size += internal::count_digits(abs_value);\n  if (message.size() <= internal::INLINE_BUFFER_SIZE - error_code_size)\n    out << message << SEP;\n  out << ERROR_STR << error_code;\n  assert(out.size() <= internal::INLINE_BUFFER_SIZE);\n}\n\nvoid report_error(FormatFunc func, int error_code,\n                  StringRef message) FMT_NOEXCEPT {\n  MemoryWriter full_message;\n  func(full_message, error_code, message);\n  // Use Writer::data instead of Writer::c_str to avoid potential memory\n  // allocation.\n  std::fwrite(full_message.data(), full_message.size(), 1, stderr);\n  std::fputc('\\n', stderr);\n}\n}  // namespace\n\nFMT_FUNC void SystemError::init(\n    int err_code, CStringRef format_str, ArgList args) {\n  error_code_ = err_code;\n  MemoryWriter w;\n  format_system_error(w, err_code, format(format_str, args));\n  std::runtime_error &base = *this;\n  base = std::runtime_error(w.str());\n}\n\ntemplate <typename T>\nint internal::CharTraits<char>::format_float(\n    char *buffer, std::size_t size, const char *format,\n    unsigned width, int precision, T value) {\n  if (width == 0) {\n    return precision < 0 ?\n        FMT_SNPRINTF(buffer, size, format, value) :\n        FMT_SNPRINTF(buffer, size, format, precision, value);\n  }\n  return precision < 0 ?\n      FMT_SNPRINTF(buffer, size, format, width, value) :\n      FMT_SNPRINTF(buffer, size, format, width, precision, value);\n}\n\ntemplate <typename T>\nint internal::CharTraits<wchar_t>::format_float(\n    wchar_t *buffer, std::size_t size, const wchar_t *format,\n    unsigned width, int precision, T value) {\n  if (width == 0) {\n    return precision < 0 ?\n        FMT_SWPRINTF(buffer, size, format, value) :\n        FMT_SWPRINTF(buffer, size, format, precision, value);\n  }\n  return precision < 0 ?\n      FMT_SWPRINTF(buffer, size, format, width, value) :\n      FMT_SWPRINTF(buffer, size, format, width, precision, value);\n}\n\ntemplate <typename T>\nconst char internal::BasicData<T>::DIGITS[] =\n    \"0001020304050607080910111213141516171819\"\n    \"2021222324252627282930313233343536373839\"\n    \"4041424344454647484950515253545556575859\"\n    \"6061626364656667686970717273747576777879\"\n    \"8081828384858687888990919293949596979899\";\n\n#define FMT_POWERS_OF_10(factor) \\\n  factor * 10, \\\n  factor * 100, \\\n  factor * 1000, \\\n  factor * 10000, \\\n  factor * 100000, \\\n  factor * 1000000, \\\n  factor * 10000000, \\\n  factor * 100000000, \\\n  factor * 1000000000\n\ntemplate <typename T>\nconst uint32_t internal::BasicData<T>::POWERS_OF_10_32[] = {\n  0, FMT_POWERS_OF_10(1)\n};\n\ntemplate <typename T>\nconst uint64_t internal::BasicData<T>::POWERS_OF_10_64[] = {\n  0,\n  FMT_POWERS_OF_10(1),\n  FMT_POWERS_OF_10(ULongLong(1000000000)),\n  // Multiply several constants instead of using a single long long constant\n  // to avoid warnings about C++98 not supporting long long.\n  ULongLong(1000000000) * ULongLong(1000000000) * 10\n};\n\nFMT_FUNC void internal::report_unknown_type(char code, const char *type) {\n  (void)type;\n  if (std::isprint(static_cast<unsigned char>(code))) {\n    FMT_THROW(FormatError(\n        format(\"unknown format code '{}' for {}\", code, type)));\n  }\n  FMT_THROW(FormatError(\n      format(\"unknown format code '\\\\x{:02x}' for {}\",\n        static_cast<unsigned>(code), type)));\n}\n\n#if FMT_USE_WINDOWS_H\n\nFMT_FUNC internal::UTF8ToUTF16::UTF8ToUTF16(StringRef s) {\n  static const char ERROR_MSG[] = \"cannot convert string from UTF-8 to UTF-16\";\n  if (s.size() > INT_MAX)\n    FMT_THROW(WindowsError(ERROR_INVALID_PARAMETER, ERROR_MSG));\n  int s_size = static_cast<int>(s.size());\n  int length = MultiByteToWideChar(\n      CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, FMT_NULL, 0);\n  if (length == 0)\n    FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));\n  buffer_.resize(length + 1);\n  length = MultiByteToWideChar(\n    CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, &buffer_[0], length);\n  if (length == 0)\n    FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));\n  buffer_[length] = 0;\n}\n\nFMT_FUNC internal::UTF16ToUTF8::UTF16ToUTF8(WStringRef s) {\n  if (int error_code = convert(s)) {\n    FMT_THROW(WindowsError(error_code,\n        \"cannot convert string from UTF-16 to UTF-8\"));\n  }\n}\n\nFMT_FUNC int internal::UTF16ToUTF8::convert(WStringRef s) {\n  if (s.size() > INT_MAX)\n    return ERROR_INVALID_PARAMETER;\n  int s_size = static_cast<int>(s.size());\n  int length = WideCharToMultiByte(\n    CP_UTF8, 0, s.data(), s_size, FMT_NULL, 0, FMT_NULL, FMT_NULL);\n  if (length == 0)\n    return GetLastError();\n  buffer_.resize(length + 1);\n  length = WideCharToMultiByte(\n    CP_UTF8, 0, s.data(), s_size, &buffer_[0], length, FMT_NULL, FMT_NULL);\n  if (length == 0)\n    return GetLastError();\n  buffer_[length] = 0;\n  return 0;\n}\n\nFMT_FUNC void WindowsError::init(\n    int err_code, CStringRef format_str, ArgList args) {\n  error_code_ = err_code;\n  MemoryWriter w;\n  internal::format_windows_error(w, err_code, format(format_str, args));\n  std::runtime_error &base = *this;\n  base = std::runtime_error(w.str());\n}\n\nFMT_FUNC void internal::format_windows_error(\n    Writer &out, int error_code, StringRef message) FMT_NOEXCEPT {\n  FMT_TRY {\n    MemoryBuffer<wchar_t, INLINE_BUFFER_SIZE> buffer;\n    buffer.resize(INLINE_BUFFER_SIZE);\n    for (;;) {\n      wchar_t *system_message = &buffer[0];\n      int result = FormatMessageW(\n        FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,\n        FMT_NULL, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),\n        system_message, static_cast<uint32_t>(buffer.size()), FMT_NULL);\n      if (result != 0) {\n        UTF16ToUTF8 utf8_message;\n        if (utf8_message.convert(system_message) == ERROR_SUCCESS) {\n          out << message << \": \" << utf8_message;\n          return;\n        }\n        break;\n      }\n      if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)\n        break;  // Can't get error message, report error code instead.\n      buffer.resize(buffer.size() * 2);\n    }\n  } FMT_CATCH(...) {}\n  fmt::format_error_code(out, error_code, message);  // 'fmt::' is for bcc32.\n}\n\n#endif  // FMT_USE_WINDOWS_H\n\nFMT_FUNC void format_system_error(\n    Writer &out, int error_code, StringRef message) FMT_NOEXCEPT {\n  FMT_TRY {\n    internal::MemoryBuffer<char, internal::INLINE_BUFFER_SIZE> buffer;\n    buffer.resize(internal::INLINE_BUFFER_SIZE);\n    for (;;) {\n      char *system_message = &buffer[0];\n      int result = safe_strerror(error_code, system_message, buffer.size());\n      if (result == 0) {\n        out << message << \": \" << system_message;\n        return;\n      }\n      if (result != ERANGE)\n        break;  // Can't get error message, report error code instead.\n      buffer.resize(buffer.size() * 2);\n    }\n  } FMT_CATCH(...) {}\n  fmt::format_error_code(out, error_code, message);  // 'fmt::' is for bcc32.\n}\n\ntemplate <typename Char>\nvoid internal::FixedBuffer<Char>::grow(std::size_t) {\n  FMT_THROW(std::runtime_error(\"buffer overflow\"));\n}\n\nFMT_FUNC internal::Arg internal::FormatterBase::do_get_arg(\n    unsigned arg_index, const char *&error) {\n  internal::Arg arg = args_[arg_index];\n  switch (arg.type) {\n  case internal::Arg::NONE:\n    error = \"argument index out of range\";\n    break;\n  case internal::Arg::NAMED_ARG:\n    arg = *static_cast<const internal::Arg*>(arg.pointer);\n    break;\n  default:\n    /*nothing*/;\n  }\n  return arg;\n}\n\nFMT_FUNC void report_system_error(\n    int error_code, fmt::StringRef message) FMT_NOEXCEPT {\n  // 'fmt::' is for bcc32.\n  report_error(format_system_error, error_code, message);\n}\n\n#if FMT_USE_WINDOWS_H\nFMT_FUNC void report_windows_error(\n    int error_code, fmt::StringRef message) FMT_NOEXCEPT {\n  // 'fmt::' is for bcc32.\n  report_error(internal::format_windows_error, error_code, message);\n}\n#endif\n\nFMT_FUNC void print(std::FILE *f, CStringRef format_str, ArgList args) {\n  MemoryWriter w;\n  w.write(format_str, args);\n  std::fwrite(w.data(), 1, w.size(), f);\n}\n\nFMT_FUNC void print(CStringRef format_str, ArgList args) {\n  print(stdout, format_str, args);\n}\n\nFMT_FUNC void print_colored(Color c, CStringRef format, ArgList args) {\n  char escape[] = \"\\x1b[30m\";\n  escape[3] = static_cast<char>('0' + c);\n  std::fputs(escape, stdout);\n  print(format, args);\n  std::fputs(RESET_COLOR, stdout);\n}\n\n#ifndef FMT_HEADER_ONLY\n\ntemplate struct internal::BasicData<void>;\n\n// Explicit instantiations for char.\n\ntemplate void internal::FixedBuffer<char>::grow(std::size_t);\n\ntemplate FMT_API int internal::CharTraits<char>::format_float(\n    char *buffer, std::size_t size, const char *format,\n    unsigned width, int precision, double value);\n\ntemplate FMT_API int internal::CharTraits<char>::format_float(\n    char *buffer, std::size_t size, const char *format,\n    unsigned width, int precision, long double value);\n\n// Explicit instantiations for wchar_t.\n\ntemplate void internal::FixedBuffer<wchar_t>::grow(std::size_t);\n\ntemplate FMT_API int internal::CharTraits<wchar_t>::format_float(\n    wchar_t *buffer, std::size_t size, const wchar_t *format,\n    unsigned width, int precision, double value);\n\ntemplate FMT_API int internal::CharTraits<wchar_t>::format_float(\n    wchar_t *buffer, std::size_t size, const wchar_t *format,\n    unsigned width, int precision, long double value);\n\n#endif  // FMT_HEADER_ONLY\n\n}  // namespace fmt\n\n#ifdef _MSC_VER\n# pragma warning(pop)\n#endif\n"
  },
  {
    "path": "spdlog/fmt/bundled/format.h",
    "content": "/*\n Formatting library for C++\n\n Copyright (c) 2012 - 2016, Victor Zverovich\n All rights reserved.\n\n Redistribution and use in source and binary forms, with or without\n modification, are permitted provided that the following conditions are met:\n\n 1. Redistributions of source code must retain the above copyright notice, this\n    list of conditions and the following disclaimer.\n 2. Redistributions in binary form must reproduce the above copyright notice,\n    this list of conditions and the following disclaimer in the documentation\n    and/or other materials provided with the distribution.\n\n THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR\n ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n */\n\n#ifndef FMT_FORMAT_H_\n#define FMT_FORMAT_H_\n\n#define FMT_INCLUDE\n#include <cassert>\n#include <clocale>\n#include <cmath>\n#include <cstdio>\n#include <cstring>\n#include <limits>\n#include <memory>\n#include <stdexcept>\n#include <string>\n#include <utility> // for std::pair\n#include <vector>\n#undef FMT_INCLUDE\n\n// The fmt library version in the form major * 10000 + minor * 100 + patch.\n#define FMT_VERSION 40100\n\n#if defined(__has_include)\n#define FMT_HAS_INCLUDE(x) __has_include(x)\n#else\n#define FMT_HAS_INCLUDE(x) 0\n#endif\n\n#if (FMT_HAS_INCLUDE(<string_view>) && __cplusplus > 201402L) || (defined(_MSVC_LANG) && _MSVC_LANG > 201402L && _MSC_VER >= 1910)\n#include <string_view>\n#define FMT_HAS_STRING_VIEW 1\n#else\n#define FMT_HAS_STRING_VIEW 0\n#endif\n\n#if defined _SECURE_SCL && _SECURE_SCL\n#define FMT_SECURE_SCL _SECURE_SCL\n#else\n#define FMT_SECURE_SCL 0\n#endif\n\n#if FMT_SECURE_SCL\n#include <iterator>\n#endif\n\n#ifdef _MSC_VER\n#define FMT_MSC_VER _MSC_VER\n#else\n#define FMT_MSC_VER 0\n#endif\n\n#if FMT_MSC_VER && FMT_MSC_VER <= 1500\ntypedef unsigned __int32 uint32_t;\ntypedef unsigned __int64 uint64_t;\ntypedef __int64 intmax_t;\n#else\n#include <stdint.h>\n#endif\n\n#if !defined(FMT_HEADER_ONLY) && defined(_WIN32)\n#ifdef FMT_EXPORT\n#define FMT_API __declspec(dllexport)\n#elif defined(FMT_SHARED)\n#define FMT_API __declspec(dllimport)\n#endif\n#endif\n#ifndef FMT_API\n#define FMT_API\n#endif\n\n#ifdef __GNUC__\n#define FMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)\n#define FMT_GCC_EXTENSION __extension__\n#if FMT_GCC_VERSION >= 406\n#pragma GCC diagnostic push\n// Disable the warning about \"long long\" which is sometimes reported even\n// when using __extension__.\n#pragma GCC diagnostic ignored \"-Wlong-long\"\n// Disable the warning about declaration shadowing because it affects too\n// many valid cases.\n#pragma GCC diagnostic ignored \"-Wshadow\"\n// Disable the warning about implicit conversions that may change the sign of\n// an integer; silencing it otherwise would require many explicit casts.\n#pragma GCC diagnostic ignored \"-Wsign-conversion\"\n#endif\n#if __cplusplus >= 201103L || defined __GXX_EXPERIMENTAL_CXX0X__\n#define FMT_HAS_GXX_CXX11 1\n#endif\n#else\n#define FMT_GCC_VERSION 0\n#define FMT_GCC_EXTENSION\n#define FMT_HAS_GXX_CXX11 0\n#endif\n\n#if defined(__INTEL_COMPILER)\n#define FMT_ICC_VERSION __INTEL_COMPILER\n#elif defined(__ICL)\n#define FMT_ICC_VERSION __ICL\n#endif\n\n#if defined(__clang__) && !defined(FMT_ICC_VERSION)\n#define FMT_CLANG_VERSION (__clang_major__ * 100 + __clang_minor__)\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wdocumentation-unknown-command\"\n#pragma clang diagnostic ignored \"-Wpadded\"\n#endif\n\n#ifdef __GNUC_LIBSTD__\n#define FMT_GNUC_LIBSTD_VERSION (__GNUC_LIBSTD__ * 100 + __GNUC_LIBSTD_MINOR__)\n#endif\n\n#ifdef __has_feature\n#define FMT_HAS_FEATURE(x) __has_feature(x)\n#else\n#define FMT_HAS_FEATURE(x) 0\n#endif\n\n#ifdef __has_builtin\n#define FMT_HAS_BUILTIN(x) __has_builtin(x)\n#else\n#define FMT_HAS_BUILTIN(x) 0\n#endif\n\n#ifdef __has_cpp_attribute\n#define FMT_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x)\n#else\n#define FMT_HAS_CPP_ATTRIBUTE(x) 0\n#endif\n\n#if FMT_HAS_CPP_ATTRIBUTE(maybe_unused)\n#define FMT_HAS_CXX17_ATTRIBUTE_MAYBE_UNUSED\n// VC++ 1910 support /std: option and that will set _MSVC_LANG macro\n// Clang with Microsoft CodeGen doesn't define _MSVC_LANG macro\n#elif defined(_MSVC_LANG) && _MSVC_LANG > 201402 && _MSC_VER >= 1910\n#define FMT_HAS_CXX17_ATTRIBUTE_MAYBE_UNUSED\n#endif\n\n#ifdef FMT_HAS_CXX17_ATTRIBUTE_MAYBE_UNUSED\n#define FMT_MAYBE_UNUSED [[maybe_unused]]\n// g++/clang++ also support [[gnu::unused]]. However, we don't use it.\n#elif defined(__GNUC__)\n#define FMT_MAYBE_UNUSED __attribute__((unused))\n#else\n#define FMT_MAYBE_UNUSED\n#endif\n\n// Use the compiler's attribute noreturn\n#if defined(__MINGW32__) || defined(__MINGW64__)\n#define FMT_NORETURN __attribute__((noreturn))\n#elif FMT_HAS_CPP_ATTRIBUTE(noreturn) && __cplusplus >= 201103L\n#define FMT_NORETURN [[noreturn]]\n#else\n#define FMT_NORETURN\n#endif\n\n#ifndef FMT_USE_VARIADIC_TEMPLATES\n// Variadic templates are available in GCC since version 4.4\n// (http://gcc.gnu.org/projects/cxx0x.html) and in Visual C++\n// since version 2013.\n#define FMT_USE_VARIADIC_TEMPLATES                                                                                                         \\\n    (FMT_HAS_FEATURE(cxx_variadic_templates) || (FMT_GCC_VERSION >= 404 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1800)\n#endif\n\n#ifndef FMT_USE_RVALUE_REFERENCES\n// Don't use rvalue references when compiling with clang and an old libstdc++\n// as the latter doesn't provide std::move.\n#if defined(FMT_GNUC_LIBSTD_VERSION) && FMT_GNUC_LIBSTD_VERSION <= 402\n#define FMT_USE_RVALUE_REFERENCES 0\n#else\n#define FMT_USE_RVALUE_REFERENCES                                                                                                          \\\n    (FMT_HAS_FEATURE(cxx_rvalue_references) || (FMT_GCC_VERSION >= 403 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1600)\n#endif\n#endif\n\n#if __cplusplus >= 201103L || FMT_MSC_VER >= 1700\n#define FMT_USE_ALLOCATOR_TRAITS 1\n#else\n#define FMT_USE_ALLOCATOR_TRAITS 0\n#endif\n\n// Check if exceptions are disabled.\n#if defined(__GNUC__) && !defined(__EXCEPTIONS)\n#define FMT_EXCEPTIONS 0\n#endif\n#if FMT_MSC_VER && !_HAS_EXCEPTIONS\n#define FMT_EXCEPTIONS 0\n#endif\n#ifndef FMT_EXCEPTIONS\n#define FMT_EXCEPTIONS 1\n#endif\n\n#ifndef FMT_THROW\n#if FMT_EXCEPTIONS\n#define FMT_THROW(x) throw x\n#else\n#define FMT_THROW(x) assert(false)\n#endif\n#endif\n\n// Define FMT_USE_NOEXCEPT to make fmt use noexcept (C++11 feature).\n#ifndef FMT_USE_NOEXCEPT\n#define FMT_USE_NOEXCEPT 0\n#endif\n\n#if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1900\n#define FMT_DETECTED_NOEXCEPT noexcept\n#else\n#define FMT_DETECTED_NOEXCEPT throw()\n#endif\n\n#ifndef FMT_NOEXCEPT\n#if FMT_EXCEPTIONS\n#define FMT_NOEXCEPT FMT_DETECTED_NOEXCEPT\n#else\n#define FMT_NOEXCEPT\n#endif\n#endif\n\n// This is needed because GCC still uses throw() in its headers when exceptions\n// are disabled.\n#if FMT_GCC_VERSION\n#define FMT_DTOR_NOEXCEPT FMT_DETECTED_NOEXCEPT\n#else\n#define FMT_DTOR_NOEXCEPT FMT_NOEXCEPT\n#endif\n\n#ifndef FMT_OVERRIDE\n#if (defined(FMT_USE_OVERRIDE) && FMT_USE_OVERRIDE) || FMT_HAS_FEATURE(cxx_override) || (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) ||   \\\n    FMT_MSC_VER >= 1900\n#define FMT_OVERRIDE override\n#else\n#define FMT_OVERRIDE\n#endif\n#endif\n\n#ifndef FMT_NULL\n#if FMT_HAS_FEATURE(cxx_nullptr) || (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1600\n#define FMT_NULL nullptr\n#else\n#define FMT_NULL NULL\n#endif\n#endif\n\n// A macro to disallow the copy constructor and operator= functions\n// This should be used in the private: declarations for a class\n#ifndef FMT_USE_DELETED_FUNCTIONS\n#define FMT_USE_DELETED_FUNCTIONS 0\n#endif\n\n#if FMT_USE_DELETED_FUNCTIONS || FMT_HAS_FEATURE(cxx_deleted_functions) || (FMT_GCC_VERSION >= 404 && FMT_HAS_GXX_CXX11) ||                \\\n    FMT_MSC_VER >= 1800\n#define FMT_DELETED_OR_UNDEFINED = delete\n#define FMT_DISALLOW_COPY_AND_ASSIGN(TypeName)                                                                                             \\\n    TypeName(const TypeName &) = delete;                                                                                                   \\\n    TypeName &operator=(const TypeName &) = delete\n#else\n#define FMT_DELETED_OR_UNDEFINED\n#define FMT_DISALLOW_COPY_AND_ASSIGN(TypeName)                                                                                             \\\n    TypeName(const TypeName &);                                                                                                            \\\n    TypeName &operator=(const TypeName &)\n#endif\n\n#ifndef FMT_USE_DEFAULTED_FUNCTIONS\n#define FMT_USE_DEFAULTED_FUNCTIONS 0\n#endif\n\n#ifndef FMT_DEFAULTED_COPY_CTOR\n#if FMT_USE_DEFAULTED_FUNCTIONS || FMT_HAS_FEATURE(cxx_defaulted_functions) || (FMT_GCC_VERSION >= 404 && FMT_HAS_GXX_CXX11) ||            \\\n    FMT_MSC_VER >= 1800\n#define FMT_DEFAULTED_COPY_CTOR(TypeName) TypeName(const TypeName &) = default;\n#else\n#define FMT_DEFAULTED_COPY_CTOR(TypeName)\n#endif\n#endif\n\n#ifndef FMT_USE_USER_DEFINED_LITERALS\n// All compilers which support UDLs also support variadic templates. This\n// makes the fmt::literals implementation easier. However, an explicit check\n// for variadic templates is added here just in case.\n// For Intel's compiler both it and the system gcc/msc must support UDLs.\n#if FMT_USE_VARIADIC_TEMPLATES && FMT_USE_RVALUE_REFERENCES &&                                                                             \\\n    (FMT_HAS_FEATURE(cxx_user_literals) || (FMT_GCC_VERSION >= 407 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1900) &&                        \\\n    (!defined(FMT_ICC_VERSION) || FMT_ICC_VERSION >= 1500)\n#define FMT_USE_USER_DEFINED_LITERALS 1\n#else\n#define FMT_USE_USER_DEFINED_LITERALS 0\n#endif\n#endif\n\n#ifndef FMT_USE_EXTERN_TEMPLATES\n#define FMT_USE_EXTERN_TEMPLATES (FMT_CLANG_VERSION >= 209 || (FMT_GCC_VERSION >= 303 && FMT_HAS_GXX_CXX11))\n#endif\n\n#ifdef FMT_HEADER_ONLY\n// If header only do not use extern templates.\n#undef FMT_USE_EXTERN_TEMPLATES\n#define FMT_USE_EXTERN_TEMPLATES 0\n#endif\n\n#ifndef FMT_ASSERT\n#define FMT_ASSERT(condition, message) assert((condition) && message)\n#endif\n\n// __builtin_clz is broken in clang with Microsoft CodeGen:\n// https://github.com/fmtlib/fmt/issues/519\n#ifndef _MSC_VER\n#if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clz)\n#define FMT_BUILTIN_CLZ(n) __builtin_clz(n)\n#endif\n\n#if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clzll)\n#define FMT_BUILTIN_CLZLL(n) __builtin_clzll(n)\n#endif\n#endif\n\n// Some compilers masquerade as both MSVC and GCC-likes or\n// otherwise support __builtin_clz and __builtin_clzll, so\n// only define FMT_BUILTIN_CLZ using the MSVC intrinsics\n// if the clz and clzll builtins are not available.\n#if FMT_MSC_VER && !defined(FMT_BUILTIN_CLZLL) && !defined(_MANAGED)\n#include <intrin.h> // _BitScanReverse, _BitScanReverse64\n\nnamespace fmt {\nnamespace internal {\n// avoid Clang with Microsoft CodeGen's -Wunknown-pragmas warning\n#ifndef __clang__\n#pragma intrinsic(_BitScanReverse)\n#endif\ninline uint32_t clz(uint32_t x)\n{\n    unsigned long r = 0;\n    _BitScanReverse(&r, x);\n\n    assert(x != 0);\n    // Static analysis complains about using uninitialized data\n    // \"r\", but the only way that can happen is if \"x\" is 0,\n    // which the callers guarantee to not happen.\n#pragma warning(suppress : 6102)\n    return 31 - r;\n}\n#define FMT_BUILTIN_CLZ(n) fmt::internal::clz(n)\n\n// avoid Clang with Microsoft CodeGen's -Wunknown-pragmas warning\n#if defined(_WIN64) && !defined(__clang__)\n#pragma intrinsic(_BitScanReverse64)\n#endif\n\ninline uint32_t clzll(uint64_t x)\n{\n    unsigned long r = 0;\n#ifdef _WIN64\n    _BitScanReverse64(&r, x);\n#else\n    // Scan the high 32 bits.\n    if (_BitScanReverse(&r, static_cast<uint32_t>(x >> 32)))\n        return 63 - (r + 32);\n\n    // Scan the low 32 bits.\n    _BitScanReverse(&r, static_cast<uint32_t>(x));\n#endif\n\n    assert(x != 0);\n    // Static analysis complains about using uninitialized data\n    // \"r\", but the only way that can happen is if \"x\" is 0,\n    // which the callers guarantee to not happen.\n#pragma warning(suppress : 6102)\n    return 63 - r;\n}\n#define FMT_BUILTIN_CLZLL(n) fmt::internal::clzll(n)\n} // namespace internal\n} // namespace fmt\n#endif\n\nnamespace fmt {\nnamespace internal {\nstruct DummyInt\n{\n    int data[2];\n    operator int() const\n    {\n        return 0;\n    }\n};\ntypedef std::numeric_limits<fmt::internal::DummyInt> FPUtil;\n\n// Dummy implementations of system functions such as signbit and ecvt called\n// if the latter are not available.\ninline DummyInt signbit(...)\n{\n    return DummyInt();\n}\ninline DummyInt _ecvt_s(...)\n{\n    return DummyInt();\n}\ninline DummyInt isinf(...)\n{\n    return DummyInt();\n}\ninline DummyInt _finite(...)\n{\n    return DummyInt();\n}\ninline DummyInt isnan(...)\n{\n    return DummyInt();\n}\ninline DummyInt _isnan(...)\n{\n    return DummyInt();\n}\n\n// A helper function to suppress bogus \"conditional expression is constant\"\n// warnings.\ntemplate<typename T>\ninline T const_check(T value)\n{\n    return value;\n}\n} // namespace internal\n} // namespace fmt\n\nnamespace std {\n// Standard permits specialization of std::numeric_limits. This specialization\n// is used to resolve ambiguity between isinf and std::isinf in glibc:\n// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=48891\n// and the same for isnan and signbit.\ntemplate<>\nclass numeric_limits<fmt::internal::DummyInt> : public std::numeric_limits<int>\n{\npublic:\n    // Portable version of isinf.\n    template<typename T>\n    static bool isinfinity(T x)\n    {\n        using namespace fmt::internal;\n        // The resolution \"priority\" is:\n        // isinf macro > std::isinf > ::isinf > fmt::internal::isinf\n        if (const_check(sizeof(isinf(x)) == sizeof(bool) || sizeof(isinf(x)) == sizeof(int)))\n        {\n            return isinf(x) != 0;\n        }\n        return !_finite(static_cast<double>(x));\n    }\n\n    // Portable version of isnan.\n    template<typename T>\n    static bool isnotanumber(T x)\n    {\n        using namespace fmt::internal;\n        if (const_check(sizeof(isnan(x)) == sizeof(bool) || sizeof(isnan(x)) == sizeof(int)))\n        {\n            return isnan(x) != 0;\n        }\n        return _isnan(static_cast<double>(x)) != 0;\n    }\n\n    // Portable version of signbit.\n    static bool isnegative(double x)\n    {\n        using namespace fmt::internal;\n        if (const_check(sizeof(signbit(x)) == sizeof(bool) || sizeof(signbit(x)) == sizeof(int)))\n        {\n            return signbit(x) != 0;\n        }\n        if (x < 0)\n            return true;\n        if (!isnotanumber(x))\n            return false;\n        int dec = 0, sign = 0;\n        char buffer[2]; // The buffer size must be >= 2 or _ecvt_s will fail.\n        _ecvt_s(buffer, sizeof(buffer), x, 0, &dec, &sign);\n        return sign != 0;\n    }\n};\n} // namespace std\n\nnamespace fmt {\n\n// Fix the warning about long long on older versions of GCC\n// that don't support the diagnostic pragma.\nFMT_GCC_EXTENSION typedef long long LongLong;\nFMT_GCC_EXTENSION typedef unsigned long long ULongLong;\n\n#if FMT_USE_RVALUE_REFERENCES\nusing std::move;\n#endif\n\ntemplate<typename Char>\nclass BasicWriter;\n\ntypedef BasicWriter<char> Writer;\ntypedef BasicWriter<wchar_t> WWriter;\n\ntemplate<typename Char>\nclass ArgFormatter;\n\nstruct FormatSpec;\n\ntemplate<typename Impl, typename Char, typename Spec = fmt::FormatSpec>\nclass BasicPrintfArgFormatter;\n\ntemplate<typename CharType, typename ArgFormatter = fmt::ArgFormatter<CharType>>\nclass BasicFormatter;\n\n/**\n  \\rst\n  A string reference. It can be constructed from a C string or\n  ``std::basic_string``.\n\n  You can use one of the following typedefs for common character types:\n\n  +------------+-------------------------+\n  | Type       | Definition              |\n  +============+=========================+\n  | StringRef  | BasicStringRef<char>    |\n  +------------+-------------------------+\n  | WStringRef | BasicStringRef<wchar_t> |\n  +------------+-------------------------+\n\n  This class is most useful as a parameter type to allow passing\n  different types of strings to a function, for example::\n\n    template <typename... Args>\n    std::string format(StringRef format_str, const Args & ... args);\n\n    format(\"{}\", 42);\n    format(std::string(\"{}\"), 42);\n  \\endrst\n */\ntemplate<typename Char>\nclass BasicStringRef\n{\nprivate:\n    const Char *data_;\n    std::size_t size_;\n\npublic:\n    /** Constructs a string reference object from a C string and a size. */\n    BasicStringRef(const Char *s, std::size_t size)\n        : data_(s)\n        , size_(size)\n    {\n    }\n\n    /**\n      \\rst\n      Constructs a string reference object from a C string computing\n      the size with ``std::char_traits<Char>::length``.\n      \\endrst\n     */\n    BasicStringRef(const Char *s)\n        : data_(s)\n        , size_(std::char_traits<Char>::length(s))\n    {\n    }\n\n    /**\n      \\rst\n      Constructs a string reference from a ``std::basic_string`` object.\n      \\endrst\n     */\n    template<typename Allocator>\n    BasicStringRef(const std::basic_string<Char, std::char_traits<Char>, Allocator> &s)\n        : data_(s.c_str())\n        , size_(s.size())\n    {\n    }\n\n#if FMT_HAS_STRING_VIEW\n    /**\n      \\rst\n      Constructs a string reference from a ``std::basic_string_view`` object.\n      \\endrst\n     */\n    BasicStringRef(const std::basic_string_view<Char, std::char_traits<Char>> &s)\n        : data_(s.data())\n        , size_(s.size())\n    {\n    }\n\n    /**\n     \\rst\n     Converts a string reference to an ``std::string_view`` object.\n     \\endrst\n    */\n    explicit operator std::basic_string_view<Char>() const FMT_NOEXCEPT\n    {\n        return std::basic_string_view<Char>(data_, size_);\n    }\n#endif\n\n    /**\n      \\rst\n      Converts a string reference to an ``std::string`` object.\n      \\endrst\n     */\n    std::basic_string<Char> to_string() const\n    {\n        return std::basic_string<Char>(data_, size_);\n    }\n\n    /** Returns a pointer to the string data. */\n    const Char *data() const\n    {\n        return data_;\n    }\n\n    /** Returns the string size. */\n    std::size_t size() const\n    {\n        return size_;\n    }\n\n    // Lexicographically compare this string reference to other.\n    int compare(BasicStringRef other) const\n    {\n        std::size_t size = size_ < other.size_ ? size_ : other.size_;\n        int result = std::char_traits<Char>::compare(data_, other.data_, size);\n        if (result == 0)\n            result = size_ == other.size_ ? 0 : (size_ < other.size_ ? -1 : 1);\n        return result;\n    }\n\n    friend bool operator==(BasicStringRef lhs, BasicStringRef rhs)\n    {\n        return lhs.compare(rhs) == 0;\n    }\n    friend bool operator!=(BasicStringRef lhs, BasicStringRef rhs)\n    {\n        return lhs.compare(rhs) != 0;\n    }\n    friend bool operator<(BasicStringRef lhs, BasicStringRef rhs)\n    {\n        return lhs.compare(rhs) < 0;\n    }\n    friend bool operator<=(BasicStringRef lhs, BasicStringRef rhs)\n    {\n        return lhs.compare(rhs) <= 0;\n    }\n    friend bool operator>(BasicStringRef lhs, BasicStringRef rhs)\n    {\n        return lhs.compare(rhs) > 0;\n    }\n    friend bool operator>=(BasicStringRef lhs, BasicStringRef rhs)\n    {\n        return lhs.compare(rhs) >= 0;\n    }\n};\n\ntypedef BasicStringRef<char> StringRef;\ntypedef BasicStringRef<wchar_t> WStringRef;\n\n/**\n  \\rst\n  A reference to a null terminated string. It can be constructed from a C\n  string or ``std::basic_string``.\n\n  You can use one of the following typedefs for common character types:\n\n  +-------------+--------------------------+\n  | Type        | Definition               |\n  +=============+==========================+\n  | CStringRef  | BasicCStringRef<char>    |\n  +-------------+--------------------------+\n  | WCStringRef | BasicCStringRef<wchar_t> |\n  +-------------+--------------------------+\n\n  This class is most useful as a parameter type to allow passing\n  different types of strings to a function, for example::\n\n    template <typename... Args>\n    std::string format(CStringRef format_str, const Args & ... args);\n\n    format(\"{}\", 42);\n    format(std::string(\"{}\"), 42);\n  \\endrst\n */\ntemplate<typename Char>\nclass BasicCStringRef\n{\nprivate:\n    const Char *data_;\n\npublic:\n    /** Constructs a string reference object from a C string. */\n    BasicCStringRef(const Char *s)\n        : data_(s)\n    {\n    }\n\n    /**\n      \\rst\n      Constructs a string reference from a ``std::basic_string`` object.\n      \\endrst\n     */\n    template<typename Allocator>\n    BasicCStringRef(const std::basic_string<Char, std::char_traits<Char>, Allocator> &s)\n        : data_(s.c_str())\n    {\n    }\n\n    /** Returns the pointer to a C string. */\n    const Char *c_str() const\n    {\n        return data_;\n    }\n};\n\ntypedef BasicCStringRef<char> CStringRef;\ntypedef BasicCStringRef<wchar_t> WCStringRef;\n\n/** A formatting error such as invalid format string. */\nclass FormatError : public std::runtime_error\n{\npublic:\n    explicit FormatError(CStringRef message)\n        : std::runtime_error(message.c_str())\n    {\n    }\n    FormatError(const FormatError &ferr)\n        : std::runtime_error(ferr)\n    {\n    }\n    FMT_API ~FormatError() FMT_DTOR_NOEXCEPT FMT_OVERRIDE;\n};\n\nnamespace internal {\n\n// MakeUnsigned<T>::Type gives an unsigned type corresponding to integer type T.\ntemplate<typename T>\nstruct MakeUnsigned\n{\n    typedef T Type;\n};\n\n#define FMT_SPECIALIZE_MAKE_UNSIGNED(T, U)                                                                                                 \\\n    template<>                                                                                                                             \\\n    struct MakeUnsigned<T>                                                                                                                 \\\n    {                                                                                                                                      \\\n        typedef U Type;                                                                                                                    \\\n    }\n\nFMT_SPECIALIZE_MAKE_UNSIGNED(char, unsigned char);\nFMT_SPECIALIZE_MAKE_UNSIGNED(signed char, unsigned char);\nFMT_SPECIALIZE_MAKE_UNSIGNED(short, unsigned short);\nFMT_SPECIALIZE_MAKE_UNSIGNED(int, unsigned);\nFMT_SPECIALIZE_MAKE_UNSIGNED(long, unsigned long);\nFMT_SPECIALIZE_MAKE_UNSIGNED(LongLong, ULongLong);\n\n// Casts nonnegative integer to unsigned.\ntemplate<typename Int>\ninline typename MakeUnsigned<Int>::Type to_unsigned(Int value)\n{\n    FMT_ASSERT(value >= 0, \"negative value\");\n    return static_cast<typename MakeUnsigned<Int>::Type>(value);\n}\n\n// The number of characters to store in the MemoryBuffer object itself\n// to avoid dynamic memory allocation.\nenum\n{\n    INLINE_BUFFER_SIZE = 500\n};\n\n#if FMT_SECURE_SCL\n// Use checked iterator to avoid warnings on MSVC.\ntemplate<typename T>\ninline stdext::checked_array_iterator<T *> make_ptr(T *ptr, std::size_t size)\n{\n    return stdext::checked_array_iterator<T *>(ptr, size);\n}\n#else\ntemplate<typename T>\ninline T *make_ptr(T *ptr, std::size_t)\n{\n    return ptr;\n}\n#endif\n} // namespace internal\n\n/**\n  \\rst\n  A buffer supporting a subset of ``std::vector``'s operations.\n  \\endrst\n */\ntemplate<typename T>\nclass Buffer\n{\nprivate:\n    FMT_DISALLOW_COPY_AND_ASSIGN(Buffer);\n\nprotected:\n    T *ptr_;\n    std::size_t size_;\n    std::size_t capacity_;\n\n    Buffer(T *ptr = FMT_NULL, std::size_t capacity = 0)\n        : ptr_(ptr)\n        , size_(0)\n        , capacity_(capacity)\n    {\n    }\n\n    /**\n      \\rst\n      Increases the buffer capacity to hold at least *size* elements updating\n      ``ptr_`` and ``capacity_``.\n      \\endrst\n     */\n    virtual void grow(std::size_t size) = 0;\n\npublic:\n    virtual ~Buffer() {}\n\n    /** Returns the size of this buffer. */\n    std::size_t size() const\n    {\n        return size_;\n    }\n\n    /** Returns the capacity of this buffer. */\n    std::size_t capacity() const\n    {\n        return capacity_;\n    }\n\n    /**\n      Resizes the buffer. If T is a POD type new elements may not be initialized.\n     */\n    void resize(std::size_t new_size)\n    {\n        if (new_size > capacity_)\n            grow(new_size);\n        size_ = new_size;\n    }\n\n    /**\n      \\rst\n      Reserves space to store at least *capacity* elements.\n      \\endrst\n     */\n    void reserve(std::size_t capacity)\n    {\n        if (capacity > capacity_)\n            grow(capacity);\n    }\n\n    void clear() FMT_NOEXCEPT\n    {\n        size_ = 0;\n    }\n\n    void push_back(const T &value)\n    {\n        if (size_ == capacity_)\n            grow(size_ + 1);\n        ptr_[size_++] = value;\n    }\n\n    /** Appends data to the end of the buffer. */\n    template<typename U>\n    void append(const U *begin, const U *end);\n\n    T &operator[](std::size_t index)\n    {\n        return ptr_[index];\n    }\n    const T &operator[](std::size_t index) const\n    {\n        return ptr_[index];\n    }\n};\n\ntemplate<typename T>\ntemplate<typename U>\nvoid Buffer<T>::append(const U *begin, const U *end)\n{\n    FMT_ASSERT(end >= begin, \"negative value\");\n    std::size_t new_size = size_ + static_cast<std::size_t>(end - begin);\n    if (new_size > capacity_)\n        grow(new_size);\n    std::uninitialized_copy(begin, end, internal::make_ptr(ptr_, capacity_) + size_);\n    size_ = new_size;\n}\n\nnamespace internal {\n\n// A memory buffer for trivially copyable/constructible types with the first\n// SIZE elements stored in the object itself.\ntemplate<typename T, std::size_t SIZE, typename Allocator = std::allocator<T>>\nclass MemoryBuffer : private Allocator, public Buffer<T>\n{\nprivate:\n    T data_[SIZE];\n\n    // Deallocate memory allocated by the buffer.\n    void deallocate()\n    {\n        if (this->ptr_ != data_)\n            Allocator::deallocate(this->ptr_, this->capacity_);\n    }\n\nprotected:\n    void grow(std::size_t size) FMT_OVERRIDE;\n\npublic:\n    explicit MemoryBuffer(const Allocator &alloc = Allocator())\n        : Allocator(alloc)\n        , Buffer<T>(data_, SIZE)\n    {\n    }\n    ~MemoryBuffer() FMT_OVERRIDE\n    {\n        deallocate();\n    }\n\n#if FMT_USE_RVALUE_REFERENCES\nprivate:\n    // Move data from other to this buffer.\n    void move(MemoryBuffer &other)\n    {\n        Allocator &this_alloc = *this, &other_alloc = other;\n        this_alloc = std::move(other_alloc);\n        this->size_ = other.size_;\n        this->capacity_ = other.capacity_;\n        if (other.ptr_ == other.data_)\n        {\n            this->ptr_ = data_;\n            std::uninitialized_copy(other.data_, other.data_ + this->size_, make_ptr(data_, this->capacity_));\n        }\n        else\n        {\n            this->ptr_ = other.ptr_;\n            // Set pointer to the inline array so that delete is not called\n            // when deallocating.\n            other.ptr_ = other.data_;\n        }\n    }\n\npublic:\n    MemoryBuffer(MemoryBuffer &&other)\n    {\n        move(other);\n    }\n\n    MemoryBuffer &operator=(MemoryBuffer &&other)\n    {\n        assert(this != &other);\n        deallocate();\n        move(other);\n        return *this;\n    }\n#endif\n\n    // Returns a copy of the allocator associated with this buffer.\n    Allocator get_allocator() const\n    {\n        return *this;\n    }\n};\n\ntemplate<typename T, std::size_t SIZE, typename Allocator>\nvoid MemoryBuffer<T, SIZE, Allocator>::grow(std::size_t size)\n{\n    std::size_t new_capacity = this->capacity_ + this->capacity_ / 2;\n    if (size > new_capacity)\n        new_capacity = size;\n#if FMT_USE_ALLOCATOR_TRAITS\n    T *new_ptr = std::allocator_traits<Allocator>::allocate(*this, new_capacity, FMT_NULL);\n#else\n    T *new_ptr = this->allocate(new_capacity, FMT_NULL);\n#endif\n    // The following code doesn't throw, so the raw pointer above doesn't leak.\n    std::uninitialized_copy(this->ptr_, this->ptr_ + this->size_, make_ptr(new_ptr, new_capacity));\n    std::size_t old_capacity = this->capacity_;\n    T *old_ptr = this->ptr_;\n    this->capacity_ = new_capacity;\n    this->ptr_ = new_ptr;\n    // deallocate may throw (at least in principle), but it doesn't matter since\n    // the buffer already uses the new storage and will deallocate it in case\n    // of exception.\n    if (old_ptr != data_)\n        Allocator::deallocate(old_ptr, old_capacity);\n}\n\n// A fixed-size buffer.\ntemplate<typename Char>\nclass FixedBuffer : public fmt::Buffer<Char>\n{\npublic:\n    FixedBuffer(Char *array, std::size_t size)\n        : fmt::Buffer<Char>(array, size)\n    {\n    }\n\nprotected:\n    FMT_API void grow(std::size_t size) FMT_OVERRIDE;\n};\n\ntemplate<typename Char>\nclass BasicCharTraits\n{\npublic:\n#if FMT_SECURE_SCL\n    typedef stdext::checked_array_iterator<Char *> CharPtr;\n#else\n    typedef Char *CharPtr;\n#endif\n    static Char cast(int value)\n    {\n        return static_cast<Char>(value);\n    }\n};\n\ntemplate<typename Char>\nclass CharTraits;\n\ntemplate<>\nclass CharTraits<char> : public BasicCharTraits<char>\n{\nprivate:\n    // Conversion from wchar_t to char is not allowed.\n    static char convert(wchar_t);\n\npublic:\n    static char convert(char value)\n    {\n        return value;\n    }\n\n    // Formats a floating-point number.\n    template<typename T>\n    FMT_API static int format_float(char *buffer, std::size_t size, const char *format, unsigned width, int precision, T value);\n};\n\n#if FMT_USE_EXTERN_TEMPLATES\nextern template int CharTraits<char>::format_float<double>(\n    char *buffer, std::size_t size, const char *format, unsigned width, int precision, double value);\nextern template int CharTraits<char>::format_float<long double>(\n    char *buffer, std::size_t size, const char *format, unsigned width, int precision, long double value);\n#endif\n\ntemplate<>\nclass CharTraits<wchar_t> : public BasicCharTraits<wchar_t>\n{\npublic:\n    static wchar_t convert(char value)\n    {\n        return value;\n    }\n    static wchar_t convert(wchar_t value)\n    {\n        return value;\n    }\n\n    template<typename T>\n    FMT_API static int format_float(wchar_t *buffer, std::size_t size, const wchar_t *format, unsigned width, int precision, T value);\n};\n\n#if FMT_USE_EXTERN_TEMPLATES\nextern template int CharTraits<wchar_t>::format_float<double>(\n    wchar_t *buffer, std::size_t size, const wchar_t *format, unsigned width, int precision, double value);\nextern template int CharTraits<wchar_t>::format_float<long double>(\n    wchar_t *buffer, std::size_t size, const wchar_t *format, unsigned width, int precision, long double value);\n#endif\n\n// Checks if a number is negative - used to avoid warnings.\ntemplate<bool IsSigned>\nstruct SignChecker\n{\n    template<typename T>\n    static bool is_negative(T value)\n    {\n        return value < 0;\n    }\n};\n\ntemplate<>\nstruct SignChecker<false>\n{\n    template<typename T>\n    static bool is_negative(T)\n    {\n        return false;\n    }\n};\n\n// Returns true if value is negative, false otherwise.\n// Same as (value < 0) but doesn't produce warnings if T is an unsigned type.\ntemplate<typename T>\ninline bool is_negative(T value)\n{\n    return SignChecker<std::numeric_limits<T>::is_signed>::is_negative(value);\n}\n\n// Selects uint32_t if FitsIn32Bits is true, uint64_t otherwise.\ntemplate<bool FitsIn32Bits>\nstruct TypeSelector\n{\n    typedef uint32_t Type;\n};\n\ntemplate<>\nstruct TypeSelector<false>\n{\n    typedef uint64_t Type;\n};\n\ntemplate<typename T>\nstruct IntTraits\n{\n    // Smallest of uint32_t and uint64_t that is large enough to represent\n    // all values of T.\n    typedef typename TypeSelector<std::numeric_limits<T>::digits <= 32>::Type MainType;\n};\n\nFMT_API FMT_NORETURN void report_unknown_type(char code, const char *type);\n\n// Static data is placed in this class template to allow header-only\n// configuration.\ntemplate<typename T = void>\nstruct FMT_API BasicData\n{\n    static const uint32_t POWERS_OF_10_32[];\n    static const uint64_t POWERS_OF_10_64[];\n    static const char DIGITS[];\n};\n\n#if FMT_USE_EXTERN_TEMPLATES\nextern template struct BasicData<void>;\n#endif\n\ntypedef BasicData<> Data;\n\n#ifdef FMT_BUILTIN_CLZLL\n// Returns the number of decimal digits in n. Leading zeros are not counted\n// except for n == 0 in which case count_digits returns 1.\ninline unsigned count_digits(uint64_t n)\n{\n    // Based on http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10\n    // and the benchmark https://github.com/localvoid/cxx-benchmark-count-digits.\n    int t = (64 - FMT_BUILTIN_CLZLL(n | 1)) * 1233 >> 12;\n    return to_unsigned(t) - (n < Data::POWERS_OF_10_64[t]) + 1;\n}\n#else\n// Fallback version of count_digits used when __builtin_clz is not available.\ninline unsigned count_digits(uint64_t n)\n{\n    unsigned count = 1;\n    for (;;)\n    {\n        // Integer division is slow so do it for a group of four digits instead\n        // of for every digit. The idea comes from the talk by Alexandrescu\n        // \"Three Optimization Tips for C++\". See speed-test for a comparison.\n        if (n < 10)\n            return count;\n        if (n < 100)\n            return count + 1;\n        if (n < 1000)\n            return count + 2;\n        if (n < 10000)\n            return count + 3;\n        n /= 10000u;\n        count += 4;\n    }\n}\n#endif\n\n#ifdef FMT_BUILTIN_CLZ\n// Optional version of count_digits for better performance on 32-bit platforms.\ninline unsigned count_digits(uint32_t n)\n{\n    int t = (32 - FMT_BUILTIN_CLZ(n | 1)) * 1233 >> 12;\n    return to_unsigned(t) - (n < Data::POWERS_OF_10_32[t]) + 1;\n}\n#endif\n\n// A functor that doesn't add a thousands separator.\nstruct NoThousandsSep\n{\n    template<typename Char>\n    void operator()(Char *)\n    {\n    }\n};\n\n// A functor that adds a thousands separator.\nclass ThousandsSep\n{\nprivate:\n    fmt::StringRef sep_;\n\n    // Index of a decimal digit with the least significant digit having index 0.\n    unsigned digit_index_;\n\npublic:\n    explicit ThousandsSep(fmt::StringRef sep)\n        : sep_(sep)\n        , digit_index_(0)\n    {\n    }\n\n    template<typename Char>\n    void operator()(Char *&buffer)\n    {\n        if (++digit_index_ % 3 != 0)\n            return;\n        buffer -= sep_.size();\n        std::uninitialized_copy(sep_.data(), sep_.data() + sep_.size(), internal::make_ptr(buffer, sep_.size()));\n    }\n};\n\n// Formats a decimal unsigned integer value writing into buffer.\n// thousands_sep is a functor that is called after writing each char to\n// add a thousands separator if necessary.\ntemplate<typename UInt, typename Char, typename ThousandsSep>\ninline void format_decimal(Char *buffer, UInt value, unsigned num_digits, ThousandsSep thousands_sep)\n{\n    buffer += num_digits;\n    while (value >= 100)\n    {\n        // Integer division is slow so do it for a group of two digits instead\n        // of for every digit. The idea comes from the talk by Alexandrescu\n        // \"Three Optimization Tips for C++\". See speed-test for a comparison.\n        unsigned index = static_cast<unsigned>((value % 100) * 2);\n        value /= 100;\n        *--buffer = Data::DIGITS[index + 1];\n        thousands_sep(buffer);\n        *--buffer = Data::DIGITS[index];\n        thousands_sep(buffer);\n    }\n    if (value < 10)\n    {\n        *--buffer = static_cast<char>('0' + value);\n        return;\n    }\n    unsigned index = static_cast<unsigned>(value * 2);\n    *--buffer = Data::DIGITS[index + 1];\n    thousands_sep(buffer);\n    *--buffer = Data::DIGITS[index];\n}\n\ntemplate<typename UInt, typename Char>\ninline void format_decimal(Char *buffer, UInt value, unsigned num_digits)\n{\n    format_decimal(buffer, value, num_digits, NoThousandsSep());\n    return;\n}\n\n#ifndef _WIN32\n#define FMT_USE_WINDOWS_H 0\n#elif !defined(FMT_USE_WINDOWS_H)\n#define FMT_USE_WINDOWS_H 1\n#endif\n\n// Define FMT_USE_WINDOWS_H to 0 to disable use of windows.h.\n// All the functionality that relies on it will be disabled too.\n#if FMT_USE_WINDOWS_H\n// A converter from UTF-8 to UTF-16.\n// It is only provided for Windows since other systems support UTF-8 natively.\nclass UTF8ToUTF16\n{\nprivate:\n    MemoryBuffer<wchar_t, INLINE_BUFFER_SIZE> buffer_;\n\npublic:\n    FMT_API explicit UTF8ToUTF16(StringRef s);\n    operator WStringRef() const\n    {\n        return WStringRef(&buffer_[0], size());\n    }\n    size_t size() const\n    {\n        return buffer_.size() - 1;\n    }\n    const wchar_t *c_str() const\n    {\n        return &buffer_[0];\n    }\n    std::wstring str() const\n    {\n        return std::wstring(&buffer_[0], size());\n    }\n};\n\n// A converter from UTF-16 to UTF-8.\n// It is only provided for Windows since other systems support UTF-8 natively.\nclass UTF16ToUTF8\n{\nprivate:\n    MemoryBuffer<char, INLINE_BUFFER_SIZE> buffer_;\n\npublic:\n    UTF16ToUTF8() {}\n    FMT_API explicit UTF16ToUTF8(WStringRef s);\n    operator StringRef() const\n    {\n        return StringRef(&buffer_[0], size());\n    }\n    size_t size() const\n    {\n        return buffer_.size() - 1;\n    }\n    const char *c_str() const\n    {\n        return &buffer_[0];\n    }\n    std::string str() const\n    {\n        return std::string(&buffer_[0], size());\n    }\n\n    // Performs conversion returning a system error code instead of\n    // throwing exception on conversion error. This method may still throw\n    // in case of memory allocation error.\n    FMT_API int convert(WStringRef s);\n};\n\nFMT_API void format_windows_error(fmt::Writer &out, int error_code, fmt::StringRef message) FMT_NOEXCEPT;\n#endif\n\n// A formatting argument value.\nstruct Value\n{\n    template<typename Char>\n    struct StringValue\n    {\n        const Char *value;\n        std::size_t size;\n    };\n\n    typedef void (*FormatFunc)(void *formatter, const void *arg, void *format_str_ptr);\n\n    struct CustomValue\n    {\n        const void *value;\n        FormatFunc format;\n    };\n\n    union\n    {\n        int int_value;\n        unsigned uint_value;\n        LongLong long_long_value;\n        ULongLong ulong_long_value;\n        double double_value;\n        long double long_double_value;\n        const void *pointer;\n        StringValue<char> string;\n        StringValue<signed char> sstring;\n        StringValue<unsigned char> ustring;\n        StringValue<wchar_t> wstring;\n        CustomValue custom;\n    };\n\n    enum Type\n    {\n        NONE,\n        NAMED_ARG,\n        // Integer types should go first,\n        INT,\n        UINT,\n        LONG_LONG,\n        ULONG_LONG,\n        BOOL,\n        CHAR,\n        LAST_INTEGER_TYPE = CHAR,\n        // followed by floating-point types.\n        DOUBLE,\n        LONG_DOUBLE,\n        LAST_NUMERIC_TYPE = LONG_DOUBLE,\n        CSTRING,\n        STRING,\n        WSTRING,\n        POINTER,\n        CUSTOM\n    };\n};\n\n// A formatting argument. It is a trivially copyable/constructible type to\n// allow storage in internal::MemoryBuffer.\nstruct Arg : Value\n{\n    Type type;\n};\n\ntemplate<typename Char>\nstruct NamedArg;\ntemplate<typename Char, typename T>\nstruct NamedArgWithType;\n\ntemplate<typename T = void>\nstruct Null\n{\n};\n\n// A helper class template to enable or disable overloads taking wide\n// characters and strings in MakeValue.\ntemplate<typename T, typename Char>\nstruct WCharHelper\n{\n    typedef Null<T> Supported;\n    typedef T Unsupported;\n};\n\ntemplate<typename T>\nstruct WCharHelper<T, wchar_t>\n{\n    typedef T Supported;\n    typedef Null<T> Unsupported;\n};\n\ntypedef char Yes[1];\ntypedef char No[2];\n\ntemplate<typename T>\nT &get();\n\n// These are non-members to workaround an overload resolution bug in bcc32.\nYes &convert(fmt::ULongLong);\nNo &convert(...);\n\ntemplate<typename T, bool ENABLE_CONVERSION>\nstruct ConvertToIntImpl\n{\n    enum\n    {\n        value = ENABLE_CONVERSION\n    };\n};\n\ntemplate<typename T, bool ENABLE_CONVERSION>\nstruct ConvertToIntImpl2\n{\n    enum\n    {\n        value = false\n    };\n};\n\ntemplate<typename T>\nstruct ConvertToIntImpl2<T, true>\n{\n    enum\n    {\n        // Don't convert numeric types.\n        value = ConvertToIntImpl<T, !std::numeric_limits<T>::is_specialized>::value\n    };\n};\n\ntemplate<typename T>\nstruct ConvertToInt\n{\n    enum\n    {\n        enable_conversion = sizeof(fmt::internal::convert(get<T>())) == sizeof(Yes)\n    };\n    enum\n    {\n        value = ConvertToIntImpl2<T, enable_conversion>::value\n    };\n};\n\n#define FMT_DISABLE_CONVERSION_TO_INT(Type)                                                                                                \\\n    template<>                                                                                                                             \\\n    struct ConvertToInt<Type>                                                                                                              \\\n    {                                                                                                                                      \\\n        enum                                                                                                                               \\\n        {                                                                                                                                  \\\n            value = 0                                                                                                                      \\\n        };                                                                                                                                 \\\n    }\n\n// Silence warnings about convering float to int.\nFMT_DISABLE_CONVERSION_TO_INT(float);\nFMT_DISABLE_CONVERSION_TO_INT(double);\nFMT_DISABLE_CONVERSION_TO_INT(long double);\n\ntemplate<bool B, class T = void>\nstruct EnableIf\n{\n};\n\ntemplate<class T>\nstruct EnableIf<true, T>\n{\n    typedef T type;\n};\n\ntemplate<bool B, class T, class F>\nstruct Conditional\n{\n    typedef T type;\n};\n\ntemplate<class T, class F>\nstruct Conditional<false, T, F>\n{\n    typedef F type;\n};\n\n// For bcc32 which doesn't understand ! in template arguments.\ntemplate<bool>\nstruct Not\n{\n    enum\n    {\n        value = 0\n    };\n};\n\ntemplate<>\nstruct Not<false>\n{\n    enum\n    {\n        value = 1\n    };\n};\n\ntemplate<typename T>\nstruct FalseType\n{\n    enum\n    {\n        value = 0\n    };\n};\n\ntemplate<typename T, T>\nstruct LConvCheck\n{\n    LConvCheck(int) {}\n};\n\n// Returns the thousands separator for the current locale.\n// We check if ``lconv`` contains ``thousands_sep`` because on Android\n// ``lconv`` is stubbed as an empty struct.\ntemplate<typename LConv>\ninline StringRef thousands_sep(LConv *lc, LConvCheck<char * LConv::*, &LConv::thousands_sep> = 0)\n{\n    return lc->thousands_sep;\n}\n\ninline fmt::StringRef thousands_sep(...)\n{\n    return \"\";\n}\n\n#define FMT_CONCAT(a, b) a##b\n\n#if FMT_GCC_VERSION >= 303\n#define FMT_UNUSED __attribute__((unused))\n#else\n#define FMT_UNUSED\n#endif\n\n#ifndef FMT_USE_STATIC_ASSERT\n#define FMT_USE_STATIC_ASSERT 0\n#endif\n\n#if FMT_USE_STATIC_ASSERT || FMT_HAS_FEATURE(cxx_static_assert) || (FMT_GCC_VERSION >= 403 && FMT_HAS_GXX_CXX11) || _MSC_VER >= 1600\n#define FMT_STATIC_ASSERT(cond, message) static_assert(cond, message)\n#else\n#define FMT_CONCAT_(a, b) FMT_CONCAT(a, b)\n#define FMT_STATIC_ASSERT(cond, message) typedef int FMT_CONCAT_(Assert, __LINE__)[(cond) ? 1 : -1] FMT_UNUSED\n#endif\n\ntemplate<typename Formatter>\nvoid format_arg(Formatter &, ...)\n{\n    FMT_STATIC_ASSERT(FalseType<Formatter>::value, \"Cannot format argument. To enable the use of ostream \"\n                                                   \"operator<< include fmt/ostream.h. Otherwise provide \"\n                                                   \"an overload of format_arg.\");\n}\n\n// Makes an Arg object from any type.\ntemplate<typename Formatter>\nclass MakeValue : public Arg\n{\npublic:\n    typedef typename Formatter::Char Char;\n\nprivate:\n    // The following two methods are private to disallow formatting of\n    // arbitrary pointers. If you want to output a pointer cast it to\n    // \"void *\" or \"const void *\". In particular, this forbids formatting\n    // of \"[const] volatile char *\" which is printed as bool by iostreams.\n    // Do not implement!\n    template<typename T>\n    MakeValue(const T *value);\n    template<typename T>\n    MakeValue(T *value);\n\n    // The following methods are private to disallow formatting of wide\n    // characters and strings into narrow strings as in\n    //   fmt::format(\"{}\", L\"test\");\n    // To fix this, use a wide format string: fmt::format(L\"{}\", L\"test\").\n#if !FMT_MSC_VER || defined(_NATIVE_WCHAR_T_DEFINED)\n    MakeValue(typename WCharHelper<wchar_t, Char>::Unsupported);\n#endif\n    MakeValue(typename WCharHelper<wchar_t *, Char>::Unsupported);\n    MakeValue(typename WCharHelper<const wchar_t *, Char>::Unsupported);\n    MakeValue(typename WCharHelper<const std::wstring &, Char>::Unsupported);\n#if FMT_HAS_STRING_VIEW\n    MakeValue(typename WCharHelper<const std::wstring_view &, Char>::Unsupported);\n#endif\n    MakeValue(typename WCharHelper<WStringRef, Char>::Unsupported);\n\n    void set_string(StringRef str)\n    {\n        string.value = str.data();\n        string.size = str.size();\n    }\n\n    void set_string(WStringRef str)\n    {\n        wstring.value = str.data();\n        wstring.size = str.size();\n    }\n\n    // Formats an argument of a custom type, such as a user-defined class.\n    template<typename T>\n    static void format_custom_arg(void *formatter, const void *arg, void *format_str_ptr)\n    {\n        format_arg(*static_cast<Formatter *>(formatter), *static_cast<const Char **>(format_str_ptr), *static_cast<const T *>(arg));\n    }\n\npublic:\n    MakeValue() {}\n\n#define FMT_MAKE_VALUE_(Type, field, TYPE, rhs)                                                                                            \\\n    MakeValue(Type value)                                                                                                                  \\\n    {                                                                                                                                      \\\n        field = rhs;                                                                                                                       \\\n    }                                                                                                                                      \\\n    static uint64_t type(Type)                                                                                                             \\\n    {                                                                                                                                      \\\n        return Arg::TYPE;                                                                                                                  \\\n    }\n\n#define FMT_MAKE_VALUE(Type, field, TYPE) FMT_MAKE_VALUE_(Type, field, TYPE, value)\n\n    FMT_MAKE_VALUE(bool, int_value, BOOL)\n    FMT_MAKE_VALUE(short, int_value, INT)\n    FMT_MAKE_VALUE(unsigned short, uint_value, UINT)\n    FMT_MAKE_VALUE(int, int_value, INT)\n    FMT_MAKE_VALUE(unsigned, uint_value, UINT)\n\n    MakeValue(long value)\n    {\n        // To minimize the number of types we need to deal with, long is\n        // translated either to int or to long long depending on its size.\n        if (const_check(sizeof(long) == sizeof(int)))\n            int_value = static_cast<int>(value);\n        else\n            long_long_value = value;\n    }\n    static uint64_t type(long)\n    {\n        return sizeof(long) == sizeof(int) ? Arg::INT : Arg::LONG_LONG;\n    }\n\n    MakeValue(unsigned long value)\n    {\n        if (const_check(sizeof(unsigned long) == sizeof(unsigned)))\n            uint_value = static_cast<unsigned>(value);\n        else\n            ulong_long_value = value;\n    }\n    static uint64_t type(unsigned long)\n    {\n        return sizeof(unsigned long) == sizeof(unsigned) ? Arg::UINT : Arg::ULONG_LONG;\n    }\n\n    FMT_MAKE_VALUE(LongLong, long_long_value, LONG_LONG)\n    FMT_MAKE_VALUE(ULongLong, ulong_long_value, ULONG_LONG)\n    FMT_MAKE_VALUE(float, double_value, DOUBLE)\n    FMT_MAKE_VALUE(double, double_value, DOUBLE)\n    FMT_MAKE_VALUE(long double, long_double_value, LONG_DOUBLE)\n    FMT_MAKE_VALUE(signed char, int_value, INT)\n    FMT_MAKE_VALUE(unsigned char, uint_value, UINT)\n    FMT_MAKE_VALUE(char, int_value, CHAR)\n\n#if __cplusplus >= 201103L\n    template<typename T, typename = typename std::enable_if<std::is_enum<T>::value && ConvertToInt<T>::value>::type>\n    MakeValue(T value)\n    {\n        int_value = value;\n    }\n\n    template<typename T, typename = typename std::enable_if<std::is_enum<T>::value && ConvertToInt<T>::value>::type>\n    static uint64_t type(T)\n    {\n        return Arg::INT;\n    }\n#endif\n\n#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)\n    MakeValue(typename WCharHelper<wchar_t, Char>::Supported value)\n    {\n        int_value = value;\n    }\n    static uint64_t type(wchar_t)\n    {\n        return Arg::CHAR;\n    }\n#endif\n\n#define FMT_MAKE_STR_VALUE(Type, TYPE)                                                                                                     \\\n    MakeValue(Type value)                                                                                                                  \\\n    {                                                                                                                                      \\\n        set_string(value);                                                                                                                 \\\n    }                                                                                                                                      \\\n    static uint64_t type(Type)                                                                                                             \\\n    {                                                                                                                                      \\\n        return Arg::TYPE;                                                                                                                  \\\n    }\n\n    FMT_MAKE_VALUE(char *, string.value, CSTRING)\n    FMT_MAKE_VALUE(const char *, string.value, CSTRING)\n    FMT_MAKE_VALUE(signed char *, sstring.value, CSTRING)\n    FMT_MAKE_VALUE(const signed char *, sstring.value, CSTRING)\n    FMT_MAKE_VALUE(unsigned char *, ustring.value, CSTRING)\n    FMT_MAKE_VALUE(const unsigned char *, ustring.value, CSTRING)\n    FMT_MAKE_STR_VALUE(const std::string &, STRING)\n#if FMT_HAS_STRING_VIEW\n    FMT_MAKE_STR_VALUE(const std::string_view &, STRING)\n#endif\n    FMT_MAKE_STR_VALUE(StringRef, STRING)\n    FMT_MAKE_VALUE_(CStringRef, string.value, CSTRING, value.c_str())\n\n#define FMT_MAKE_WSTR_VALUE(Type, TYPE)                                                                                                    \\\n    MakeValue(typename WCharHelper<Type, Char>::Supported value)                                                                           \\\n    {                                                                                                                                      \\\n        set_string(value);                                                                                                                 \\\n    }                                                                                                                                      \\\n    static uint64_t type(Type)                                                                                                             \\\n    {                                                                                                                                      \\\n        return Arg::TYPE;                                                                                                                  \\\n    }\n\n    FMT_MAKE_WSTR_VALUE(wchar_t *, WSTRING)\n    FMT_MAKE_WSTR_VALUE(const wchar_t *, WSTRING)\n    FMT_MAKE_WSTR_VALUE(const std::wstring &, WSTRING)\n#if FMT_HAS_STRING_VIEW\n    FMT_MAKE_WSTR_VALUE(const std::wstring_view &, WSTRING)\n#endif\n    FMT_MAKE_WSTR_VALUE(WStringRef, WSTRING)\n\n    FMT_MAKE_VALUE(void *, pointer, POINTER)\n    FMT_MAKE_VALUE(const void *, pointer, POINTER)\n\n    template<typename T>\n    MakeValue(const T &value, typename EnableIf<Not<ConvertToInt<T>::value>::value, int>::type = 0)\n    {\n        custom.value = &value;\n        custom.format = &format_custom_arg<T>;\n    }\n\n    template<typename T>\n    static typename EnableIf<Not<ConvertToInt<T>::value>::value, uint64_t>::type type(const T &)\n    {\n        return Arg::CUSTOM;\n    }\n\n    // Additional template param `Char_` is needed here because make_type always\n    // uses char.\n    template<typename Char_>\n    MakeValue(const NamedArg<Char_> &value)\n    {\n        pointer = &value;\n    }\n    template<typename Char_, typename T>\n    MakeValue(const NamedArgWithType<Char_, T> &value)\n    {\n        pointer = &value;\n    }\n\n    template<typename Char_>\n    static uint64_t type(const NamedArg<Char_> &)\n    {\n        return Arg::NAMED_ARG;\n    }\n    template<typename Char_, typename T>\n    static uint64_t type(const NamedArgWithType<Char_, T> &)\n    {\n        return Arg::NAMED_ARG;\n    }\n};\n\ntemplate<typename Formatter>\nclass MakeArg : public Arg\n{\npublic:\n    MakeArg()\n    {\n        type = Arg::NONE;\n    }\n\n    template<typename T>\n    MakeArg(const T &value)\n        : Arg(MakeValue<Formatter>(value))\n    {\n        type = static_cast<Arg::Type>(MakeValue<Formatter>::type(value));\n    }\n};\n\ntemplate<typename Char>\nstruct NamedArg : Arg\n{\n    BasicStringRef<Char> name;\n\n    template<typename T>\n    NamedArg(BasicStringRef<Char> argname, const T &value)\n        : Arg(MakeArg<BasicFormatter<Char>>(value))\n        , name(argname)\n    {\n    }\n};\n\ntemplate<typename Char, typename T>\nstruct NamedArgWithType : NamedArg<Char>\n{\n    NamedArgWithType(BasicStringRef<Char> argname, const T &value)\n        : NamedArg<Char>(argname, value)\n    {\n    }\n};\n\nclass RuntimeError : public std::runtime_error\n{\nprotected:\n    RuntimeError()\n        : std::runtime_error(\"\")\n    {\n    }\n    RuntimeError(const RuntimeError &rerr)\n        : std::runtime_error(rerr)\n    {\n    }\n    FMT_API ~RuntimeError() FMT_DTOR_NOEXCEPT FMT_OVERRIDE;\n};\n\ntemplate<typename Char>\nclass ArgMap;\n} // namespace internal\n\n/** An argument list. */\nclass ArgList\n{\nprivate:\n    // To reduce compiled code size per formatting function call, types of first\n    // MAX_PACKED_ARGS arguments are passed in the types_ field.\n    uint64_t types_;\n    union\n    {\n        // If the number of arguments is less than MAX_PACKED_ARGS, the argument\n        // values are stored in values_, otherwise they are stored in args_.\n        // This is done to reduce compiled code size as storing larger objects\n        // may require more code (at least on x86-64) even if the same amount of\n        // data is actually copied to stack. It saves ~10% on the bloat test.\n        const internal::Value *values_;\n        const internal::Arg *args_;\n    };\n\n    internal::Arg::Type type(unsigned index) const\n    {\n        return type(types_, index);\n    }\n\n    template<typename Char>\n    friend class internal::ArgMap;\n\npublic:\n    // Maximum number of arguments with packed types.\n    enum\n    {\n        MAX_PACKED_ARGS = 16\n    };\n\n    ArgList()\n        : types_(0)\n    {\n    }\n\n    ArgList(ULongLong types, const internal::Value *values)\n        : types_(types)\n        , values_(values)\n    {\n    }\n    ArgList(ULongLong types, const internal::Arg *args)\n        : types_(types)\n        , args_(args)\n    {\n    }\n\n    uint64_t types() const\n    {\n        return types_;\n    }\n\n    /** Returns the argument at specified index. */\n    internal::Arg operator[](unsigned index) const\n    {\n        using internal::Arg;\n        Arg arg;\n        bool use_values = type(MAX_PACKED_ARGS - 1) == Arg::NONE;\n        if (index < MAX_PACKED_ARGS)\n        {\n            Arg::Type arg_type = type(index);\n            internal::Value &val = arg;\n            if (arg_type != Arg::NONE)\n                val = use_values ? values_[index] : args_[index];\n            arg.type = arg_type;\n            return arg;\n        }\n        if (use_values)\n        {\n            // The index is greater than the number of arguments that can be stored\n            // in values, so return a \"none\" argument.\n            arg.type = Arg::NONE;\n            return arg;\n        }\n        for (unsigned i = MAX_PACKED_ARGS; i <= index; ++i)\n        {\n            if (args_[i].type == Arg::NONE)\n                return args_[i];\n        }\n        return args_[index];\n    }\n\n    static internal::Arg::Type type(uint64_t types, unsigned index)\n    {\n        unsigned shift = index * 4;\n        uint64_t mask = 0xf;\n        return static_cast<internal::Arg::Type>((types & (mask << shift)) >> shift);\n    }\n};\n\n#define FMT_DISPATCH(call) static_cast<Impl *>(this)->call\n\n/**\n  \\rst\n  An argument visitor based on the `curiously recurring template pattern\n  <http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern>`_.\n\n  To use `~fmt::ArgVisitor` define a subclass that implements some or all of the\n  visit methods with the same signatures as the methods in `~fmt::ArgVisitor`,\n  for example, `~fmt::ArgVisitor::visit_int()`.\n  Pass the subclass as the *Impl* template parameter. Then calling\n  `~fmt::ArgVisitor::visit` for some argument will dispatch to a visit method\n  specific to the argument type. For example, if the argument type is\n  ``double`` then the `~fmt::ArgVisitor::visit_double()` method of a subclass\n  will be called. If the subclass doesn't contain a method with this signature,\n  then a corresponding method of `~fmt::ArgVisitor` will be called.\n\n  **Example**::\n\n    class MyArgVisitor : public fmt::ArgVisitor<MyArgVisitor, void> {\n     public:\n      void visit_int(int value) { fmt::print(\"{}\", value); }\n      void visit_double(double value) { fmt::print(\"{}\", value ); }\n    };\n  \\endrst\n */\ntemplate<typename Impl, typename Result>\nclass ArgVisitor\n{\nprivate:\n    typedef internal::Arg Arg;\n\npublic:\n    void report_unhandled_arg() {}\n\n    Result visit_unhandled_arg()\n    {\n        FMT_DISPATCH(report_unhandled_arg());\n        return Result();\n    }\n\n    /** Visits an ``int`` argument. **/\n    Result visit_int(int value)\n    {\n        return FMT_DISPATCH(visit_any_int(value));\n    }\n\n    /** Visits a ``long long`` argument. **/\n    Result visit_long_long(LongLong value)\n    {\n        return FMT_DISPATCH(visit_any_int(value));\n    }\n\n    /** Visits an ``unsigned`` argument. **/\n    Result visit_uint(unsigned value)\n    {\n        return FMT_DISPATCH(visit_any_int(value));\n    }\n\n    /** Visits an ``unsigned long long`` argument. **/\n    Result visit_ulong_long(ULongLong value)\n    {\n        return FMT_DISPATCH(visit_any_int(value));\n    }\n\n    /** Visits a ``bool`` argument. **/\n    Result visit_bool(bool value)\n    {\n        return FMT_DISPATCH(visit_any_int(value));\n    }\n\n    /** Visits a ``char`` or ``wchar_t`` argument. **/\n    Result visit_char(int value)\n    {\n        return FMT_DISPATCH(visit_any_int(value));\n    }\n\n    /** Visits an argument of any integral type. **/\n    template<typename T>\n    Result visit_any_int(T)\n    {\n        return FMT_DISPATCH(visit_unhandled_arg());\n    }\n\n    /** Visits a ``double`` argument. **/\n    Result visit_double(double value)\n    {\n        return FMT_DISPATCH(visit_any_double(value));\n    }\n\n    /** Visits a ``long double`` argument. **/\n    Result visit_long_double(long double value)\n    {\n        return FMT_DISPATCH(visit_any_double(value));\n    }\n\n    /** Visits a ``double`` or ``long double`` argument. **/\n    template<typename T>\n    Result visit_any_double(T)\n    {\n        return FMT_DISPATCH(visit_unhandled_arg());\n    }\n\n    /** Visits a null-terminated C string (``const char *``) argument. **/\n    Result visit_cstring(const char *)\n    {\n        return FMT_DISPATCH(visit_unhandled_arg());\n    }\n\n    /** Visits a string argument. **/\n    Result visit_string(Arg::StringValue<char>)\n    {\n        return FMT_DISPATCH(visit_unhandled_arg());\n    }\n\n    /** Visits a wide string argument. **/\n    Result visit_wstring(Arg::StringValue<wchar_t>)\n    {\n        return FMT_DISPATCH(visit_unhandled_arg());\n    }\n\n    /** Visits a pointer argument. **/\n    Result visit_pointer(const void *)\n    {\n        return FMT_DISPATCH(visit_unhandled_arg());\n    }\n\n    /** Visits an argument of a custom (user-defined) type. **/\n    Result visit_custom(Arg::CustomValue)\n    {\n        return FMT_DISPATCH(visit_unhandled_arg());\n    }\n\n    /**\n      \\rst\n      Visits an argument dispatching to the appropriate visit method based on\n      the argument type. For example, if the argument type is ``double`` then\n      the `~fmt::ArgVisitor::visit_double()` method of the *Impl* class will be\n      called.\n      \\endrst\n     */\n    Result visit(const Arg &arg)\n    {\n        switch (arg.type)\n        {\n        case Arg::NONE:\n        case Arg::NAMED_ARG:\n            FMT_ASSERT(false, \"invalid argument type\");\n            break;\n        case Arg::INT:\n            return FMT_DISPATCH(visit_int(arg.int_value));\n        case Arg::UINT:\n            return FMT_DISPATCH(visit_uint(arg.uint_value));\n        case Arg::LONG_LONG:\n            return FMT_DISPATCH(visit_long_long(arg.long_long_value));\n        case Arg::ULONG_LONG:\n            return FMT_DISPATCH(visit_ulong_long(arg.ulong_long_value));\n        case Arg::BOOL:\n            return FMT_DISPATCH(visit_bool(arg.int_value != 0));\n        case Arg::CHAR:\n            return FMT_DISPATCH(visit_char(arg.int_value));\n        case Arg::DOUBLE:\n            return FMT_DISPATCH(visit_double(arg.double_value));\n        case Arg::LONG_DOUBLE:\n            return FMT_DISPATCH(visit_long_double(arg.long_double_value));\n        case Arg::CSTRING:\n            return FMT_DISPATCH(visit_cstring(arg.string.value));\n        case Arg::STRING:\n            return FMT_DISPATCH(visit_string(arg.string));\n        case Arg::WSTRING:\n            return FMT_DISPATCH(visit_wstring(arg.wstring));\n        case Arg::POINTER:\n            return FMT_DISPATCH(visit_pointer(arg.pointer));\n        case Arg::CUSTOM:\n            return FMT_DISPATCH(visit_custom(arg.custom));\n        }\n        return Result();\n    }\n};\n\nenum Alignment\n{\n    ALIGN_DEFAULT,\n    ALIGN_LEFT,\n    ALIGN_RIGHT,\n    ALIGN_CENTER,\n    ALIGN_NUMERIC\n};\n\n// Flags.\nenum\n{\n    SIGN_FLAG = 1,\n    PLUS_FLAG = 2,\n    MINUS_FLAG = 4,\n    HASH_FLAG = 8,\n    CHAR_FLAG = 0x10 // Argument has char type - used in error reporting.\n};\n\n// An empty format specifier.\nstruct EmptySpec\n{\n};\n\n// A type specifier.\ntemplate<char TYPE>\nstruct TypeSpec : EmptySpec\n{\n    Alignment align() const\n    {\n        return ALIGN_DEFAULT;\n    }\n    unsigned width() const\n    {\n        return 0;\n    }\n    int precision() const\n    {\n        return -1;\n    }\n    bool flag(unsigned) const\n    {\n        return false;\n    }\n    char type() const\n    {\n        return TYPE;\n    }\n    char type_prefix() const\n    {\n        return TYPE;\n    }\n    char fill() const\n    {\n        return ' ';\n    }\n};\n\n// A width specifier.\nstruct WidthSpec\n{\n    unsigned width_;\n    // Fill is always wchar_t and cast to char if necessary to avoid having\n    // two specialization of WidthSpec and its subclasses.\n    wchar_t fill_;\n\n    WidthSpec(unsigned width, wchar_t fill)\n        : width_(width)\n        , fill_(fill)\n    {\n    }\n\n    unsigned width() const\n    {\n        return width_;\n    }\n    wchar_t fill() const\n    {\n        return fill_;\n    }\n};\n\n// An alignment specifier.\nstruct AlignSpec : WidthSpec\n{\n    Alignment align_;\n\n    AlignSpec(unsigned width, wchar_t fill, Alignment align = ALIGN_DEFAULT)\n        : WidthSpec(width, fill)\n        , align_(align)\n    {\n    }\n\n    Alignment align() const\n    {\n        return align_;\n    }\n\n    int precision() const\n    {\n        return -1;\n    }\n};\n\n// An alignment and type specifier.\ntemplate<char TYPE>\nstruct AlignTypeSpec : AlignSpec\n{\n    AlignTypeSpec(unsigned width, wchar_t fill)\n        : AlignSpec(width, fill)\n    {\n    }\n\n    bool flag(unsigned) const\n    {\n        return false;\n    }\n    char type() const\n    {\n        return TYPE;\n    }\n    char type_prefix() const\n    {\n        return TYPE;\n    }\n};\n\n// A full format specifier.\nstruct FormatSpec : AlignSpec\n{\n    unsigned flags_;\n    int precision_;\n    char type_;\n\n    FormatSpec(unsigned width = 0, char type = 0, wchar_t fill = ' ')\n        : AlignSpec(width, fill)\n        , flags_(0)\n        , precision_(-1)\n        , type_(type)\n    {\n    }\n\n    bool flag(unsigned f) const\n    {\n        return (flags_ & f) != 0;\n    }\n    int precision() const\n    {\n        return precision_;\n    }\n    char type() const\n    {\n        return type_;\n    }\n    char type_prefix() const\n    {\n        return type_;\n    }\n};\n\n// An integer format specifier.\ntemplate<typename T, typename SpecT = TypeSpec<0>, typename Char = char>\nclass IntFormatSpec : public SpecT\n{\nprivate:\n    T value_;\n\npublic:\n    IntFormatSpec(T val, const SpecT &spec = SpecT())\n        : SpecT(spec)\n        , value_(val)\n    {\n    }\n\n    T value() const\n    {\n        return value_;\n    }\n};\n\n// A string format specifier.\ntemplate<typename Char>\nclass StrFormatSpec : public AlignSpec\n{\nprivate:\n    const Char *str_;\n\npublic:\n    template<typename FillChar>\n    StrFormatSpec(const Char *str, unsigned width, FillChar fill)\n        : AlignSpec(width, fill)\n        , str_(str)\n    {\n        internal::CharTraits<Char>::convert(FillChar());\n    }\n\n    const Char *str() const\n    {\n        return str_;\n    }\n};\n\n/**\n  Returns an integer format specifier to format the value in base 2.\n */\nIntFormatSpec<int, TypeSpec<'b'>> bin(int value);\n\n/**\n  Returns an integer format specifier to format the value in base 8.\n */\nIntFormatSpec<int, TypeSpec<'o'>> oct(int value);\n\n/**\n  Returns an integer format specifier to format the value in base 16 using\n  lower-case letters for the digits above 9.\n */\nIntFormatSpec<int, TypeSpec<'x'>> hex(int value);\n\n/**\n  Returns an integer formatter format specifier to format in base 16 using\n  upper-case letters for the digits above 9.\n */\nIntFormatSpec<int, TypeSpec<'X'>> hexu(int value);\n\n/**\n  \\rst\n  Returns an integer format specifier to pad the formatted argument with the\n  fill character to the specified width using the default (right) numeric\n  alignment.\n\n  **Example**::\n\n    MemoryWriter out;\n    out << pad(hex(0xcafe), 8, '0');\n    // out.str() == \"0000cafe\"\n\n  \\endrst\n */\ntemplate<char TYPE_CODE, typename Char>\nIntFormatSpec<int, AlignTypeSpec<TYPE_CODE>, Char> pad(int value, unsigned width, Char fill = ' ');\n\n#define FMT_DEFINE_INT_FORMATTERS(TYPE)                                                                                                    \\\n    inline IntFormatSpec<TYPE, TypeSpec<'b'>> bin(TYPE value)                                                                              \\\n    {                                                                                                                                      \\\n        return IntFormatSpec<TYPE, TypeSpec<'b'>>(value, TypeSpec<'b'>());                                                                 \\\n    }                                                                                                                                      \\\n                                                                                                                                           \\\n    inline IntFormatSpec<TYPE, TypeSpec<'o'>> oct(TYPE value)                                                                              \\\n    {                                                                                                                                      \\\n        return IntFormatSpec<TYPE, TypeSpec<'o'>>(value, TypeSpec<'o'>());                                                                 \\\n    }                                                                                                                                      \\\n                                                                                                                                           \\\n    inline IntFormatSpec<TYPE, TypeSpec<'x'>> hex(TYPE value)                                                                              \\\n    {                                                                                                                                      \\\n        return IntFormatSpec<TYPE, TypeSpec<'x'>>(value, TypeSpec<'x'>());                                                                 \\\n    }                                                                                                                                      \\\n                                                                                                                                           \\\n    inline IntFormatSpec<TYPE, TypeSpec<'X'>> hexu(TYPE value)                                                                             \\\n    {                                                                                                                                      \\\n        return IntFormatSpec<TYPE, TypeSpec<'X'>>(value, TypeSpec<'X'>());                                                                 \\\n    }                                                                                                                                      \\\n                                                                                                                                           \\\n    template<char TYPE_CODE>                                                                                                               \\\n    inline IntFormatSpec<TYPE, AlignTypeSpec<TYPE_CODE>> pad(IntFormatSpec<TYPE, TypeSpec<TYPE_CODE>> f, unsigned width)                   \\\n    {                                                                                                                                      \\\n        return IntFormatSpec<TYPE, AlignTypeSpec<TYPE_CODE>>(f.value(), AlignTypeSpec<TYPE_CODE>(width, ' '));                             \\\n    }                                                                                                                                      \\\n                                                                                                                                           \\\n    /* For compatibility with older compilers we provide two overloads for pad, */                                                         \\\n    /* one that takes a fill character and one that doesn't. In the future this */                                                         \\\n    /* can be replaced with one overload making the template argument Char      */                                                         \\\n    /* default to char (C++11). */                                                                                                         \\\n    template<char TYPE_CODE, typename Char>                                                                                                \\\n    inline IntFormatSpec<TYPE, AlignTypeSpec<TYPE_CODE>, Char> pad(                                                                        \\\n        IntFormatSpec<TYPE, TypeSpec<TYPE_CODE>, Char> f, unsigned width, Char fill)                                                       \\\n    {                                                                                                                                      \\\n        return IntFormatSpec<TYPE, AlignTypeSpec<TYPE_CODE>, Char>(f.value(), AlignTypeSpec<TYPE_CODE>(width, fill));                      \\\n    }                                                                                                                                      \\\n                                                                                                                                           \\\n    inline IntFormatSpec<TYPE, AlignTypeSpec<0>> pad(TYPE value, unsigned width)                                                           \\\n    {                                                                                                                                      \\\n        return IntFormatSpec<TYPE, AlignTypeSpec<0>>(value, AlignTypeSpec<0>(width, ' '));                                                 \\\n    }                                                                                                                                      \\\n                                                                                                                                           \\\n    template<typename Char>                                                                                                                \\\n    inline IntFormatSpec<TYPE, AlignTypeSpec<0>, Char> pad(TYPE value, unsigned width, Char fill)                                          \\\n    {                                                                                                                                      \\\n        return IntFormatSpec<TYPE, AlignTypeSpec<0>, Char>(value, AlignTypeSpec<0>(width, fill));                                          \\\n    }\n\nFMT_DEFINE_INT_FORMATTERS(int)\nFMT_DEFINE_INT_FORMATTERS(long)\nFMT_DEFINE_INT_FORMATTERS(unsigned)\nFMT_DEFINE_INT_FORMATTERS(unsigned long)\nFMT_DEFINE_INT_FORMATTERS(LongLong)\nFMT_DEFINE_INT_FORMATTERS(ULongLong)\n\n/**\n  \\rst\n  Returns a string formatter that pads the formatted argument with the fill\n  character to the specified width using the default (left) string alignment.\n\n  **Example**::\n\n    std::string s = str(MemoryWriter() << pad(\"abc\", 8));\n    // s == \"abc     \"\n\n  \\endrst\n */\ntemplate<typename Char>\ninline StrFormatSpec<Char> pad(const Char *str, unsigned width, Char fill = ' ')\n{\n    return StrFormatSpec<Char>(str, width, fill);\n}\n\ninline StrFormatSpec<wchar_t> pad(const wchar_t *str, unsigned width, char fill = ' ')\n{\n    return StrFormatSpec<wchar_t>(str, width, fill);\n}\n\nnamespace internal {\n\ntemplate<typename Char>\nclass ArgMap\n{\nprivate:\n    typedef std::vector<std::pair<fmt::BasicStringRef<Char>, internal::Arg>> MapType;\n    typedef typename MapType::value_type Pair;\n\n    MapType map_;\n\npublic:\n    void init(const ArgList &args);\n\n    const internal::Arg *find(const fmt::BasicStringRef<Char> &name) const\n    {\n        // The list is unsorted, so just return the first matching name.\n        for (typename MapType::const_iterator it = map_.begin(), end = map_.end(); it != end; ++it)\n        {\n            if (it->first == name)\n                return &it->second;\n        }\n        return FMT_NULL;\n    }\n};\n\ntemplate<typename Char>\nvoid ArgMap<Char>::init(const ArgList &args)\n{\n    if (!map_.empty())\n        return;\n    typedef internal::NamedArg<Char> NamedArg;\n    const NamedArg *named_arg = FMT_NULL;\n    bool use_values = args.type(ArgList::MAX_PACKED_ARGS - 1) == internal::Arg::NONE;\n    if (use_values)\n    {\n        for (unsigned i = 0; /*nothing*/; ++i)\n        {\n            internal::Arg::Type arg_type = args.type(i);\n            switch (arg_type)\n            {\n            case internal::Arg::NONE:\n                return;\n            case internal::Arg::NAMED_ARG:\n                named_arg = static_cast<const NamedArg *>(args.values_[i].pointer);\n                map_.push_back(Pair(named_arg->name, *named_arg));\n                break;\n            default:\n                /*nothing*/\n                ;\n            }\n        }\n        return;\n    }\n    for (unsigned i = 0; i != ArgList::MAX_PACKED_ARGS; ++i)\n    {\n        internal::Arg::Type arg_type = args.type(i);\n        if (arg_type == internal::Arg::NAMED_ARG)\n        {\n            named_arg = static_cast<const NamedArg *>(args.args_[i].pointer);\n            map_.push_back(Pair(named_arg->name, *named_arg));\n        }\n    }\n    for (unsigned i = ArgList::MAX_PACKED_ARGS; /*nothing*/; ++i)\n    {\n        switch (args.args_[i].type)\n        {\n        case internal::Arg::NONE:\n            return;\n        case internal::Arg::NAMED_ARG:\n            named_arg = static_cast<const NamedArg *>(args.args_[i].pointer);\n            map_.push_back(Pair(named_arg->name, *named_arg));\n            break;\n        default:\n            /*nothing*/\n            ;\n        }\n    }\n}\n\ntemplate<typename Impl, typename Char, typename Spec = fmt::FormatSpec>\nclass ArgFormatterBase : public ArgVisitor<Impl, void>\n{\nprivate:\n    BasicWriter<Char> &writer_;\n    Spec &spec_;\n\n    FMT_DISALLOW_COPY_AND_ASSIGN(ArgFormatterBase);\n\n    void write_pointer(const void *p)\n    {\n        spec_.flags_ = HASH_FLAG;\n        spec_.type_ = 'x';\n        writer_.write_int(reinterpret_cast<uintptr_t>(p), spec_);\n    }\n\n    // workaround MSVC two-phase lookup issue\n    typedef internal::Arg Arg;\n\nprotected:\n    BasicWriter<Char> &writer()\n    {\n        return writer_;\n    }\n    Spec &spec()\n    {\n        return spec_;\n    }\n\n    void write(bool value)\n    {\n        const char *str_value = value ? \"true\" : \"false\";\n        Arg::StringValue<char> str = {str_value, std::strlen(str_value)};\n        writer_.write_str(str, spec_);\n    }\n\n    void write(const char *value)\n    {\n        Arg::StringValue<char> str = {value, value ? std::strlen(value) : 0};\n        writer_.write_str(str, spec_);\n    }\n\npublic:\n    typedef Spec SpecType;\n\n    ArgFormatterBase(BasicWriter<Char> &w, Spec &s)\n        : writer_(w)\n        , spec_(s)\n    {\n    }\n\n    template<typename T>\n    void visit_any_int(T value)\n    {\n        writer_.write_int(value, spec_);\n    }\n\n    template<typename T>\n    void visit_any_double(T value)\n    {\n        writer_.write_double(value, spec_);\n    }\n\n    void visit_bool(bool value)\n    {\n        if (spec_.type_)\n        {\n            visit_any_int(value);\n            return;\n        }\n        write(value);\n    }\n\n    void visit_char(int value)\n    {\n        if (spec_.type_ && spec_.type_ != 'c')\n        {\n            spec_.flags_ |= CHAR_FLAG;\n            writer_.write_int(value, spec_);\n            return;\n        }\n        if (spec_.align_ == ALIGN_NUMERIC || spec_.flags_ != 0)\n            FMT_THROW(FormatError(\"invalid format specifier for char\"));\n        typedef typename BasicWriter<Char>::CharPtr CharPtr;\n        Char fill = internal::CharTraits<Char>::cast(spec_.fill());\n        CharPtr out = CharPtr();\n        const unsigned CHAR_SIZE = 1;\n        if (spec_.width_ > CHAR_SIZE)\n        {\n            out = writer_.grow_buffer(spec_.width_);\n            if (spec_.align_ == ALIGN_RIGHT)\n            {\n                std::uninitialized_fill_n(out, spec_.width_ - CHAR_SIZE, fill);\n                out += spec_.width_ - CHAR_SIZE;\n            }\n            else if (spec_.align_ == ALIGN_CENTER)\n            {\n                out = writer_.fill_padding(out, spec_.width_, internal::const_check(CHAR_SIZE), fill);\n            }\n            else\n            {\n                std::uninitialized_fill_n(out + CHAR_SIZE, spec_.width_ - CHAR_SIZE, fill);\n            }\n        }\n        else\n        {\n            out = writer_.grow_buffer(CHAR_SIZE);\n        }\n        *out = internal::CharTraits<Char>::cast(value);\n    }\n\n    void visit_cstring(const char *value)\n    {\n        if (spec_.type_ == 'p')\n            return write_pointer(value);\n        write(value);\n    }\n\n    // Qualification with \"internal\" here and below is a workaround for nvcc.\n    void visit_string(internal::Arg::StringValue<char> value)\n    {\n        writer_.write_str(value, spec_);\n    }\n\n    using ArgVisitor<Impl, void>::visit_wstring;\n\n    void visit_wstring(internal::Arg::StringValue<Char> value)\n    {\n        writer_.write_str(value, spec_);\n    }\n\n    void visit_pointer(const void *value)\n    {\n        if (spec_.type_ && spec_.type_ != 'p')\n            report_unknown_type(spec_.type_, \"pointer\");\n        write_pointer(value);\n    }\n};\n\nclass FormatterBase\n{\nprivate:\n    ArgList args_;\n    int next_arg_index_;\n\n    // Returns the argument with specified index.\n    FMT_API Arg do_get_arg(unsigned arg_index, const char *&error);\n\nprotected:\n    const ArgList &args() const\n    {\n        return args_;\n    }\n\n    explicit FormatterBase(const ArgList &args)\n    {\n        args_ = args;\n        next_arg_index_ = 0;\n    }\n\n    // Returns the next argument.\n    Arg next_arg(const char *&error)\n    {\n        if (next_arg_index_ >= 0)\n            return do_get_arg(internal::to_unsigned(next_arg_index_++), error);\n        error = \"cannot switch from manual to automatic argument indexing\";\n        return Arg();\n    }\n\n    // Checks if manual indexing is used and returns the argument with\n    // specified index.\n    Arg get_arg(unsigned arg_index, const char *&error)\n    {\n        return check_no_auto_index(error) ? do_get_arg(arg_index, error) : Arg();\n    }\n\n    bool check_no_auto_index(const char *&error)\n    {\n        if (next_arg_index_ > 0)\n        {\n            error = \"cannot switch from automatic to manual argument indexing\";\n            return false;\n        }\n        next_arg_index_ = -1;\n        return true;\n    }\n\n    template<typename Char>\n    void write(BasicWriter<Char> &w, const Char *start, const Char *end)\n    {\n        if (start != end)\n            w << BasicStringRef<Char>(start, internal::to_unsigned(end - start));\n    }\n};\n} // namespace internal\n\n/**\n  \\rst\n  An argument formatter based on the `curiously recurring template pattern\n  <http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern>`_.\n\n  To use `~fmt::BasicArgFormatter` define a subclass that implements some or\n  all of the visit methods with the same signatures as the methods in\n  `~fmt::ArgVisitor`, for example, `~fmt::ArgVisitor::visit_int()`.\n  Pass the subclass as the *Impl* template parameter. When a formatting\n  function processes an argument, it will dispatch to a visit method\n  specific to the argument type. For example, if the argument type is\n  ``double`` then the `~fmt::ArgVisitor::visit_double()` method of a subclass\n  will be called. If the subclass doesn't contain a method with this signature,\n  then a corresponding method of `~fmt::BasicArgFormatter` or its superclass\n  will be called.\n  \\endrst\n */\ntemplate<typename Impl, typename Char, typename Spec = fmt::FormatSpec>\nclass BasicArgFormatter : public internal::ArgFormatterBase<Impl, Char, Spec>\n{\nprivate:\n    BasicFormatter<Char, Impl> &formatter_;\n    const Char *format_;\n\npublic:\n    /**\n      \\rst\n      Constructs an argument formatter object.\n      *formatter* is a reference to the main formatter object, *spec* contains\n      format specifier information for standard argument types, and *fmt* points\n      to the part of the format string being parsed for custom argument types.\n      \\endrst\n     */\n    BasicArgFormatter(BasicFormatter<Char, Impl> &formatter, Spec &spec, const Char *fmt)\n        : internal::ArgFormatterBase<Impl, Char, Spec>(formatter.writer(), spec)\n        , formatter_(formatter)\n        , format_(fmt)\n    {\n    }\n\n    /** Formats an argument of a custom (user-defined) type. */\n    void visit_custom(internal::Arg::CustomValue c)\n    {\n        c.format(&formatter_, c.value, &format_);\n    }\n};\n\n/** The default argument formatter. */\ntemplate<typename Char>\nclass ArgFormatter : public BasicArgFormatter<ArgFormatter<Char>, Char, FormatSpec>\n{\npublic:\n    /** Constructs an argument formatter object. */\n    ArgFormatter(BasicFormatter<Char> &formatter, FormatSpec &spec, const Char *fmt)\n        : BasicArgFormatter<ArgFormatter<Char>, Char, FormatSpec>(formatter, spec, fmt)\n    {\n    }\n};\n\n/** This template formats data and writes the output to a writer. */\ntemplate<typename CharType, typename ArgFormatter>\nclass BasicFormatter : private internal::FormatterBase\n{\npublic:\n    /** The character type for the output. */\n    typedef CharType Char;\n\nprivate:\n    BasicWriter<Char> &writer_;\n    internal::ArgMap<Char> map_;\n\n    FMT_DISALLOW_COPY_AND_ASSIGN(BasicFormatter);\n\n    using internal::FormatterBase::get_arg;\n\n    // Checks if manual indexing is used and returns the argument with\n    // specified name.\n    internal::Arg get_arg(BasicStringRef<Char> arg_name, const char *&error);\n\n    // Parses argument index and returns corresponding argument.\n    internal::Arg parse_arg_index(const Char *&s);\n\n    // Parses argument name and returns corresponding argument.\n    internal::Arg parse_arg_name(const Char *&s);\n\npublic:\n    /**\n     \\rst\n     Constructs a ``BasicFormatter`` object. References to the arguments and\n     the writer are stored in the formatter object so make sure they have\n     appropriate lifetimes.\n     \\endrst\n     */\n    BasicFormatter(const ArgList &args, BasicWriter<Char> &w)\n        : internal::FormatterBase(args)\n        , writer_(w)\n    {\n    }\n\n    /** Returns a reference to the writer associated with this formatter. */\n    BasicWriter<Char> &writer()\n    {\n        return writer_;\n    }\n\n    /** Formats stored arguments and writes the output to the writer. */\n    void format(BasicCStringRef<Char> format_str);\n\n    // Formats a single argument and advances format_str, a format string pointer.\n    const Char *format(const Char *&format_str, const internal::Arg &arg);\n};\n\n// Generates a comma-separated list with results of applying f to\n// numbers 0..n-1.\n#define FMT_GEN(n, f) FMT_GEN##n(f)\n#define FMT_GEN1(f) f(0)\n#define FMT_GEN2(f) FMT_GEN1(f), f(1)\n#define FMT_GEN3(f) FMT_GEN2(f), f(2)\n#define FMT_GEN4(f) FMT_GEN3(f), f(3)\n#define FMT_GEN5(f) FMT_GEN4(f), f(4)\n#define FMT_GEN6(f) FMT_GEN5(f), f(5)\n#define FMT_GEN7(f) FMT_GEN6(f), f(6)\n#define FMT_GEN8(f) FMT_GEN7(f), f(7)\n#define FMT_GEN9(f) FMT_GEN8(f), f(8)\n#define FMT_GEN10(f) FMT_GEN9(f), f(9)\n#define FMT_GEN11(f) FMT_GEN10(f), f(10)\n#define FMT_GEN12(f) FMT_GEN11(f), f(11)\n#define FMT_GEN13(f) FMT_GEN12(f), f(12)\n#define FMT_GEN14(f) FMT_GEN13(f), f(13)\n#define FMT_GEN15(f) FMT_GEN14(f), f(14)\n\nnamespace internal {\ninline uint64_t make_type()\n{\n    return 0;\n}\n\ntemplate<typename T>\ninline uint64_t make_type(const T &arg)\n{\n    return MakeValue<BasicFormatter<char>>::type(arg);\n}\n\ntemplate<std::size_t N, bool /*IsPacked*/ = (N < ArgList::MAX_PACKED_ARGS)>\nstruct ArgArray;\n\ntemplate<std::size_t N>\nstruct ArgArray<N, true /*IsPacked*/>\n{\n    // '+' is used to silence GCC -Wduplicated-branches warning.\n    typedef Value Type[N > 0 ? N : +1];\n\n    template<typename Formatter, typename T>\n    static Value make(const T &value)\n    {\n#ifdef __clang__\n        Value result = MakeValue<Formatter>(value);\n        // Workaround a bug in Apple LLVM version 4.2 (clang-425.0.28) of clang:\n        // https://github.com/fmtlib/fmt/issues/276\n        (void)result.custom.format;\n        return result;\n#else\n        return MakeValue<Formatter>(value);\n#endif\n    }\n};\n\ntemplate<std::size_t N>\nstruct ArgArray<N, false /*IsPacked*/>\n{\n    typedef Arg Type[N + 1]; // +1 for the list end Arg::NONE\n\n    template<typename Formatter, typename T>\n    static Arg make(const T &value)\n    {\n        return MakeArg<Formatter>(value);\n    }\n};\n\n#if FMT_USE_VARIADIC_TEMPLATES\ntemplate<typename Arg, typename... Args>\ninline uint64_t make_type(const Arg &first, const Args &... tail)\n{\n    return make_type(first) | (make_type(tail...) << 4);\n}\n\n#else\n\nstruct ArgType\n{\n    uint64_t type;\n\n    ArgType()\n        : type(0)\n    {\n    }\n\n    template<typename T>\n    ArgType(const T &arg)\n        : type(make_type(arg))\n    {\n    }\n};\n\n#define FMT_ARG_TYPE_DEFAULT(n) ArgType t##n = ArgType()\n\ninline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT))\n{\n    return t0.type | (t1.type << 4) | (t2.type << 8) | (t3.type << 12) | (t4.type << 16) | (t5.type << 20) | (t6.type << 24) |\n           (t7.type << 28) | (t8.type << 32) | (t9.type << 36) | (t10.type << 40) | (t11.type << 44) | (t12.type << 48) | (t13.type << 52) |\n           (t14.type << 56);\n}\n#endif\n} // namespace internal\n\n#define FMT_MAKE_TEMPLATE_ARG(n) typename T##n\n#define FMT_MAKE_ARG_TYPE(n) T##n\n#define FMT_MAKE_ARG(n) const T##n &v##n\n#define FMT_ASSIGN_char(n) arr[n] = fmt::internal::MakeValue<fmt::BasicFormatter<char>>(v##n)\n#define FMT_ASSIGN_wchar_t(n) arr[n] = fmt::internal::MakeValue<fmt::BasicFormatter<wchar_t>>(v##n)\n\n#if FMT_USE_VARIADIC_TEMPLATES\n// Defines a variadic function returning void.\n#define FMT_VARIADIC_VOID(func, arg_type)                                                                                                  \\\n    template<typename... Args>                                                                                                             \\\n    void func(arg_type arg0, const Args &... args)                                                                                         \\\n    {                                                                                                                                      \\\n        typedef fmt::internal::ArgArray<sizeof...(Args)> ArgArray;                                                                         \\\n        typename ArgArray::Type array{ArgArray::template make<fmt::BasicFormatter<Char>>(args)...};                                        \\\n        func(arg0, fmt::ArgList(fmt::internal::make_type(args...), array));                                                                \\\n    }\n\n// Defines a variadic constructor.\n#define FMT_VARIADIC_CTOR(ctor, func, arg0_type, arg1_type)                                                                                \\\n    template<typename... Args>                                                                                                             \\\n    ctor(arg0_type arg0, arg1_type arg1, const Args &... args)                                                                             \\\n    {                                                                                                                                      \\\n        typedef fmt::internal::ArgArray<sizeof...(Args)> ArgArray;                                                                         \\\n        typename ArgArray::Type array{ArgArray::template make<fmt::BasicFormatter<Char>>(args)...};                                        \\\n        func(arg0, arg1, fmt::ArgList(fmt::internal::make_type(args...), array));                                                          \\\n    }\n\n#else\n\n#define FMT_MAKE_REF(n) fmt::internal::MakeValue<fmt::BasicFormatter<Char>>(v##n)\n#define FMT_MAKE_REF2(n) v##n\n\n// Defines a wrapper for a function taking one argument of type arg_type\n// and n additional arguments of arbitrary types.\n#define FMT_WRAP1(func, arg_type, n)                                                                                                       \\\n    template<FMT_GEN(n, FMT_MAKE_TEMPLATE_ARG)>                                                                                            \\\n    inline void func(arg_type arg1, FMT_GEN(n, FMT_MAKE_ARG))                                                                              \\\n    {                                                                                                                                      \\\n        const fmt::internal::ArgArray<n>::Type array = {FMT_GEN(n, FMT_MAKE_REF)};                                                         \\\n        func(arg1, fmt::ArgList(fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), array));                                              \\\n    }\n\n// Emulates a variadic function returning void on a pre-C++11 compiler.\n#define FMT_VARIADIC_VOID(func, arg_type)                                                                                                  \\\n    inline void func(arg_type arg)                                                                                                         \\\n    {                                                                                                                                      \\\n        func(arg, fmt::ArgList());                                                                                                         \\\n    }                                                                                                                                      \\\n    FMT_WRAP1(func, arg_type, 1)                                                                                                           \\\n    FMT_WRAP1(func, arg_type, 2)                                                                                                           \\\n    FMT_WRAP1(func, arg_type, 3)                                                                                                           \\\n    FMT_WRAP1(func, arg_type, 4)                                                                                                           \\\n    FMT_WRAP1(func, arg_type, 5)                                                                                                           \\\n    FMT_WRAP1(func, arg_type, 6)                                                                                                           \\\n    FMT_WRAP1(func, arg_type, 7) FMT_WRAP1(func, arg_type, 8) FMT_WRAP1(func, arg_type, 9) FMT_WRAP1(func, arg_type, 10)\n\n#define FMT_CTOR(ctor, func, arg0_type, arg1_type, n)                                                                                      \\\n    template<FMT_GEN(n, FMT_MAKE_TEMPLATE_ARG)>                                                                                            \\\n    ctor(arg0_type arg0, arg1_type arg1, FMT_GEN(n, FMT_MAKE_ARG))                                                                         \\\n    {                                                                                                                                      \\\n        const fmt::internal::ArgArray<n>::Type array = {FMT_GEN(n, FMT_MAKE_REF)};                                                         \\\n        func(arg0, arg1, fmt::ArgList(fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), array));                                        \\\n    }\n\n// Emulates a variadic constructor on a pre-C++11 compiler.\n#define FMT_VARIADIC_CTOR(ctor, func, arg0_type, arg1_type)                                                                                \\\n    FMT_CTOR(ctor, func, arg0_type, arg1_type, 1)                                                                                          \\\n    FMT_CTOR(ctor, func, arg0_type, arg1_type, 2)                                                                                          \\\n    FMT_CTOR(ctor, func, arg0_type, arg1_type, 3)                                                                                          \\\n    FMT_CTOR(ctor, func, arg0_type, arg1_type, 4)                                                                                          \\\n    FMT_CTOR(ctor, func, arg0_type, arg1_type, 5)                                                                                          \\\n    FMT_CTOR(ctor, func, arg0_type, arg1_type, 6)                                                                                          \\\n    FMT_CTOR(ctor, func, arg0_type, arg1_type, 7)                                                                                          \\\n    FMT_CTOR(ctor, func, arg0_type, arg1_type, 8)                                                                                          \\\n    FMT_CTOR(ctor, func, arg0_type, arg1_type, 9)                                                                                          \\\n    FMT_CTOR(ctor, func, arg0_type, arg1_type, 10)\n#endif\n\n// Generates a comma-separated list with results of applying f to pairs\n// (argument, index).\n#define FMT_FOR_EACH1(f, x0) f(x0, 0)\n#define FMT_FOR_EACH2(f, x0, x1) FMT_FOR_EACH1(f, x0), f(x1, 1)\n#define FMT_FOR_EACH3(f, x0, x1, x2) FMT_FOR_EACH2(f, x0, x1), f(x2, 2)\n#define FMT_FOR_EACH4(f, x0, x1, x2, x3) FMT_FOR_EACH3(f, x0, x1, x2), f(x3, 3)\n#define FMT_FOR_EACH5(f, x0, x1, x2, x3, x4) FMT_FOR_EACH4(f, x0, x1, x2, x3), f(x4, 4)\n#define FMT_FOR_EACH6(f, x0, x1, x2, x3, x4, x5) FMT_FOR_EACH5(f, x0, x1, x2, x3, x4), f(x5, 5)\n#define FMT_FOR_EACH7(f, x0, x1, x2, x3, x4, x5, x6) FMT_FOR_EACH6(f, x0, x1, x2, x3, x4, x5), f(x6, 6)\n#define FMT_FOR_EACH8(f, x0, x1, x2, x3, x4, x5, x6, x7) FMT_FOR_EACH7(f, x0, x1, x2, x3, x4, x5, x6), f(x7, 7)\n#define FMT_FOR_EACH9(f, x0, x1, x2, x3, x4, x5, x6, x7, x8) FMT_FOR_EACH8(f, x0, x1, x2, x3, x4, x5, x6, x7), f(x8, 8)\n#define FMT_FOR_EACH10(f, x0, x1, x2, x3, x4, x5, x6, x7, x8, x9) FMT_FOR_EACH9(f, x0, x1, x2, x3, x4, x5, x6, x7, x8), f(x9, 9)\n\n/**\n An error returned by an operating system or a language runtime,\n for example a file opening error.\n*/\nclass SystemError : public internal::RuntimeError\n{\nprivate:\n    FMT_API void init(int err_code, CStringRef format_str, ArgList args);\n\nprotected:\n    int error_code_;\n\n    typedef char Char; // For FMT_VARIADIC_CTOR.\n\n    SystemError() {}\n\npublic:\n    /**\n     \\rst\n     Constructs a :class:`fmt::SystemError` object with a description\n     formatted with `fmt::format_system_error`. *message* and additional\n     arguments passed into the constructor are formatted similarly to\n     `fmt::format`.\n\n     **Example**::\n\n       // This throws a SystemError with the description\n       //   cannot open file 'madeup': No such file or directory\n       // or similar (system message may vary).\n       const char *filename = \"madeup\";\n       std::FILE *file = std::fopen(filename, \"r\");\n       if (!file)\n         throw fmt::SystemError(errno, \"cannot open file '{}'\", filename);\n     \\endrst\n    */\n    SystemError(int error_code, CStringRef message)\n    {\n        init(error_code, message, ArgList());\n    }\n    FMT_DEFAULTED_COPY_CTOR(SystemError)\n    FMT_VARIADIC_CTOR(SystemError, init, int, CStringRef)\n\n    FMT_API ~SystemError() FMT_DTOR_NOEXCEPT FMT_OVERRIDE;\n\n    int error_code() const\n    {\n        return error_code_;\n    }\n};\n\n/**\n  \\rst\n  Formats an error returned by an operating system or a language runtime,\n  for example a file opening error, and writes it to *out* in the following\n  form:\n\n  .. parsed-literal::\n     *<message>*: *<system-message>*\n\n  where *<message>* is the passed message and *<system-message>* is\n  the system message corresponding to the error code.\n  *error_code* is a system error code as given by ``errno``.\n  If *error_code* is not a valid error code such as -1, the system message\n  may look like \"Unknown error -1\" and is platform-dependent.\n  \\endrst\n */\nFMT_API void format_system_error(fmt::Writer &out, int error_code, fmt::StringRef message) FMT_NOEXCEPT;\n\n/**\n  \\rst\n  This template provides operations for formatting and writing data into\n  a character stream. The output is stored in a buffer provided by a subclass\n  such as :class:`fmt::BasicMemoryWriter`.\n\n  You can use one of the following typedefs for common character types:\n\n  +---------+----------------------+\n  | Type    | Definition           |\n  +=========+======================+\n  | Writer  | BasicWriter<char>    |\n  +---------+----------------------+\n  | WWriter | BasicWriter<wchar_t> |\n  +---------+----------------------+\n\n  \\endrst\n */\ntemplate<typename Char>\nclass BasicWriter\n{\nprivate:\n    // Output buffer.\n    Buffer<Char> &buffer_;\n\n    FMT_DISALLOW_COPY_AND_ASSIGN(BasicWriter);\n\n    typedef typename internal::CharTraits<Char>::CharPtr CharPtr;\n\n#if FMT_SECURE_SCL\n    // Returns pointer value.\n    static Char *get(CharPtr p)\n    {\n        return p.base();\n    }\n#else\n    static Char *get(Char *p)\n    {\n        return p;\n    }\n#endif\n\n    // Fills the padding around the content and returns the pointer to the\n    // content area.\n    static CharPtr fill_padding(CharPtr buffer, unsigned total_size, std::size_t content_size, wchar_t fill);\n\n    // Grows the buffer by n characters and returns a pointer to the newly\n    // allocated area.\n    CharPtr grow_buffer(std::size_t n)\n    {\n        std::size_t size = buffer_.size();\n        buffer_.resize(size + n);\n        return internal::make_ptr(&buffer_[size], n);\n    }\n\n    // Writes an unsigned decimal integer.\n    template<typename UInt>\n    Char *write_unsigned_decimal(UInt value, unsigned prefix_size = 0)\n    {\n        unsigned num_digits = internal::count_digits(value);\n        Char *ptr = get(grow_buffer(prefix_size + num_digits));\n        internal::format_decimal(ptr + prefix_size, value, num_digits);\n        return ptr;\n    }\n\n    // Writes a decimal integer.\n    template<typename Int>\n    void write_decimal(Int value)\n    {\n        typedef typename internal::IntTraits<Int>::MainType MainType;\n        MainType abs_value = static_cast<MainType>(value);\n        if (internal::is_negative(value))\n        {\n            abs_value = 0 - abs_value;\n            *write_unsigned_decimal(abs_value, 1) = '-';\n        }\n        else\n        {\n            write_unsigned_decimal(abs_value, 0);\n        }\n    }\n\n    // Prepare a buffer for integer formatting.\n    CharPtr prepare_int_buffer(unsigned num_digits, const EmptySpec &, const char *prefix, unsigned prefix_size)\n    {\n        unsigned size = prefix_size + num_digits;\n        CharPtr p = grow_buffer(size);\n        std::uninitialized_copy(prefix, prefix + prefix_size, p);\n        return p + size - 1;\n    }\n\n    template<typename Spec>\n    CharPtr prepare_int_buffer(unsigned num_digits, const Spec &spec, const char *prefix, unsigned prefix_size);\n\n    // Formats an integer.\n    template<typename T, typename Spec>\n    void write_int(T value, Spec spec);\n\n    // Formats a floating-point number (double or long double).\n    template<typename T, typename Spec>\n    void write_double(T value, const Spec &spec);\n\n    // Writes a formatted string.\n    template<typename StrChar>\n    CharPtr write_str(const StrChar *s, std::size_t size, const AlignSpec &spec);\n\n    template<typename StrChar, typename Spec>\n    void write_str(const internal::Arg::StringValue<StrChar> &str, const Spec &spec);\n\n    // This following methods are private to disallow writing wide characters\n    // and strings to a char stream. If you want to print a wide string as a\n    // pointer as std::ostream does, cast it to const void*.\n    // Do not implement!\n    void operator<<(typename internal::WCharHelper<wchar_t, Char>::Unsupported);\n    void operator<<(typename internal::WCharHelper<const wchar_t *, Char>::Unsupported);\n\n    // Appends floating-point length specifier to the format string.\n    // The second argument is only used for overload resolution.\n    void append_float_length(Char *&format_ptr, long double)\n    {\n        *format_ptr++ = 'L';\n    }\n\n    template<typename T>\n    void append_float_length(Char *&, T)\n    {\n    }\n\n    template<typename Impl, typename Char_, typename Spec_>\n    friend class internal::ArgFormatterBase;\n\n    template<typename Impl, typename Char_, typename Spec_>\n    friend class BasicPrintfArgFormatter;\n\nprotected:\n    /**\n      Constructs a ``BasicWriter`` object.\n     */\n    explicit BasicWriter(Buffer<Char> &b)\n        : buffer_(b)\n    {\n    }\n\npublic:\n    /**\n      \\rst\n      Destroys a ``BasicWriter`` object.\n      \\endrst\n     */\n    virtual ~BasicWriter() {}\n\n    /**\n      Returns the total number of characters written.\n     */\n    std::size_t size() const\n    {\n        return buffer_.size();\n    }\n\n    /**\n      Returns a pointer to the output buffer content. No terminating null\n      character is appended.\n     */\n    const Char *data() const FMT_NOEXCEPT\n    {\n        return &buffer_[0];\n    }\n\n    /**\n      Returns a pointer to the output buffer content with terminating null\n      character appended.\n     */\n    const Char *c_str() const\n    {\n        std::size_t size = buffer_.size();\n        buffer_.reserve(size + 1);\n        buffer_[size] = '\\0';\n        return &buffer_[0];\n    }\n\n    /**\n      \\rst\n      Returns the content of the output buffer as an `std::string`.\n      \\endrst\n     */\n    std::basic_string<Char> str() const\n    {\n        return std::basic_string<Char>(&buffer_[0], buffer_.size());\n    }\n\n    /**\n      \\rst\n      Writes formatted data.\n\n      *args* is an argument list representing arbitrary arguments.\n\n      **Example**::\n\n         MemoryWriter out;\n         out.write(\"Current point:\\n\");\n         out.write(\"({:+f}, {:+f})\", -3.14, 3.14);\n\n      This will write the following output to the ``out`` object:\n\n      .. code-block:: none\n\n         Current point:\n         (-3.140000, +3.140000)\n\n      The output can be accessed using :func:`data()`, :func:`c_str` or\n      :func:`str` methods.\n\n      See also :ref:`syntax`.\n      \\endrst\n     */\n    void write(BasicCStringRef<Char> format, ArgList args)\n    {\n        BasicFormatter<Char>(args, *this).format(format);\n    }\n    FMT_VARIADIC_VOID(write, BasicCStringRef<Char>)\n\n    BasicWriter &operator<<(int value)\n    {\n        write_decimal(value);\n        return *this;\n    }\n    BasicWriter &operator<<(unsigned value)\n    {\n        return *this << IntFormatSpec<unsigned>(value);\n    }\n    BasicWriter &operator<<(long value)\n    {\n        write_decimal(value);\n        return *this;\n    }\n    BasicWriter &operator<<(unsigned long value)\n    {\n        return *this << IntFormatSpec<unsigned long>(value);\n    }\n    BasicWriter &operator<<(LongLong value)\n    {\n        write_decimal(value);\n        return *this;\n    }\n\n    /**\n      \\rst\n      Formats *value* and writes it to the stream.\n      \\endrst\n     */\n    BasicWriter &operator<<(ULongLong value)\n    {\n        return *this << IntFormatSpec<ULongLong>(value);\n    }\n\n    BasicWriter &operator<<(double value)\n    {\n        write_double(value, FormatSpec());\n        return *this;\n    }\n\n    /**\n      \\rst\n      Formats *value* using the general format for floating-point numbers\n      (``'g'``) and writes it to the stream.\n      \\endrst\n     */\n    BasicWriter &operator<<(long double value)\n    {\n        write_double(value, FormatSpec());\n        return *this;\n    }\n\n    /**\n      Writes a character to the stream.\n     */\n    BasicWriter &operator<<(char value)\n    {\n        buffer_.push_back(value);\n        return *this;\n    }\n\n    BasicWriter &operator<<(typename internal::WCharHelper<wchar_t, Char>::Supported value)\n    {\n        buffer_.push_back(value);\n        return *this;\n    }\n\n    /**\n      \\rst\n      Writes *value* to the stream.\n      \\endrst\n     */\n    BasicWriter &operator<<(fmt::BasicStringRef<Char> value)\n    {\n        const Char *str = value.data();\n        buffer_.append(str, str + value.size());\n        return *this;\n    }\n\n    BasicWriter &operator<<(typename internal::WCharHelper<StringRef, Char>::Supported value)\n    {\n        const char *str = value.data();\n        buffer_.append(str, str + value.size());\n        return *this;\n    }\n\n    template<typename T, typename Spec, typename FillChar>\n    BasicWriter &operator<<(IntFormatSpec<T, Spec, FillChar> spec)\n    {\n        internal::CharTraits<Char>::convert(FillChar());\n        write_int(spec.value(), spec);\n        return *this;\n    }\n\n    template<typename StrChar>\n    BasicWriter &operator<<(const StrFormatSpec<StrChar> &spec)\n    {\n        const StrChar *s = spec.str();\n        write_str(s, std::char_traits<Char>::length(s), spec);\n        return *this;\n    }\n\n    void clear() FMT_NOEXCEPT\n    {\n        buffer_.clear();\n    }\n\n    Buffer<Char> &buffer() FMT_NOEXCEPT\n    {\n        return buffer_;\n    }\n};\n\ntemplate<typename Char>\ntemplate<typename StrChar>\ntypename BasicWriter<Char>::CharPtr BasicWriter<Char>::write_str(const StrChar *s, std::size_t size, const AlignSpec &spec)\n{\n    CharPtr out = CharPtr();\n    if (spec.width() > size)\n    {\n        out = grow_buffer(spec.width());\n        Char fill = internal::CharTraits<Char>::cast(spec.fill());\n        if (spec.align() == ALIGN_RIGHT)\n        {\n            std::uninitialized_fill_n(out, spec.width() - size, fill);\n            out += spec.width() - size;\n        }\n        else if (spec.align() == ALIGN_CENTER)\n        {\n            out = fill_padding(out, spec.width(), size, fill);\n        }\n        else\n        {\n            std::uninitialized_fill_n(out + size, spec.width() - size, fill);\n        }\n    }\n    else\n    {\n        out = grow_buffer(size);\n    }\n    std::uninitialized_copy(s, s + size, out);\n    return out;\n}\n\ntemplate<typename Char>\ntemplate<typename StrChar, typename Spec>\nvoid BasicWriter<Char>::write_str(const internal::Arg::StringValue<StrChar> &s, const Spec &spec)\n{\n    // Check if StrChar is convertible to Char.\n    internal::CharTraits<Char>::convert(StrChar());\n    if (spec.type_ && spec.type_ != 's')\n        internal::report_unknown_type(spec.type_, \"string\");\n    const StrChar *str_value = s.value;\n    std::size_t str_size = s.size;\n    if (str_size == 0)\n    {\n        if (!str_value)\n        {\n            FMT_THROW(FormatError(\"string pointer is null\"));\n        }\n    }\n    std::size_t precision = static_cast<std::size_t>(spec.precision_);\n    if (spec.precision_ >= 0 && precision < str_size)\n        str_size = precision;\n    write_str(str_value, str_size, spec);\n}\n\ntemplate<typename Char>\ntypename BasicWriter<Char>::CharPtr BasicWriter<Char>::fill_padding(\n    CharPtr buffer, unsigned total_size, std::size_t content_size, wchar_t fill)\n{\n    std::size_t padding = total_size - content_size;\n    std::size_t left_padding = padding / 2;\n    Char fill_char = internal::CharTraits<Char>::cast(fill);\n    std::uninitialized_fill_n(buffer, left_padding, fill_char);\n    buffer += left_padding;\n    CharPtr content = buffer;\n    std::uninitialized_fill_n(buffer + content_size, padding - left_padding, fill_char);\n    return content;\n}\n\ntemplate<typename Char>\ntemplate<typename Spec>\ntypename BasicWriter<Char>::CharPtr BasicWriter<Char>::prepare_int_buffer(\n    unsigned num_digits, const Spec &spec, const char *prefix, unsigned prefix_size)\n{\n    unsigned width = spec.width();\n    Alignment align = spec.align();\n    Char fill = internal::CharTraits<Char>::cast(spec.fill());\n    if (spec.precision() > static_cast<int>(num_digits))\n    {\n        // Octal prefix '0' is counted as a digit, so ignore it if precision\n        // is specified.\n        if (prefix_size > 0 && prefix[prefix_size - 1] == '0')\n            --prefix_size;\n        unsigned number_size = prefix_size + internal::to_unsigned(spec.precision());\n        AlignSpec subspec(number_size, '0', ALIGN_NUMERIC);\n        if (number_size >= width)\n            return prepare_int_buffer(num_digits, subspec, prefix, prefix_size);\n        buffer_.reserve(width);\n        unsigned fill_size = width - number_size;\n        if (align != ALIGN_LEFT)\n        {\n            CharPtr p = grow_buffer(fill_size);\n            std::uninitialized_fill(p, p + fill_size, fill);\n        }\n        CharPtr result = prepare_int_buffer(num_digits, subspec, prefix, prefix_size);\n        if (align == ALIGN_LEFT)\n        {\n            CharPtr p = grow_buffer(fill_size);\n            std::uninitialized_fill(p, p + fill_size, fill);\n        }\n        return result;\n    }\n    unsigned size = prefix_size + num_digits;\n    if (width <= size)\n    {\n        CharPtr p = grow_buffer(size);\n        std::uninitialized_copy(prefix, prefix + prefix_size, p);\n        return p + size - 1;\n    }\n    CharPtr p = grow_buffer(width);\n    CharPtr end = p + width;\n    if (align == ALIGN_LEFT)\n    {\n        std::uninitialized_copy(prefix, prefix + prefix_size, p);\n        p += size;\n        std::uninitialized_fill(p, end, fill);\n    }\n    else if (align == ALIGN_CENTER)\n    {\n        p = fill_padding(p, width, size, fill);\n        std::uninitialized_copy(prefix, prefix + prefix_size, p);\n        p += size;\n    }\n    else\n    {\n        if (align == ALIGN_NUMERIC)\n        {\n            if (prefix_size != 0)\n            {\n                p = std::uninitialized_copy(prefix, prefix + prefix_size, p);\n                size -= prefix_size;\n            }\n        }\n        else\n        {\n            std::uninitialized_copy(prefix, prefix + prefix_size, end - size);\n        }\n        std::uninitialized_fill(p, end - size, fill);\n        p = end;\n    }\n    return p - 1;\n}\n\ntemplate<typename Char>\ntemplate<typename T, typename Spec>\nvoid BasicWriter<Char>::write_int(T value, Spec spec)\n{\n    unsigned prefix_size = 0;\n    typedef typename internal::IntTraits<T>::MainType UnsignedType;\n    UnsignedType abs_value = static_cast<UnsignedType>(value);\n    char prefix[4] = \"\";\n    if (internal::is_negative(value))\n    {\n        prefix[0] = '-';\n        ++prefix_size;\n        abs_value = 0 - abs_value;\n    }\n    else if (spec.flag(SIGN_FLAG))\n    {\n        prefix[0] = spec.flag(PLUS_FLAG) ? '+' : ' ';\n        ++prefix_size;\n    }\n    switch (spec.type())\n    {\n    case 0:\n    case 'd':\n    {\n        unsigned num_digits = internal::count_digits(abs_value);\n        CharPtr p = prepare_int_buffer(num_digits, spec, prefix, prefix_size) + 1;\n        internal::format_decimal(get(p), abs_value, 0);\n        break;\n    }\n    case 'x':\n    case 'X':\n    {\n        UnsignedType n = abs_value;\n        if (spec.flag(HASH_FLAG))\n        {\n            prefix[prefix_size++] = '0';\n            prefix[prefix_size++] = spec.type_prefix();\n        }\n        unsigned num_digits = 0;\n        do\n        {\n            ++num_digits;\n        } while ((n >>= 4) != 0);\n        Char *p = get(prepare_int_buffer(num_digits, spec, prefix, prefix_size));\n        n = abs_value;\n        const char *digits = spec.type() == 'x' ? \"0123456789abcdef\" : \"0123456789ABCDEF\";\n        do\n        {\n            *p-- = digits[n & 0xf];\n        } while ((n >>= 4) != 0);\n        break;\n    }\n    case 'b':\n    case 'B':\n    {\n        UnsignedType n = abs_value;\n        if (spec.flag(HASH_FLAG))\n        {\n            prefix[prefix_size++] = '0';\n            prefix[prefix_size++] = spec.type_prefix();\n        }\n        unsigned num_digits = 0;\n        do\n        {\n            ++num_digits;\n        } while ((n >>= 1) != 0);\n        Char *p = get(prepare_int_buffer(num_digits, spec, prefix, prefix_size));\n        n = abs_value;\n        do\n        {\n            *p-- = static_cast<Char>('0' + (n & 1));\n        } while ((n >>= 1) != 0);\n        break;\n    }\n    case 'o':\n    {\n        UnsignedType n = abs_value;\n        if (spec.flag(HASH_FLAG))\n            prefix[prefix_size++] = '0';\n        unsigned num_digits = 0;\n        do\n        {\n            ++num_digits;\n        } while ((n >>= 3) != 0);\n        Char *p = get(prepare_int_buffer(num_digits, spec, prefix, prefix_size));\n        n = abs_value;\n        do\n        {\n            *p-- = static_cast<Char>('0' + (n & 7));\n        } while ((n >>= 3) != 0);\n        break;\n    }\n    case 'n':\n    {\n        unsigned num_digits = internal::count_digits(abs_value);\n        fmt::StringRef sep = \"\";\n#if !(defined(ANDROID) || defined(__ANDROID__))\n        sep = internal::thousands_sep(std::localeconv());\n#endif\n        unsigned size = static_cast<unsigned>(num_digits + sep.size() * ((num_digits - 1) / 3));\n        CharPtr p = prepare_int_buffer(size, spec, prefix, prefix_size) + 1;\n        internal::format_decimal(get(p), abs_value, 0, internal::ThousandsSep(sep));\n        break;\n    }\n    default:\n        internal::report_unknown_type(spec.type(), spec.flag(CHAR_FLAG) ? \"char\" : \"integer\");\n        break;\n    }\n}\n\ntemplate<typename Char>\ntemplate<typename T, typename Spec>\nvoid BasicWriter<Char>::write_double(T value, const Spec &spec)\n{\n    // Check type.\n    char type = spec.type();\n    bool upper = false;\n    switch (type)\n    {\n    case 0:\n        type = 'g';\n        break;\n    case 'e':\n    case 'f':\n    case 'g':\n    case 'a':\n        break;\n    case 'F':\n#if FMT_MSC_VER\n        // MSVC's printf doesn't support 'F'.\n        type = 'f';\n#endif\n    // Fall through.\n    case 'E':\n    case 'G':\n    case 'A':\n        upper = true;\n        break;\n    default:\n        internal::report_unknown_type(type, \"double\");\n        break;\n    }\n\n    char sign = 0;\n    // Use isnegative instead of value < 0 because the latter is always\n    // false for NaN.\n    if (internal::FPUtil::isnegative(static_cast<double>(value)))\n    {\n        sign = '-';\n        value = -value;\n    }\n    else if (spec.flag(SIGN_FLAG))\n    {\n        sign = spec.flag(PLUS_FLAG) ? '+' : ' ';\n    }\n\n    if (internal::FPUtil::isnotanumber(value))\n    {\n        // Format NaN ourselves because sprintf's output is not consistent\n        // across platforms.\n        std::size_t nan_size = 4;\n        const char *nan = upper ? \" NAN\" : \" nan\";\n        if (!sign)\n        {\n            --nan_size;\n            ++nan;\n        }\n        CharPtr out = write_str(nan, nan_size, spec);\n        if (sign)\n            *out = sign;\n        return;\n    }\n\n    if (internal::FPUtil::isinfinity(value))\n    {\n        // Format infinity ourselves because sprintf's output is not consistent\n        // across platforms.\n        std::size_t inf_size = 4;\n        const char *inf = upper ? \" INF\" : \" inf\";\n        if (!sign)\n        {\n            --inf_size;\n            ++inf;\n        }\n        CharPtr out = write_str(inf, inf_size, spec);\n        if (sign)\n            *out = sign;\n        return;\n    }\n\n    std::size_t offset = buffer_.size();\n    unsigned width = spec.width();\n    if (sign)\n    {\n        buffer_.reserve(buffer_.size() + (width > 1u ? width : 1u));\n        if (width > 0)\n            --width;\n        ++offset;\n    }\n\n    // Build format string.\n    enum\n    {\n        MAX_FORMAT_SIZE = 10\n    }; // longest format: %#-*.*Lg\n    Char format[MAX_FORMAT_SIZE];\n    Char *format_ptr = format;\n    *format_ptr++ = '%';\n    unsigned width_for_sprintf = width;\n    if (spec.flag(HASH_FLAG))\n        *format_ptr++ = '#';\n    if (spec.align() == ALIGN_CENTER)\n    {\n        width_for_sprintf = 0;\n    }\n    else\n    {\n        if (spec.align() == ALIGN_LEFT)\n            *format_ptr++ = '-';\n        if (width != 0)\n            *format_ptr++ = '*';\n    }\n    if (spec.precision() >= 0)\n    {\n        *format_ptr++ = '.';\n        *format_ptr++ = '*';\n    }\n\n    append_float_length(format_ptr, value);\n    *format_ptr++ = type;\n    *format_ptr = '\\0';\n\n    // Format using snprintf.\n    Char fill = internal::CharTraits<Char>::cast(spec.fill());\n    unsigned n = 0;\n    Char *start = FMT_NULL;\n    for (;;)\n    {\n        std::size_t buffer_size = buffer_.capacity() - offset;\n#if FMT_MSC_VER\n        // MSVC's vsnprintf_s doesn't work with zero size, so reserve\n        // space for at least one extra character to make the size non-zero.\n        // Note that the buffer's capacity will increase by more than 1.\n        if (buffer_size == 0)\n        {\n            buffer_.reserve(offset + 1);\n            buffer_size = buffer_.capacity() - offset;\n        }\n#endif\n        start = &buffer_[offset];\n        int result = internal::CharTraits<Char>::format_float(start, buffer_size, format, width_for_sprintf, spec.precision(), value);\n        if (result >= 0)\n        {\n            n = internal::to_unsigned(result);\n            if (offset + n < buffer_.capacity())\n                break; // The buffer is large enough - continue with formatting.\n            buffer_.reserve(offset + n + 1);\n        }\n        else\n        {\n            // If result is negative we ask to increase the capacity by at least 1,\n            // but as std::vector, the buffer grows exponentially.\n            buffer_.reserve(buffer_.capacity() + 1);\n        }\n    }\n    if (sign)\n    {\n        if ((spec.align() != ALIGN_RIGHT && spec.align() != ALIGN_DEFAULT) || *start != ' ')\n        {\n            *(start - 1) = sign;\n            sign = 0;\n        }\n        else\n        {\n            *(start - 1) = fill;\n        }\n        ++n;\n    }\n    if (spec.align() == ALIGN_CENTER && spec.width() > n)\n    {\n        width = spec.width();\n        CharPtr p = grow_buffer(width);\n        std::memmove(get(p) + (width - n) / 2, get(p), n * sizeof(Char));\n        fill_padding(p, spec.width(), n, fill);\n        return;\n    }\n    if (spec.fill() != ' ' || sign)\n    {\n        while (*start == ' ')\n            *start++ = fill;\n        if (sign)\n            *(start - 1) = sign;\n    }\n    grow_buffer(n);\n}\n\n/**\n  \\rst\n  This class template provides operations for formatting and writing data\n  into a character stream. The output is stored in a memory buffer that grows\n  dynamically.\n\n  You can use one of the following typedefs for common character types\n  and the standard allocator:\n\n  +---------------+-----------------------------------------------------+\n  | Type          | Definition                                          |\n  +===============+=====================================================+\n  | MemoryWriter  | BasicMemoryWriter<char, std::allocator<char>>       |\n  +---------------+-----------------------------------------------------+\n  | WMemoryWriter | BasicMemoryWriter<wchar_t, std::allocator<wchar_t>> |\n  +---------------+-----------------------------------------------------+\n\n  **Example**::\n\n     MemoryWriter out;\n     out << \"The answer is \" << 42 << \"\\n\";\n     out.write(\"({:+f}, {:+f})\", -3.14, 3.14);\n\n  This will write the following output to the ``out`` object:\n\n  .. code-block:: none\n\n     The answer is 42\n     (-3.140000, +3.140000)\n\n  The output can be converted to an ``std::string`` with ``out.str()`` or\n  accessed as a C string with ``out.c_str()``.\n  \\endrst\n */\ntemplate<typename Char, typename Allocator = std::allocator<Char>>\nclass BasicMemoryWriter : public BasicWriter<Char>\n{\nprivate:\n    internal::MemoryBuffer<Char, internal::INLINE_BUFFER_SIZE, Allocator> buffer_;\n\npublic:\n    explicit BasicMemoryWriter(const Allocator &alloc = Allocator())\n        : BasicWriter<Char>(buffer_)\n        , buffer_(alloc)\n    {\n    }\n\n#if FMT_USE_RVALUE_REFERENCES\n    /**\n      \\rst\n      Constructs a :class:`fmt::BasicMemoryWriter` object moving the content\n      of the other object to it.\n      \\endrst\n     */\n    BasicMemoryWriter(BasicMemoryWriter &&other)\n        : BasicWriter<Char>(buffer_)\n        , buffer_(std::move(other.buffer_))\n    {\n    }\n\n    /**\n      \\rst\n      Moves the content of the other ``BasicMemoryWriter`` object to this one.\n      \\endrst\n     */\n    BasicMemoryWriter &operator=(BasicMemoryWriter &&other)\n    {\n        buffer_ = std::move(other.buffer_);\n        return *this;\n    }\n#endif\n};\n\ntypedef BasicMemoryWriter<char> MemoryWriter;\ntypedef BasicMemoryWriter<wchar_t> WMemoryWriter;\n\n/**\n  \\rst\n  This class template provides operations for formatting and writing data\n  into a fixed-size array. For writing into a dynamically growing buffer\n  use :class:`fmt::BasicMemoryWriter`.\n\n  Any write method will throw ``std::runtime_error`` if the output doesn't fit\n  into the array.\n\n  You can use one of the following typedefs for common character types:\n\n  +--------------+---------------------------+\n  | Type         | Definition                |\n  +==============+===========================+\n  | ArrayWriter  | BasicArrayWriter<char>    |\n  +--------------+---------------------------+\n  | WArrayWriter | BasicArrayWriter<wchar_t> |\n  +--------------+---------------------------+\n  \\endrst\n */\ntemplate<typename Char>\nclass BasicArrayWriter : public BasicWriter<Char>\n{\nprivate:\n    internal::FixedBuffer<Char> buffer_;\n\npublic:\n    /**\n     \\rst\n     Constructs a :class:`fmt::BasicArrayWriter` object for *array* of the\n     given size.\n     \\endrst\n     */\n    BasicArrayWriter(Char *array, std::size_t size)\n        : BasicWriter<Char>(buffer_)\n        , buffer_(array, size)\n    {\n    }\n\n    /**\n     \\rst\n     Constructs a :class:`fmt::BasicArrayWriter` object for *array* of the\n     size known at compile time.\n     \\endrst\n     */\n    template<std::size_t SIZE>\n    explicit BasicArrayWriter(Char (&array)[SIZE])\n        : BasicWriter<Char>(buffer_)\n        , buffer_(array, SIZE)\n    {\n    }\n};\n\ntypedef BasicArrayWriter<char> ArrayWriter;\ntypedef BasicArrayWriter<wchar_t> WArrayWriter;\n\n// Reports a system error without throwing an exception.\n// Can be used to report errors from destructors.\nFMT_API void report_system_error(int error_code, StringRef message) FMT_NOEXCEPT;\n\n#if FMT_USE_WINDOWS_H\n\n/** A Windows error. */\nclass WindowsError : public SystemError\n{\nprivate:\n    FMT_API void init(int error_code, CStringRef format_str, ArgList args);\n\npublic:\n    /**\n     \\rst\n     Constructs a :class:`fmt::WindowsError` object with the description\n     of the form\n\n     .. parsed-literal::\n       *<message>*: *<system-message>*\n\n     where *<message>* is the formatted message and *<system-message>* is the\n     system message corresponding to the error code.\n     *error_code* is a Windows error code as given by ``GetLastError``.\n     If *error_code* is not a valid error code such as -1, the system message\n     will look like \"error -1\".\n\n     **Example**::\n\n       // This throws a WindowsError with the description\n       //   cannot open file 'madeup': The system cannot find the file specified.\n       // or similar (system message may vary).\n       const char *filename = \"madeup\";\n       LPOFSTRUCT of = LPOFSTRUCT();\n       HFILE file = OpenFile(filename, &of, OF_READ);\n       if (file == HFILE_ERROR) {\n         throw fmt::WindowsError(GetLastError(),\n                                 \"cannot open file '{}'\", filename);\n       }\n     \\endrst\n    */\n    WindowsError(int error_code, CStringRef message)\n    {\n        init(error_code, message, ArgList());\n    }\n    FMT_VARIADIC_CTOR(WindowsError, init, int, CStringRef)\n};\n\n// Reports a Windows error without throwing an exception.\n// Can be used to report errors from destructors.\nFMT_API void report_windows_error(int error_code, StringRef message) FMT_NOEXCEPT;\n\n#endif\n\nenum Color\n{\n    BLACK,\n    RED,\n    GREEN,\n    YELLOW,\n    BLUE,\n    MAGENTA,\n    CYAN,\n    WHITE\n};\n\n/**\n  Formats a string and prints it to stdout using ANSI escape sequences\n  to specify color (experimental).\n  Example:\n    print_colored(fmt::RED, \"Elapsed time: {0:.2f} seconds\", 1.23);\n */\nFMT_API void print_colored(Color c, CStringRef format, ArgList args);\n\n/**\n  \\rst\n  Formats arguments and returns the result as a string.\n\n  **Example**::\n\n    std::string message = format(\"The answer is {}\", 42);\n  \\endrst\n*/\ninline std::string format(CStringRef format_str, ArgList args)\n{\n    MemoryWriter w;\n    w.write(format_str, args);\n    return w.str();\n}\n\ninline std::wstring format(WCStringRef format_str, ArgList args)\n{\n    WMemoryWriter w;\n    w.write(format_str, args);\n    return w.str();\n}\n\n/**\n  \\rst\n  Prints formatted data to the file *f*.\n\n  **Example**::\n\n    print(stderr, \"Don't {}!\", \"panic\");\n  \\endrst\n */\nFMT_API void print(std::FILE *f, CStringRef format_str, ArgList args);\n\n/**\n  \\rst\n  Prints formatted data to ``stdout``.\n\n  **Example**::\n\n    print(\"Elapsed time: {0:.2f} seconds\", 1.23);\n  \\endrst\n */\nFMT_API void print(CStringRef format_str, ArgList args);\n\n/**\n  Fast integer formatter.\n */\nclass FormatInt\n{\nprivate:\n    // Buffer should be large enough to hold all digits (digits10 + 1),\n    // a sign and a null character.\n    enum\n    {\n        BUFFER_SIZE = std::numeric_limits<ULongLong>::digits10 + 3\n    };\n    mutable char buffer_[BUFFER_SIZE];\n    char *str_;\n\n    // Formats value in reverse and returns the number of digits.\n    char *format_decimal(ULongLong value)\n    {\n        char *buffer_end = buffer_ + BUFFER_SIZE - 1;\n        while (value >= 100)\n        {\n            // Integer division is slow so do it for a group of two digits instead\n            // of for every digit. The idea comes from the talk by Alexandrescu\n            // \"Three Optimization Tips for C++\". See speed-test for a comparison.\n            unsigned index = static_cast<unsigned>((value % 100) * 2);\n            value /= 100;\n            *--buffer_end = internal::Data::DIGITS[index + 1];\n            *--buffer_end = internal::Data::DIGITS[index];\n        }\n        if (value < 10)\n        {\n            *--buffer_end = static_cast<char>('0' + value);\n            return buffer_end;\n        }\n        unsigned index = static_cast<unsigned>(value * 2);\n        *--buffer_end = internal::Data::DIGITS[index + 1];\n        *--buffer_end = internal::Data::DIGITS[index];\n        return buffer_end;\n    }\n\n    void FormatSigned(LongLong value)\n    {\n        ULongLong abs_value = static_cast<ULongLong>(value);\n        bool negative = value < 0;\n        if (negative)\n            abs_value = 0 - abs_value;\n        str_ = format_decimal(abs_value);\n        if (negative)\n            *--str_ = '-';\n    }\n\npublic:\n    explicit FormatInt(int value)\n    {\n        FormatSigned(value);\n    }\n    explicit FormatInt(long value)\n    {\n        FormatSigned(value);\n    }\n    explicit FormatInt(LongLong value)\n    {\n        FormatSigned(value);\n    }\n    explicit FormatInt(unsigned value)\n        : str_(format_decimal(value))\n    {\n    }\n    explicit FormatInt(unsigned long value)\n        : str_(format_decimal(value))\n    {\n    }\n    explicit FormatInt(ULongLong value)\n        : str_(format_decimal(value))\n    {\n    }\n\n    /** Returns the number of characters written to the output buffer. */\n    std::size_t size() const\n    {\n        return internal::to_unsigned(buffer_ - str_ + BUFFER_SIZE - 1);\n    }\n\n    /**\n      Returns a pointer to the output buffer content. No terminating null\n      character is appended.\n     */\n    const char *data() const\n    {\n        return str_;\n    }\n\n    /**\n      Returns a pointer to the output buffer content with terminating null\n      character appended.\n     */\n    const char *c_str() const\n    {\n        buffer_[BUFFER_SIZE - 1] = '\\0';\n        return str_;\n    }\n\n    /**\n      \\rst\n      Returns the content of the output buffer as an ``std::string``.\n      \\endrst\n     */\n    std::string str() const\n    {\n        return std::string(str_, size());\n    }\n};\n\n// Formats a decimal integer value writing into buffer and returns\n// a pointer to the end of the formatted string. This function doesn't\n// write a terminating null character.\ntemplate<typename T>\ninline void format_decimal(char *&buffer, T value)\n{\n    typedef typename internal::IntTraits<T>::MainType MainType;\n    MainType abs_value = static_cast<MainType>(value);\n    if (internal::is_negative(value))\n    {\n        *buffer++ = '-';\n        abs_value = 0 - abs_value;\n    }\n    if (abs_value < 100)\n    {\n        if (abs_value < 10)\n        {\n            *buffer++ = static_cast<char>('0' + abs_value);\n            return;\n        }\n        unsigned index = static_cast<unsigned>(abs_value * 2);\n        *buffer++ = internal::Data::DIGITS[index];\n        *buffer++ = internal::Data::DIGITS[index + 1];\n        return;\n    }\n    unsigned num_digits = internal::count_digits(abs_value);\n    internal::format_decimal(buffer, abs_value, num_digits);\n    buffer += num_digits;\n}\n\n/**\n  \\rst\n  Returns a named argument for formatting functions.\n\n  **Example**::\n\n    print(\"Elapsed time: {s:.2f} seconds\", arg(\"s\", 1.23));\n\n  \\endrst\n */\ntemplate<typename T>\ninline internal::NamedArgWithType<char, T> arg(StringRef name, const T &arg)\n{\n    return internal::NamedArgWithType<char, T>(name, arg);\n}\n\ntemplate<typename T>\ninline internal::NamedArgWithType<wchar_t, T> arg(WStringRef name, const T &arg)\n{\n    return internal::NamedArgWithType<wchar_t, T>(name, arg);\n}\n\n// The following two functions are deleted intentionally to disable\n// nested named arguments as in ``format(\"{}\", arg(\"a\", arg(\"b\", 42)))``.\ntemplate<typename Char>\nvoid arg(StringRef, const internal::NamedArg<Char> &) FMT_DELETED_OR_UNDEFINED;\ntemplate<typename Char>\nvoid arg(WStringRef, const internal::NamedArg<Char> &) FMT_DELETED_OR_UNDEFINED;\n} // namespace fmt\n\n#if FMT_GCC_VERSION\n// Use the system_header pragma to suppress warnings about variadic macros\n// because suppressing -Wvariadic-macros with the diagnostic pragma doesn't\n// work. It is used at the end because we want to suppress as little warnings\n// as possible.\n#pragma GCC system_header\n#endif\n\n// This is used to work around VC++ bugs in handling variadic macros.\n#define FMT_EXPAND(args) args\n\n// Returns the number of arguments.\n// Based on https://groups.google.com/forum/#!topic/comp.std.c/d-6Mj5Lko_s.\n#define FMT_NARG(...) FMT_NARG_(__VA_ARGS__, FMT_RSEQ_N())\n#define FMT_NARG_(...) FMT_EXPAND(FMT_ARG_N(__VA_ARGS__))\n#define FMT_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N\n#define FMT_RSEQ_N() 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0\n\n#define FMT_FOR_EACH_(N, f, ...) FMT_EXPAND(FMT_CONCAT(FMT_FOR_EACH, N)(f, __VA_ARGS__))\n#define FMT_FOR_EACH(f, ...) FMT_EXPAND(FMT_FOR_EACH_(FMT_NARG(__VA_ARGS__), f, __VA_ARGS__))\n\n#define FMT_ADD_ARG_NAME(type, index) type arg##index\n#define FMT_GET_ARG_NAME(type, index) arg##index\n\n#if FMT_USE_VARIADIC_TEMPLATES\n#define FMT_VARIADIC_(Const, Char, ReturnType, func, call, ...)                                                                            \\\n    template<typename... Args>                                                                                                             \\\n    ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), const Args &... args) Const                                               \\\n    {                                                                                                                                      \\\n        typedef fmt::internal::ArgArray<sizeof...(Args)> ArgArray;                                                                         \\\n        typename ArgArray::Type array{ArgArray::template make<fmt::BasicFormatter<Char>>(args)...};                                        \\\n        call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), fmt::ArgList(fmt::internal::make_type(args...), array));                         \\\n    }\n#else\n// Defines a wrapper for a function taking __VA_ARGS__ arguments\n// and n additional arguments of arbitrary types.\n#define FMT_WRAP(Const, Char, ReturnType, func, call, n, ...)                                                                              \\\n    template<FMT_GEN(n, FMT_MAKE_TEMPLATE_ARG)>                                                                                            \\\n    inline ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), FMT_GEN(n, FMT_MAKE_ARG)) Const                                    \\\n    {                                                                                                                                      \\\n        fmt::internal::ArgArray<n>::Type arr;                                                                                              \\\n        FMT_GEN(n, FMT_ASSIGN_##Char);                                                                                                     \\\n        call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), fmt::ArgList(fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), arr));         \\\n    }\n\n#define FMT_VARIADIC_(Const, Char, ReturnType, func, call, ...)                                                                            \\\n    inline ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__)) Const                                                              \\\n    {                                                                                                                                      \\\n        call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), fmt::ArgList());                                                                 \\\n    }                                                                                                                                      \\\n    FMT_WRAP(Const, Char, ReturnType, func, call, 1, __VA_ARGS__)                                                                          \\\n    FMT_WRAP(Const, Char, ReturnType, func, call, 2, __VA_ARGS__)                                                                          \\\n    FMT_WRAP(Const, Char, ReturnType, func, call, 3, __VA_ARGS__)                                                                          \\\n    FMT_WRAP(Const, Char, ReturnType, func, call, 4, __VA_ARGS__)                                                                          \\\n    FMT_WRAP(Const, Char, ReturnType, func, call, 5, __VA_ARGS__)                                                                          \\\n    FMT_WRAP(Const, Char, ReturnType, func, call, 6, __VA_ARGS__)                                                                          \\\n    FMT_WRAP(Const, Char, ReturnType, func, call, 7, __VA_ARGS__)                                                                          \\\n    FMT_WRAP(Const, Char, ReturnType, func, call, 8, __VA_ARGS__)                                                                          \\\n    FMT_WRAP(Const, Char, ReturnType, func, call, 9, __VA_ARGS__)                                                                          \\\n    FMT_WRAP(Const, Char, ReturnType, func, call, 10, __VA_ARGS__)                                                                         \\\n    FMT_WRAP(Const, Char, ReturnType, func, call, 11, __VA_ARGS__)                                                                         \\\n    FMT_WRAP(Const, Char, ReturnType, func, call, 12, __VA_ARGS__)                                                                         \\\n    FMT_WRAP(Const, Char, ReturnType, func, call, 13, __VA_ARGS__)                                                                         \\\n    FMT_WRAP(Const, Char, ReturnType, func, call, 14, __VA_ARGS__)                                                                         \\\n    FMT_WRAP(Const, Char, ReturnType, func, call, 15, __VA_ARGS__)\n#endif // FMT_USE_VARIADIC_TEMPLATES\n\n/**\n  \\rst\n  Defines a variadic function with the specified return type, function name\n  and argument types passed as variable arguments to this macro.\n\n  **Example**::\n\n    void print_error(const char *file, int line, const char *format,\n                     fmt::ArgList args) {\n      fmt::print(\"{}: {}: \", file, line);\n      fmt::print(format, args);\n    }\n    FMT_VARIADIC(void, print_error, const char *, int, const char *)\n\n  ``FMT_VARIADIC`` is used for compatibility with legacy C++ compilers that\n  don't implement variadic templates. You don't have to use this macro if\n  you don't need legacy compiler support and can use variadic templates\n  directly::\n\n    template <typename... Args>\n    void print_error(const char *file, int line, const char *format,\n                     const Args & ... args) {\n      fmt::print(\"{}: {}: \", file, line);\n      fmt::print(format, args...);\n    }\n  \\endrst\n */\n#define FMT_VARIADIC(ReturnType, func, ...) FMT_VARIADIC_(, char, ReturnType, func, return func, __VA_ARGS__)\n\n#define FMT_VARIADIC_CONST(ReturnType, func, ...) FMT_VARIADIC_(const, char, ReturnType, func, return func, __VA_ARGS__)\n\n#define FMT_VARIADIC_W(ReturnType, func, ...) FMT_VARIADIC_(, wchar_t, ReturnType, func, return func, __VA_ARGS__)\n\n#define FMT_VARIADIC_CONST_W(ReturnType, func, ...) FMT_VARIADIC_(const, wchar_t, ReturnType, func, return func, __VA_ARGS__)\n\n#define FMT_CAPTURE_ARG_(id, index) ::fmt::arg(#id, id)\n\n#define FMT_CAPTURE_ARG_W_(id, index) ::fmt::arg(L## #id, id)\n\n/**\n  \\rst\n  Convenient macro to capture the arguments' names and values into several\n  ``fmt::arg(name, value)``.\n\n  **Example**::\n\n    int x = 1, y = 2;\n    print(\"point: ({x}, {y})\", FMT_CAPTURE(x, y));\n    // same as:\n    // print(\"point: ({x}, {y})\", arg(\"x\", x), arg(\"y\", y));\n\n  \\endrst\n */\n#define FMT_CAPTURE(...) FMT_FOR_EACH(FMT_CAPTURE_ARG_, __VA_ARGS__)\n\n#define FMT_CAPTURE_W(...) FMT_FOR_EACH(FMT_CAPTURE_ARG_W_, __VA_ARGS__)\n\nnamespace fmt {\nFMT_VARIADIC(std::string, format, CStringRef)\nFMT_VARIADIC_W(std::wstring, format, WCStringRef)\nFMT_VARIADIC(void, print, CStringRef)\nFMT_VARIADIC(void, print, std::FILE *, CStringRef)\nFMT_VARIADIC(void, print_colored, Color, CStringRef)\n\nnamespace internal {\ntemplate<typename Char>\ninline bool is_name_start(Char c)\n{\n    return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || '_' == c;\n}\n\n// Parses an unsigned integer advancing s to the end of the parsed input.\n// This function assumes that the first character of s is a digit.\ntemplate<typename Char>\nunsigned parse_nonnegative_int(const Char *&s)\n{\n    assert('0' <= *s && *s <= '9');\n    unsigned value = 0;\n    // Convert to unsigned to prevent a warning.\n    unsigned max_int = (std::numeric_limits<int>::max)();\n    unsigned big = max_int / 10;\n    do\n    {\n        // Check for overflow.\n        if (value > big)\n        {\n            value = max_int + 1;\n            break;\n        }\n        value = value * 10 + (*s - '0');\n        ++s;\n    } while ('0' <= *s && *s <= '9');\n    // Convert to unsigned to prevent a warning.\n    if (value > max_int)\n        FMT_THROW(FormatError(\"number is too big\"));\n    return value;\n}\n\ninline void require_numeric_argument(const Arg &arg, char spec)\n{\n    if (arg.type > Arg::LAST_NUMERIC_TYPE)\n    {\n        std::string message = fmt::format(\"format specifier '{}' requires numeric argument\", spec);\n        FMT_THROW(fmt::FormatError(message));\n    }\n}\n\ntemplate<typename Char>\nvoid check_sign(const Char *&s, const Arg &arg)\n{\n    char sign = static_cast<char>(*s);\n    require_numeric_argument(arg, sign);\n    if (arg.type == Arg::UINT || arg.type == Arg::ULONG_LONG)\n    {\n        FMT_THROW(FormatError(fmt::format(\"format specifier '{}' requires signed argument\", sign)));\n    }\n    ++s;\n}\n} // namespace internal\n\ntemplate<typename Char, typename AF>\ninline internal::Arg BasicFormatter<Char, AF>::get_arg(BasicStringRef<Char> arg_name, const char *&error)\n{\n    if (check_no_auto_index(error))\n    {\n        map_.init(args());\n        const internal::Arg *arg = map_.find(arg_name);\n        if (arg)\n            return *arg;\n        error = \"argument not found\";\n    }\n    return internal::Arg();\n}\n\ntemplate<typename Char, typename AF>\ninline internal::Arg BasicFormatter<Char, AF>::parse_arg_index(const Char *&s)\n{\n    const char *error = FMT_NULL;\n    internal::Arg arg = *s < '0' || *s > '9' ? next_arg(error) : get_arg(internal::parse_nonnegative_int(s), error);\n    if (error)\n    {\n        FMT_THROW(FormatError(*s != '}' && *s != ':' ? \"invalid format string\" : error));\n    }\n    return arg;\n}\n\ntemplate<typename Char, typename AF>\ninline internal::Arg BasicFormatter<Char, AF>::parse_arg_name(const Char *&s)\n{\n    assert(internal::is_name_start(*s));\n    const Char *start = s;\n    Char c;\n    do\n    {\n        c = *++s;\n    } while (internal::is_name_start(c) || ('0' <= c && c <= '9'));\n    const char *error = FMT_NULL;\n    internal::Arg arg = get_arg(BasicStringRef<Char>(start, s - start), error);\n    if (error)\n        FMT_THROW(FormatError(error));\n    return arg;\n}\n\ntemplate<typename Char, typename ArgFormatter>\nconst Char *BasicFormatter<Char, ArgFormatter>::format(const Char *&format_str, const internal::Arg &arg)\n{\n    using internal::Arg;\n    const Char *s = format_str;\n    typename ArgFormatter::SpecType spec;\n    if (*s == ':')\n    {\n        if (arg.type == Arg::CUSTOM)\n        {\n            arg.custom.format(this, arg.custom.value, &s);\n            return s;\n        }\n        ++s;\n        // Parse fill and alignment.\n        if (Char c = *s)\n        {\n            const Char *p = s + 1;\n            spec.align_ = ALIGN_DEFAULT;\n            do\n            {\n                switch (*p)\n                {\n                case '<':\n                    spec.align_ = ALIGN_LEFT;\n                    break;\n                case '>':\n                    spec.align_ = ALIGN_RIGHT;\n                    break;\n                case '=':\n                    spec.align_ = ALIGN_NUMERIC;\n                    break;\n                case '^':\n                    spec.align_ = ALIGN_CENTER;\n                    break;\n                }\n                if (spec.align_ != ALIGN_DEFAULT)\n                {\n                    if (p != s)\n                    {\n                        if (c == '}')\n                            break;\n                        if (c == '{')\n                            FMT_THROW(FormatError(\"invalid fill character '{'\"));\n                        s += 2;\n                        spec.fill_ = c;\n                    }\n                    else\n                        ++s;\n                    if (spec.align_ == ALIGN_NUMERIC)\n                        require_numeric_argument(arg, '=');\n                    break;\n                }\n            } while (--p >= s);\n        }\n\n        // Parse sign.\n        switch (*s)\n        {\n        case '+':\n            check_sign(s, arg);\n            spec.flags_ |= SIGN_FLAG | PLUS_FLAG;\n            break;\n        case '-':\n            check_sign(s, arg);\n            spec.flags_ |= MINUS_FLAG;\n            break;\n        case ' ':\n            check_sign(s, arg);\n            spec.flags_ |= SIGN_FLAG;\n            break;\n        }\n\n        if (*s == '#')\n        {\n            require_numeric_argument(arg, '#');\n            spec.flags_ |= HASH_FLAG;\n            ++s;\n        }\n\n        // Parse zero flag.\n        if (*s == '0')\n        {\n            require_numeric_argument(arg, '0');\n            spec.align_ = ALIGN_NUMERIC;\n            spec.fill_ = '0';\n            ++s;\n        }\n\n        // Parse width.\n        if ('0' <= *s && *s <= '9')\n        {\n            spec.width_ = internal::parse_nonnegative_int(s);\n        }\n        else if (*s == '{')\n        {\n            ++s;\n            Arg width_arg = internal::is_name_start(*s) ? parse_arg_name(s) : parse_arg_index(s);\n            if (*s++ != '}')\n                FMT_THROW(FormatError(\"invalid format string\"));\n            ULongLong value = 0;\n            switch (width_arg.type)\n            {\n            case Arg::INT:\n                if (width_arg.int_value < 0)\n                    FMT_THROW(FormatError(\"negative width\"));\n                value = width_arg.int_value;\n                break;\n            case Arg::UINT:\n                value = width_arg.uint_value;\n                break;\n            case Arg::LONG_LONG:\n                if (width_arg.long_long_value < 0)\n                    FMT_THROW(FormatError(\"negative width\"));\n                value = width_arg.long_long_value;\n                break;\n            case Arg::ULONG_LONG:\n                value = width_arg.ulong_long_value;\n                break;\n            default:\n                FMT_THROW(FormatError(\"width is not integer\"));\n            }\n            unsigned max_int = (std::numeric_limits<int>::max)();\n            if (value > max_int)\n                FMT_THROW(FormatError(\"number is too big\"));\n            spec.width_ = static_cast<int>(value);\n        }\n\n        // Parse precision.\n        if (*s == '.')\n        {\n            ++s;\n            spec.precision_ = 0;\n            if ('0' <= *s && *s <= '9')\n            {\n                spec.precision_ = internal::parse_nonnegative_int(s);\n            }\n            else if (*s == '{')\n            {\n                ++s;\n                Arg precision_arg = internal::is_name_start(*s) ? parse_arg_name(s) : parse_arg_index(s);\n                if (*s++ != '}')\n                    FMT_THROW(FormatError(\"invalid format string\"));\n                ULongLong value = 0;\n                switch (precision_arg.type)\n                {\n                case Arg::INT:\n                    if (precision_arg.int_value < 0)\n                        FMT_THROW(FormatError(\"negative precision\"));\n                    value = precision_arg.int_value;\n                    break;\n                case Arg::UINT:\n                    value = precision_arg.uint_value;\n                    break;\n                case Arg::LONG_LONG:\n                    if (precision_arg.long_long_value < 0)\n                        FMT_THROW(FormatError(\"negative precision\"));\n                    value = precision_arg.long_long_value;\n                    break;\n                case Arg::ULONG_LONG:\n                    value = precision_arg.ulong_long_value;\n                    break;\n                default:\n                    FMT_THROW(FormatError(\"precision is not integer\"));\n                }\n                unsigned max_int = (std::numeric_limits<int>::max)();\n                if (value > max_int)\n                    FMT_THROW(FormatError(\"number is too big\"));\n                spec.precision_ = static_cast<int>(value);\n            }\n            else\n            {\n                FMT_THROW(FormatError(\"missing precision specifier\"));\n            }\n            if (arg.type <= Arg::LAST_INTEGER_TYPE || arg.type == Arg::POINTER)\n            {\n                FMT_THROW(FormatError(\n                    fmt::format(\"precision not allowed in {} format specifier\", arg.type == Arg::POINTER ? \"pointer\" : \"integer\")));\n            }\n        }\n\n        // Parse type.\n        if (*s != '}' && *s)\n            spec.type_ = static_cast<char>(*s++);\n    }\n\n    if (*s++ != '}')\n        FMT_THROW(FormatError(\"missing '}' in format string\"));\n\n    // Format argument.\n    ArgFormatter(*this, spec, s - 1).visit(arg);\n    return s;\n}\n\ntemplate<typename Char, typename AF>\nvoid BasicFormatter<Char, AF>::format(BasicCStringRef<Char> format_str)\n{\n    const Char *s = format_str.c_str();\n    const Char *start = s;\n    while (*s)\n    {\n        Char c = *s++;\n        if (c != '{' && c != '}')\n            continue;\n        if (*s == c)\n        {\n            write(writer_, start, s);\n            start = ++s;\n            continue;\n        }\n        if (c == '}')\n            FMT_THROW(FormatError(\"unmatched '}' in format string\"));\n        write(writer_, start, s - 1);\n        internal::Arg arg = internal::is_name_start(*s) ? parse_arg_name(s) : parse_arg_index(s);\n        start = s = format(s, arg);\n    }\n    write(writer_, start, s);\n}\n\ntemplate<typename Char, typename It>\nstruct ArgJoin\n{\n    It first;\n    It last;\n    BasicCStringRef<Char> sep;\n\n    ArgJoin(It first, It last, const BasicCStringRef<Char> &sep)\n        : first(first)\n        , last(last)\n        , sep(sep)\n    {\n    }\n};\n\ntemplate<typename It>\nArgJoin<char, It> join(It first, It last, const BasicCStringRef<char> &sep)\n{\n    return ArgJoin<char, It>(first, last, sep);\n}\n\ntemplate<typename It>\nArgJoin<wchar_t, It> join(It first, It last, const BasicCStringRef<wchar_t> &sep)\n{\n    return ArgJoin<wchar_t, It>(first, last, sep);\n}\n\n#if FMT_HAS_GXX_CXX11\ntemplate<typename Range>\nauto join(const Range &range, const BasicCStringRef<char> &sep) -> ArgJoin<char, decltype(std::begin(range))>\n{\n    return join(std::begin(range), std::end(range), sep);\n}\n\ntemplate<typename Range>\nauto join(const Range &range, const BasicCStringRef<wchar_t> &sep) -> ArgJoin<wchar_t, decltype(std::begin(range))>\n{\n    return join(std::begin(range), std::end(range), sep);\n}\n#endif\n\ntemplate<typename ArgFormatter, typename Char, typename It>\nvoid format_arg(fmt::BasicFormatter<Char, ArgFormatter> &f, const Char *&format_str, const ArgJoin<Char, It> &e)\n{\n    const Char *end = format_str;\n    if (*end == ':')\n        ++end;\n    while (*end && *end != '}')\n        ++end;\n    if (*end != '}')\n        FMT_THROW(FormatError(\"missing '}' in format string\"));\n\n    It it = e.first;\n    if (it != e.last)\n    {\n        const Char *save = format_str;\n        f.format(format_str, internal::MakeArg<fmt::BasicFormatter<Char, ArgFormatter>>(*it++));\n        while (it != e.last)\n        {\n            f.writer().write(e.sep);\n            format_str = save;\n            f.format(format_str, internal::MakeArg<fmt::BasicFormatter<Char, ArgFormatter>>(*it++));\n        }\n    }\n    format_str = end + 1;\n}\n} // namespace fmt\n\n#if FMT_USE_USER_DEFINED_LITERALS\nnamespace fmt {\nnamespace internal {\n\ntemplate<typename Char>\nstruct UdlFormat\n{\n    const Char *str;\n\n    template<typename... Args>\n    auto operator()(Args &&... args) const -> decltype(format(str, std::forward<Args>(args)...))\n    {\n        return format(str, std::forward<Args>(args)...);\n    }\n};\n\ntemplate<typename Char>\nstruct UdlArg\n{\n    const Char *str;\n\n    template<typename T>\n    NamedArgWithType<Char, T> operator=(T &&value) const\n    {\n        return {str, std::forward<T>(value)};\n    }\n};\n\n} // namespace internal\n\ninline namespace literals {\n\n/**\n  \\rst\n  C++11 literal equivalent of :func:`fmt::format`.\n\n  **Example**::\n\n    using namespace fmt::literals;\n    std::string message = \"The answer is {}\"_format(42);\n  \\endrst\n */\ninline internal::UdlFormat<char> operator\"\" _format(const char *s, std::size_t)\n{\n    return {s};\n}\ninline internal::UdlFormat<wchar_t> operator\"\" _format(const wchar_t *s, std::size_t)\n{\n    return {s};\n}\n\n/**\n  \\rst\n  C++11 literal equivalent of :func:`fmt::arg`.\n\n  **Example**::\n\n    using namespace fmt::literals;\n    print(\"Elapsed time: {s:.2f} seconds\", \"s\"_a=1.23);\n  \\endrst\n */\ninline internal::UdlArg<char> operator\"\" _a(const char *s, std::size_t)\n{\n    return {s};\n}\ninline internal::UdlArg<wchar_t> operator\"\" _a(const wchar_t *s, std::size_t)\n{\n    return {s};\n}\n\n} // namespace literals\n} // namespace fmt\n#endif // FMT_USE_USER_DEFINED_LITERALS\n\n// Restore warnings.\n#if FMT_GCC_VERSION >= 406\n#pragma GCC diagnostic pop\n#endif\n\n#if defined(__clang__) && !defined(FMT_ICC_VERSION)\n#pragma clang diagnostic pop\n#endif\n\n#ifdef FMT_HEADER_ONLY\n#define FMT_FUNC inline\n#include \"format.cc\"\n#else\n#define FMT_FUNC\n#endif\n\n#endif // FMT_FORMAT_H_\n"
  },
  {
    "path": "spdlog/fmt/bundled/ostream.cc",
    "content": "/*\n Formatting library for C++ - std::ostream support\n\n Copyright (c) 2012 - 2016, Victor Zverovich\n All rights reserved.\n\n For the license information refer to format.h.\n */\n\n#include \"ostream.h\"\n\nnamespace fmt {\n\nnamespace internal {\nFMT_FUNC void write(std::ostream &os, Writer &w) {\n  const char *data = w.data();\n  typedef internal::MakeUnsigned<std::streamsize>::Type UnsignedStreamSize;\n  UnsignedStreamSize size = w.size();\n  UnsignedStreamSize max_size =\n      internal::to_unsigned((std::numeric_limits<std::streamsize>::max)());\n  do {\n    UnsignedStreamSize n = size <= max_size ? size : max_size;\n    os.write(data, static_cast<std::streamsize>(n));\n    data += n;\n    size -= n;\n  } while (size != 0);\n}\n}\n\nFMT_FUNC void print(std::ostream &os, CStringRef format_str, ArgList args) {\n  MemoryWriter w;\n  w.write(format_str, args);\n  internal::write(os, w);\n}\n}  // namespace fmt\n"
  },
  {
    "path": "spdlog/fmt/bundled/ostream.h",
    "content": "/*\n Formatting library for C++ - std::ostream support\n\n Copyright (c) 2012 - 2016, Victor Zverovich\n All rights reserved.\n\n For the license information refer to format.h.\n */\n\n#ifndef FMT_OSTREAM_H_\n#define FMT_OSTREAM_H_\n\n#include \"format.h\"\n#include <ostream>\n\nnamespace fmt {\n\nnamespace internal {\n\ntemplate<class Char>\nclass FormatBuf : public std::basic_streambuf<Char>\n{\nprivate:\n    typedef typename std::basic_streambuf<Char>::int_type int_type;\n    typedef typename std::basic_streambuf<Char>::traits_type traits_type;\n\n    Buffer<Char> &buffer_;\n\npublic:\n    FormatBuf(Buffer<Char> &buffer)\n        : buffer_(buffer)\n    {\n    }\n\nprotected:\n    // The put-area is actually always empty. This makes the implementation\n    // simpler and has the advantage that the streambuf and the buffer are always\n    // in sync and sputc never writes into uninitialized memory. The obvious\n    // disadvantage is that each call to sputc always results in a (virtual) call\n    // to overflow. There is no disadvantage here for sputn since this always\n    // results in a call to xsputn.\n\n    int_type overflow(int_type ch = traits_type::eof()) FMT_OVERRIDE\n    {\n        if (!traits_type::eq_int_type(ch, traits_type::eof()))\n            buffer_.push_back(static_cast<Char>(ch));\n        return ch;\n    }\n\n    std::streamsize xsputn(const Char *s, std::streamsize count) FMT_OVERRIDE\n    {\n        buffer_.append(s, s + count);\n        return count;\n    }\n};\n\nYes &convert(std::ostream &);\n\nstruct DummyStream : std::ostream\n{\n    DummyStream(); // Suppress a bogus warning in MSVC.\n\n    // Hide all operator<< overloads from std::ostream.\n    template<typename T>\n    typename EnableIf<sizeof(T) == 0>::type operator<<(const T &);\n};\n\nNo &operator<<(std::ostream &, int);\n\ntemplate<typename T>\nstruct ConvertToIntImpl<T, true>\n{\n    // Convert to int only if T doesn't have an overloaded operator<<.\n    enum\n    {\n        value = sizeof(convert(get<DummyStream>() << get<T>())) == sizeof(No)\n    };\n};\n\n// Write the content of w to os.\nFMT_API void write(std::ostream &os, Writer &w);\n} // namespace internal\n\n// Formats a value.\ntemplate<typename Char, typename ArgFormatter_, typename T>\nvoid format_arg(BasicFormatter<Char, ArgFormatter_> &f, const Char *&format_str, const T &value)\n{\n    internal::MemoryBuffer<Char, internal::INLINE_BUFFER_SIZE> buffer;\n\n    internal::FormatBuf<Char> format_buf(buffer);\n    std::basic_ostream<Char> output(&format_buf);\n    output.exceptions(std::ios_base::failbit | std::ios_base::badbit);\n    output << value;\n\n    BasicStringRef<Char> str(&buffer[0], buffer.size());\n    typedef internal::MakeArg<BasicFormatter<Char>> MakeArg;\n    format_str = f.format(format_str, MakeArg(str));\n}\n\n/**\n  \\rst\n  Prints formatted data to the stream *os*.\n\n  **Example**::\n\n    print(cerr, \"Don't {}!\", \"panic\");\n  \\endrst\n */\nFMT_API void print(std::ostream &os, CStringRef format_str, ArgList args);\nFMT_VARIADIC(void, print, std::ostream &, CStringRef)\n} // namespace fmt\n\n#ifdef FMT_HEADER_ONLY\n#include \"ostream.cc\"\n#endif\n\n#endif // FMT_OSTREAM_H_\n"
  },
  {
    "path": "spdlog/fmt/bundled/posix.cc",
    "content": "/*\n A C++ interface to POSIX functions.\n\n Copyright (c) 2012 - 2016, Victor Zverovich\n All rights reserved.\n\n For the license information refer to format.h.\n */\n\n// Disable bogus MSVC warnings.\n#ifndef _CRT_SECURE_NO_WARNINGS\n# define _CRT_SECURE_NO_WARNINGS\n#endif\n\n#include \"posix.h\"\n\n#include <limits.h>\n#include <sys/types.h>\n#include <sys/stat.h>\n\n#ifndef _WIN32\n# include <unistd.h>\n#else\n# ifndef WIN32_LEAN_AND_MEAN\n#  define WIN32_LEAN_AND_MEAN\n# endif\n# include <windows.h>\n# include <io.h>\n\n# define O_CREAT _O_CREAT\n# define O_TRUNC _O_TRUNC\n\n# ifndef S_IRUSR\n#  define S_IRUSR _S_IREAD\n# endif\n\n# ifndef S_IWUSR\n#  define S_IWUSR _S_IWRITE\n# endif\n\n# ifdef __MINGW32__\n#  define _SH_DENYNO 0x40\n# endif\n\n#endif  // _WIN32\n\n#ifdef fileno\n# undef fileno\n#endif\n\nnamespace {\n#ifdef _WIN32\n// Return type of read and write functions.\ntypedef int RWResult;\n\n// On Windows the count argument to read and write is unsigned, so convert\n// it from size_t preventing integer overflow.\ninline unsigned convert_rwcount(std::size_t count) {\n  return count <= UINT_MAX ? static_cast<unsigned>(count) : UINT_MAX;\n}\n#else\n// Return type of read and write functions.\ntypedef ssize_t RWResult;\n\ninline std::size_t convert_rwcount(std::size_t count) { return count; }\n#endif\n}\n\nfmt::BufferedFile::~BufferedFile() FMT_NOEXCEPT {\n  if (file_ && FMT_SYSTEM(fclose(file_)) != 0)\n    fmt::report_system_error(errno, \"cannot close file\");\n}\n\nfmt::BufferedFile::BufferedFile(\n    fmt::CStringRef filename, fmt::CStringRef mode) {\n  FMT_RETRY_VAL(file_, FMT_SYSTEM(fopen(filename.c_str(), mode.c_str())), 0);\n  if (!file_)\n    FMT_THROW(SystemError(errno, \"cannot open file {}\", filename));\n}\n\nvoid fmt::BufferedFile::close() {\n  if (!file_)\n    return;\n  int result = FMT_SYSTEM(fclose(file_));\n  file_ = FMT_NULL;\n  if (result != 0)\n    FMT_THROW(SystemError(errno, \"cannot close file\"));\n}\n\n// A macro used to prevent expansion of fileno on broken versions of MinGW.\n#define FMT_ARGS\n\nint fmt::BufferedFile::fileno() const {\n  int fd = FMT_POSIX_CALL(fileno FMT_ARGS(file_));\n  if (fd == -1)\n    FMT_THROW(SystemError(errno, \"cannot get file descriptor\"));\n  return fd;\n}\n\nfmt::File::File(fmt::CStringRef path, int oflag) {\n  int mode = S_IRUSR | S_IWUSR;\n#if defined(_WIN32) && !defined(__MINGW32__)\n  fd_ = -1;\n  FMT_POSIX_CALL(sopen_s(&fd_, path.c_str(), oflag, _SH_DENYNO, mode));\n#else\n  FMT_RETRY(fd_, FMT_POSIX_CALL(open(path.c_str(), oflag, mode)));\n#endif\n  if (fd_ == -1)\n    FMT_THROW(SystemError(errno, \"cannot open file {}\", path));\n}\n\nfmt::File::~File() FMT_NOEXCEPT {\n  // Don't retry close in case of EINTR!\n  // See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html\n  if (fd_ != -1 && FMT_POSIX_CALL(close(fd_)) != 0)\n    fmt::report_system_error(errno, \"cannot close file\");\n}\n\nvoid fmt::File::close() {\n  if (fd_ == -1)\n    return;\n  // Don't retry close in case of EINTR!\n  // See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html\n  int result = FMT_POSIX_CALL(close(fd_));\n  fd_ = -1;\n  if (result != 0)\n    FMT_THROW(SystemError(errno, \"cannot close file\"));\n}\n\nfmt::LongLong fmt::File::size() const {\n#ifdef _WIN32\n  // Use GetFileSize instead of GetFileSizeEx for the case when _WIN32_WINNT\n  // is less than 0x0500 as is the case with some default MinGW builds.\n  // Both functions support large file sizes.\n  DWORD size_upper = 0;\n  HANDLE handle = reinterpret_cast<HANDLE>(_get_osfhandle(fd_));\n  DWORD size_lower = FMT_SYSTEM(GetFileSize(handle, &size_upper));\n  if (size_lower == INVALID_FILE_SIZE) {\n    DWORD error = GetLastError();\n    if (error != NO_ERROR)\n      FMT_THROW(WindowsError(GetLastError(), \"cannot get file size\"));\n  }\n  fmt::ULongLong long_size = size_upper;\n  return (long_size << sizeof(DWORD) * CHAR_BIT) | size_lower;\n#else\n  typedef struct stat Stat;\n  Stat file_stat = Stat();\n  if (FMT_POSIX_CALL(fstat(fd_, &file_stat)) == -1)\n    FMT_THROW(SystemError(errno, \"cannot get file attributes\"));\n  FMT_STATIC_ASSERT(sizeof(fmt::LongLong) >= sizeof(file_stat.st_size),\n      \"return type of File::size is not large enough\");\n  return file_stat.st_size;\n#endif\n}\n\nstd::size_t fmt::File::read(void *buffer, std::size_t count) {\n  RWResult result = 0;\n  FMT_RETRY(result, FMT_POSIX_CALL(read(fd_, buffer, convert_rwcount(count))));\n  if (result < 0)\n    FMT_THROW(SystemError(errno, \"cannot read from file\"));\n  return internal::to_unsigned(result);\n}\n\nstd::size_t fmt::File::write(const void *buffer, std::size_t count) {\n  RWResult result = 0;\n  FMT_RETRY(result, FMT_POSIX_CALL(write(fd_, buffer, convert_rwcount(count))));\n  if (result < 0)\n    FMT_THROW(SystemError(errno, \"cannot write to file\"));\n  return internal::to_unsigned(result);\n}\n\nfmt::File fmt::File::dup(int fd) {\n  // Don't retry as dup doesn't return EINTR.\n  // http://pubs.opengroup.org/onlinepubs/009695399/functions/dup.html\n  int new_fd = FMT_POSIX_CALL(dup(fd));\n  if (new_fd == -1)\n    FMT_THROW(SystemError(errno, \"cannot duplicate file descriptor {}\", fd));\n  return File(new_fd);\n}\n\nvoid fmt::File::dup2(int fd) {\n  int result = 0;\n  FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd)));\n  if (result == -1) {\n    FMT_THROW(SystemError(errno,\n      \"cannot duplicate file descriptor {} to {}\", fd_, fd));\n  }\n}\n\nvoid fmt::File::dup2(int fd, ErrorCode &ec) FMT_NOEXCEPT {\n  int result = 0;\n  FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd)));\n  if (result == -1)\n    ec = ErrorCode(errno);\n}\n\nvoid fmt::File::pipe(File &read_end, File &write_end) {\n  // Close the descriptors first to make sure that assignments don't throw\n  // and there are no leaks.\n  read_end.close();\n  write_end.close();\n  int fds[2] = {};\n#ifdef _WIN32\n  // Make the default pipe capacity same as on Linux 2.6.11+.\n  enum { DEFAULT_CAPACITY = 65536 };\n  int result = FMT_POSIX_CALL(pipe(fds, DEFAULT_CAPACITY, _O_BINARY));\n#else\n  // Don't retry as the pipe function doesn't return EINTR.\n  // http://pubs.opengroup.org/onlinepubs/009696799/functions/pipe.html\n  int result = FMT_POSIX_CALL(pipe(fds));\n#endif\n  if (result != 0)\n    FMT_THROW(SystemError(errno, \"cannot create pipe\"));\n  // The following assignments don't throw because read_fd and write_fd\n  // are closed.\n  read_end = File(fds[0]);\n  write_end = File(fds[1]);\n}\n\nfmt::BufferedFile fmt::File::fdopen(const char *mode) {\n  // Don't retry as fdopen doesn't return EINTR.\n  FILE *f = FMT_POSIX_CALL(fdopen(fd_, mode));\n  if (!f)\n    FMT_THROW(SystemError(errno, \"cannot associate stream with file descriptor\"));\n  BufferedFile file(f);\n  fd_ = -1;\n  return file;\n}\n\nlong fmt::getpagesize() {\n#ifdef _WIN32\n  SYSTEM_INFO si;\n  GetSystemInfo(&si);\n  return si.dwPageSize;\n#else\n  long size = FMT_POSIX_CALL(sysconf(_SC_PAGESIZE));\n  if (size < 0)\n    FMT_THROW(SystemError(errno, \"cannot get memory page size\"));\n  return size;\n#endif\n}\n"
  },
  {
    "path": "spdlog/fmt/bundled/posix.h",
    "content": "/*\n A C++ interface to POSIX functions.\n\n Copyright (c) 2012 - 2016, Victor Zverovich\n All rights reserved.\n\n For the license information refer to format.h.\n */\n\n#ifndef FMT_POSIX_H_\n#define FMT_POSIX_H_\n\n#if defined(__MINGW32__) || defined(__CYGWIN__)\n// Workaround MinGW bug https://sourceforge.net/p/mingw/bugs/2024/.\n#undef __STRICT_ANSI__\n#endif\n\n#include <errno.h>\n#include <fcntl.h>  // for O_RDONLY\n#include <locale.h> // for locale_t\n#include <stdio.h>\n#include <stdlib.h> // for strtod_l\n\n#include <cstddef>\n\n#if defined __APPLE__ || defined(__FreeBSD__)\n#include <xlocale.h> // for LC_NUMERIC_MASK on OS X\n#endif\n\n#include \"format.h\"\n\n#ifndef FMT_POSIX\n#if defined(_WIN32) && !defined(__MINGW32__)\n// Fix warnings about deprecated symbols.\n#define FMT_POSIX(call) _##call\n#else\n#define FMT_POSIX(call) call\n#endif\n#endif\n\n// Calls to system functions are wrapped in FMT_SYSTEM for testability.\n#ifdef FMT_SYSTEM\n#define FMT_POSIX_CALL(call) FMT_SYSTEM(call)\n#else\n#define FMT_SYSTEM(call) call\n#ifdef _WIN32\n// Fix warnings about deprecated symbols.\n#define FMT_POSIX_CALL(call) ::_##call\n#else\n#define FMT_POSIX_CALL(call) ::call\n#endif\n#endif\n\n// Retries the expression while it evaluates to error_result and errno\n// equals to EINTR.\n#ifndef _WIN32\n#define FMT_RETRY_VAL(result, expression, error_result)                                                                                    \\\n    do                                                                                                                                     \\\n    {                                                                                                                                      \\\n        result = (expression);                                                                                                             \\\n    } while (result == error_result && errno == EINTR)\n#else\n#define FMT_RETRY_VAL(result, expression, error_result) result = (expression)\n#endif\n\n#define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1)\n\nnamespace fmt {\n\n// An error code.\nclass ErrorCode\n{\nprivate:\n    int value_;\n\npublic:\n    explicit ErrorCode(int value = 0) FMT_NOEXCEPT : value_(value) {}\n\n    int get() const FMT_NOEXCEPT\n    {\n        return value_;\n    }\n};\n\n// A buffered file.\nclass BufferedFile\n{\nprivate:\n    FILE *file_;\n\n    friend class File;\n\n    explicit BufferedFile(FILE *f)\n        : file_(f)\n    {\n    }\n\npublic:\n    // Constructs a BufferedFile object which doesn't represent any file.\n    BufferedFile() FMT_NOEXCEPT : file_(FMT_NULL) {}\n\n    // Destroys the object closing the file it represents if any.\n    FMT_API ~BufferedFile() FMT_NOEXCEPT;\n\n#if !FMT_USE_RVALUE_REFERENCES\n    // Emulate a move constructor and a move assignment operator if rvalue\n    // references are not supported.\n\nprivate:\n    // A proxy object to emulate a move constructor.\n    // It is private to make it impossible call operator Proxy directly.\n    struct Proxy\n    {\n        FILE *file;\n    };\n\npublic:\n    // A \"move constructor\" for moving from a temporary.\n    BufferedFile(Proxy p) FMT_NOEXCEPT : file_(p.file) {}\n\n    // A \"move constructor\" for moving from an lvalue.\n    BufferedFile(BufferedFile &f) FMT_NOEXCEPT : file_(f.file_)\n    {\n        f.file_ = FMT_NULL;\n    }\n\n    // A \"move assignment operator\" for moving from a temporary.\n    BufferedFile &operator=(Proxy p)\n    {\n        close();\n        file_ = p.file;\n        return *this;\n    }\n\n    // A \"move assignment operator\" for moving from an lvalue.\n    BufferedFile &operator=(BufferedFile &other)\n    {\n        close();\n        file_ = other.file_;\n        other.file_ = FMT_NULL;\n        return *this;\n    }\n\n    // Returns a proxy object for moving from a temporary:\n    //   BufferedFile file = BufferedFile(...);\n    operator Proxy() FMT_NOEXCEPT\n    {\n        Proxy p = {file_};\n        file_ = FMT_NULL;\n        return p;\n    }\n\n#else\nprivate:\n    FMT_DISALLOW_COPY_AND_ASSIGN(BufferedFile);\n\npublic:\n    BufferedFile(BufferedFile &&other) FMT_NOEXCEPT : file_(other.file_)\n    {\n        other.file_ = FMT_NULL;\n    }\n\n    BufferedFile &operator=(BufferedFile &&other)\n    {\n        close();\n        file_ = other.file_;\n        other.file_ = FMT_NULL;\n        return *this;\n    }\n#endif\n\n    // Opens a file.\n    FMT_API BufferedFile(CStringRef filename, CStringRef mode);\n\n    // Closes the file.\n    FMT_API void close();\n\n    // Returns the pointer to a FILE object representing this file.\n    FILE *get() const FMT_NOEXCEPT\n    {\n        return file_;\n    }\n\n    // We place parentheses around fileno to workaround a bug in some versions\n    // of MinGW that define fileno as a macro.\n    FMT_API int(fileno)() const;\n\n    void print(CStringRef format_str, const ArgList &args)\n    {\n        fmt::print(file_, format_str, args);\n    }\n    FMT_VARIADIC(void, print, CStringRef)\n};\n\n// A file. Closed file is represented by a File object with descriptor -1.\n// Methods that are not declared with FMT_NOEXCEPT may throw\n// fmt::SystemError in case of failure. Note that some errors such as\n// closing the file multiple times will cause a crash on Windows rather\n// than an exception. You can get standard behavior by overriding the\n// invalid parameter handler with _set_invalid_parameter_handler.\nclass File\n{\nprivate:\n    int fd_; // File descriptor.\n\n    // Constructs a File object with a given descriptor.\n    explicit File(int fd)\n        : fd_(fd)\n    {\n    }\n\npublic:\n    // Possible values for the oflag argument to the constructor.\n    enum\n    {\n        RDONLY = FMT_POSIX(O_RDONLY), // Open for reading only.\n        WRONLY = FMT_POSIX(O_WRONLY), // Open for writing only.\n        RDWR = FMT_POSIX(O_RDWR)      // Open for reading and writing.\n    };\n\n    // Constructs a File object which doesn't represent any file.\n    File() FMT_NOEXCEPT : fd_(-1) {}\n\n    // Opens a file and constructs a File object representing this file.\n    FMT_API File(CStringRef path, int oflag);\n\n#if !FMT_USE_RVALUE_REFERENCES\n    // Emulate a move constructor and a move assignment operator if rvalue\n    // references are not supported.\n\nprivate:\n    // A proxy object to emulate a move constructor.\n    // It is private to make it impossible call operator Proxy directly.\n    struct Proxy\n    {\n        int fd;\n    };\n\npublic:\n    // A \"move constructor\" for moving from a temporary.\n    File(Proxy p) FMT_NOEXCEPT : fd_(p.fd) {}\n\n    // A \"move constructor\" for moving from an lvalue.\n    File(File &other) FMT_NOEXCEPT : fd_(other.fd_)\n    {\n        other.fd_ = -1;\n    }\n\n    // A \"move assignment operator\" for moving from a temporary.\n    File &operator=(Proxy p)\n    {\n        close();\n        fd_ = p.fd;\n        return *this;\n    }\n\n    // A \"move assignment operator\" for moving from an lvalue.\n    File &operator=(File &other)\n    {\n        close();\n        fd_ = other.fd_;\n        other.fd_ = -1;\n        return *this;\n    }\n\n    // Returns a proxy object for moving from a temporary:\n    //   File file = File(...);\n    operator Proxy() FMT_NOEXCEPT\n    {\n        Proxy p = {fd_};\n        fd_ = -1;\n        return p;\n    }\n\n#else\nprivate:\n    FMT_DISALLOW_COPY_AND_ASSIGN(File);\n\npublic:\n    File(File &&other) FMT_NOEXCEPT : fd_(other.fd_)\n    {\n        other.fd_ = -1;\n    }\n\n    File &operator=(File &&other)\n    {\n        close();\n        fd_ = other.fd_;\n        other.fd_ = -1;\n        return *this;\n    }\n#endif\n\n    // Destroys the object closing the file it represents if any.\n    FMT_API ~File() FMT_NOEXCEPT;\n\n    // Returns the file descriptor.\n    int descriptor() const FMT_NOEXCEPT\n    {\n        return fd_;\n    }\n\n    // Closes the file.\n    FMT_API void close();\n\n    // Returns the file size. The size has signed type for consistency with\n    // stat::st_size.\n    FMT_API LongLong size() const;\n\n    // Attempts to read count bytes from the file into the specified buffer.\n    FMT_API std::size_t read(void *buffer, std::size_t count);\n\n    // Attempts to write count bytes from the specified buffer to the file.\n    FMT_API std::size_t write(const void *buffer, std::size_t count);\n\n    // Duplicates a file descriptor with the dup function and returns\n    // the duplicate as a file object.\n    FMT_API static File dup(int fd);\n\n    // Makes fd be the copy of this file descriptor, closing fd first if\n    // necessary.\n    FMT_API void dup2(int fd);\n\n    // Makes fd be the copy of this file descriptor, closing fd first if\n    // necessary.\n    FMT_API void dup2(int fd, ErrorCode &ec) FMT_NOEXCEPT;\n\n    // Creates a pipe setting up read_end and write_end file objects for reading\n    // and writing respectively.\n    FMT_API static void pipe(File &read_end, File &write_end);\n\n    // Creates a BufferedFile object associated with this file and detaches\n    // this File object from the file.\n    FMT_API BufferedFile fdopen(const char *mode);\n};\n\n// Returns the memory page size.\nlong getpagesize();\n\n#if (defined(LC_NUMERIC_MASK) || defined(_MSC_VER)) && !defined(__ANDROID__) && !defined(__CYGWIN__)\n#define FMT_LOCALE\n#endif\n\n#ifdef FMT_LOCALE\n// A \"C\" numeric locale.\nclass Locale\n{\nprivate:\n#ifdef _MSC_VER\n    typedef _locale_t locale_t;\n\n    enum\n    {\n        LC_NUMERIC_MASK = LC_NUMERIC\n    };\n\n    static locale_t newlocale(int category_mask, const char *locale, locale_t)\n    {\n        return _create_locale(category_mask, locale);\n    }\n\n    static void freelocale(locale_t locale)\n    {\n        _free_locale(locale);\n    }\n\n    static double strtod_l(const char *nptr, char **endptr, _locale_t locale)\n    {\n        return _strtod_l(nptr, endptr, locale);\n    }\n#endif\n\n    locale_t locale_;\n\n    FMT_DISALLOW_COPY_AND_ASSIGN(Locale);\n\npublic:\n    typedef locale_t Type;\n\n    Locale()\n        : locale_(newlocale(LC_NUMERIC_MASK, \"C\", FMT_NULL))\n    {\n        if (!locale_)\n            FMT_THROW(fmt::SystemError(errno, \"cannot create locale\"));\n    }\n    ~Locale()\n    {\n        freelocale(locale_);\n    }\n\n    Type get() const\n    {\n        return locale_;\n    }\n\n    // Converts string to floating-point number and advances str past the end\n    // of the parsed input.\n    double strtod(const char *&str) const\n    {\n        char *end = FMT_NULL;\n        double result = strtod_l(str, &end, locale_);\n        str = end;\n        return result;\n    }\n};\n#endif // FMT_LOCALE\n} // namespace fmt\n\n#if !FMT_USE_RVALUE_REFERENCES\nnamespace std {\n// For compatibility with C++98.\ninline fmt::BufferedFile &move(fmt::BufferedFile &f)\n{\n    return f;\n}\ninline fmt::File &move(fmt::File &f)\n{\n    return f;\n}\n} // namespace std\n#endif\n\n#endif // FMT_POSIX_H_\n"
  },
  {
    "path": "spdlog/fmt/bundled/printf.cc",
    "content": "/*\n Formatting library for C++\n\n Copyright (c) 2012 - 2016, Victor Zverovich\n All rights reserved.\n\n For the license information refer to format.h.\n */\n\n#include \"format.h\"\n#include \"printf.h\"\n\nnamespace fmt {\n\ntemplate <typename Char>\nvoid printf(BasicWriter<Char> &w, BasicCStringRef<Char> format, ArgList args);\n\nFMT_FUNC int fprintf(std::FILE *f, CStringRef format, ArgList args) {\n  MemoryWriter w;\n  printf(w, format, args);\n  std::size_t size = w.size();\n  return std::fwrite(w.data(), 1, size, f) < size ? -1 : static_cast<int>(size);\n}\n\n#ifndef FMT_HEADER_ONLY\n\ntemplate void PrintfFormatter<char>::format(CStringRef format);\ntemplate void PrintfFormatter<wchar_t>::format(WCStringRef format);\n\n#endif  // FMT_HEADER_ONLY\n\n}  // namespace fmt\n"
  },
  {
    "path": "spdlog/fmt/bundled/printf.h",
    "content": "/*\n Formatting library for C++\n\n Copyright (c) 2012 - 2016, Victor Zverovich\n All rights reserved.\n\n For the license information refer to format.h.\n */\n\n#ifndef FMT_PRINTF_H_\n#define FMT_PRINTF_H_\n\n#include <algorithm> // std::fill_n\n#include <limits>    // std::numeric_limits\n\n#include \"ostream.h\"\n\nnamespace fmt {\nnamespace internal {\n\n// Checks if a value fits in int - used to avoid warnings about comparing\n// signed and unsigned integers.\ntemplate<bool IsSigned>\nstruct IntChecker\n{\n    template<typename T>\n    static bool fits_in_int(T value)\n    {\n        unsigned max = std::numeric_limits<int>::max();\n        return value <= max;\n    }\n    static bool fits_in_int(bool)\n    {\n        return true;\n    }\n};\n\ntemplate<>\nstruct IntChecker<true>\n{\n    template<typename T>\n    static bool fits_in_int(T value)\n    {\n        return value >= std::numeric_limits<int>::min() && value <= std::numeric_limits<int>::max();\n    }\n    static bool fits_in_int(int)\n    {\n        return true;\n    }\n};\n\nclass PrecisionHandler : public ArgVisitor<PrecisionHandler, int>\n{\npublic:\n    void report_unhandled_arg()\n    {\n        FMT_THROW(FormatError(\"precision is not integer\"));\n    }\n\n    template<typename T>\n    int visit_any_int(T value)\n    {\n        if (!IntChecker<std::numeric_limits<T>::is_signed>::fits_in_int(value))\n            FMT_THROW(FormatError(\"number is too big\"));\n        return static_cast<int>(value);\n    }\n};\n\n// IsZeroInt::visit(arg) returns true iff arg is a zero integer.\nclass IsZeroInt : public ArgVisitor<IsZeroInt, bool>\n{\npublic:\n    template<typename T>\n    bool visit_any_int(T value)\n    {\n        return value == 0;\n    }\n};\n\n// returns the default type for format specific \"%s\"\nclass DefaultType : public ArgVisitor<DefaultType, char>\n{\npublic:\n    char visit_char(int)\n    {\n        return 'c';\n    }\n\n    char visit_bool(bool)\n    {\n        return 's';\n    }\n\n    char visit_pointer(const void *)\n    {\n        return 'p';\n    }\n\n    template<typename T>\n    char visit_any_int(T)\n    {\n        return 'd';\n    }\n\n    template<typename T>\n    char visit_any_double(T)\n    {\n        return 'g';\n    }\n\n    char visit_unhandled_arg()\n    {\n        return 's';\n    }\n};\n\ntemplate<typename T, typename U>\nstruct is_same\n{\n    enum\n    {\n        value = 0\n    };\n};\n\ntemplate<typename T>\nstruct is_same<T, T>\n{\n    enum\n    {\n        value = 1\n    };\n};\n\n// An argument visitor that converts an integer argument to T for printf,\n// if T is an integral type. If T is void, the argument is converted to\n// corresponding signed or unsigned type depending on the type specifier:\n// 'd' and 'i' - signed, other - unsigned)\ntemplate<typename T = void>\nclass ArgConverter : public ArgVisitor<ArgConverter<T>, void>\n{\nprivate:\n    internal::Arg &arg_;\n    wchar_t type_;\n\n    FMT_DISALLOW_COPY_AND_ASSIGN(ArgConverter);\n\npublic:\n    ArgConverter(internal::Arg &arg, wchar_t type)\n        : arg_(arg)\n        , type_(type)\n    {\n    }\n\n    void visit_bool(bool value)\n    {\n        if (type_ != 's')\n            visit_any_int(value);\n    }\n\n    void visit_char(int value)\n    {\n        if (type_ != 's')\n            visit_any_int(value);\n    }\n\n    template<typename U>\n    void visit_any_int(U value)\n    {\n        bool is_signed = type_ == 'd' || type_ == 'i';\n        if (type_ == 's')\n        {\n            is_signed = std::numeric_limits<U>::is_signed;\n        }\n\n        using internal::Arg;\n        typedef typename internal::Conditional<is_same<T, void>::value, U, T>::type TargetType;\n        if (const_check(sizeof(TargetType) <= sizeof(int)))\n        {\n            // Extra casts are used to silence warnings.\n            if (is_signed)\n            {\n                arg_.type = Arg::INT;\n                arg_.int_value = static_cast<int>(static_cast<TargetType>(value));\n            }\n            else\n            {\n                arg_.type = Arg::UINT;\n                typedef typename internal::MakeUnsigned<TargetType>::Type Unsigned;\n                arg_.uint_value = static_cast<unsigned>(static_cast<Unsigned>(value));\n            }\n        }\n        else\n        {\n            if (is_signed)\n            {\n                arg_.type = Arg::LONG_LONG;\n                // glibc's printf doesn't sign extend arguments of smaller types:\n                //   std::printf(\"%lld\", -42);  // prints \"4294967254\"\n                // but we don't have to do the same because it's a UB.\n                arg_.long_long_value = static_cast<LongLong>(value);\n            }\n            else\n            {\n                arg_.type = Arg::ULONG_LONG;\n                arg_.ulong_long_value = static_cast<typename internal::MakeUnsigned<U>::Type>(value);\n            }\n        }\n    }\n};\n\n// Converts an integer argument to char for printf.\nclass CharConverter : public ArgVisitor<CharConverter, void>\n{\nprivate:\n    internal::Arg &arg_;\n\n    FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter);\n\npublic:\n    explicit CharConverter(internal::Arg &arg)\n        : arg_(arg)\n    {\n    }\n\n    template<typename T>\n    void visit_any_int(T value)\n    {\n        arg_.type = internal::Arg::CHAR;\n        arg_.int_value = static_cast<char>(value);\n    }\n};\n\n// Checks if an argument is a valid printf width specifier and sets\n// left alignment if it is negative.\nclass WidthHandler : public ArgVisitor<WidthHandler, unsigned>\n{\nprivate:\n    FormatSpec &spec_;\n\n    FMT_DISALLOW_COPY_AND_ASSIGN(WidthHandler);\n\npublic:\n    explicit WidthHandler(FormatSpec &spec)\n        : spec_(spec)\n    {\n    }\n\n    void report_unhandled_arg()\n    {\n        FMT_THROW(FormatError(\"width is not integer\"));\n    }\n\n    template<typename T>\n    unsigned visit_any_int(T value)\n    {\n        typedef typename internal::IntTraits<T>::MainType UnsignedType;\n        UnsignedType width = static_cast<UnsignedType>(value);\n        if (internal::is_negative(value))\n        {\n            spec_.align_ = ALIGN_LEFT;\n            width = 0 - width;\n        }\n        unsigned int_max = std::numeric_limits<int>::max();\n        if (width > int_max)\n            FMT_THROW(FormatError(\"number is too big\"));\n        return static_cast<unsigned>(width);\n    }\n};\n} // namespace internal\n\n/**\n  \\rst\n  A ``printf`` argument formatter based on the `curiously recurring template\n  pattern <http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern>`_.\n\n  To use `~fmt::BasicPrintfArgFormatter` define a subclass that implements some\n  or all of the visit methods with the same signatures as the methods in\n  `~fmt::ArgVisitor`, for example, `~fmt::ArgVisitor::visit_int()`.\n  Pass the subclass as the *Impl* template parameter. When a formatting\n  function processes an argument, it will dispatch to a visit method\n  specific to the argument type. For example, if the argument type is\n  ``double`` then the `~fmt::ArgVisitor::visit_double()` method of a subclass\n  will be called. If the subclass doesn't contain a method with this signature,\n  then a corresponding method of `~fmt::BasicPrintfArgFormatter` or its\n  superclass will be called.\n  \\endrst\n */\ntemplate<typename Impl, typename Char, typename Spec>\nclass BasicPrintfArgFormatter : public internal::ArgFormatterBase<Impl, Char, Spec>\n{\nprivate:\n    void write_null_pointer()\n    {\n        this->spec().type_ = 0;\n        this->write(\"(nil)\");\n    }\n\n    typedef internal::ArgFormatterBase<Impl, Char, Spec> Base;\n\npublic:\n    /**\n      \\rst\n      Constructs an argument formatter object.\n      *writer* is a reference to the output writer and *spec* contains format\n      specifier information for standard argument types.\n      \\endrst\n     */\n    BasicPrintfArgFormatter(BasicWriter<Char> &w, Spec &s)\n        : internal::ArgFormatterBase<Impl, Char, Spec>(w, s)\n    {\n    }\n\n    /** Formats an argument of type ``bool``. */\n    void visit_bool(bool value)\n    {\n        Spec &fmt_spec = this->spec();\n        if (fmt_spec.type_ != 's')\n            return this->visit_any_int(value);\n        fmt_spec.type_ = 0;\n        this->write(value);\n    }\n\n    /** Formats a character. */\n    void visit_char(int value)\n    {\n        const Spec &fmt_spec = this->spec();\n        BasicWriter<Char> &w = this->writer();\n        if (fmt_spec.type_ && fmt_spec.type_ != 'c')\n            w.write_int(value, fmt_spec);\n        typedef typename BasicWriter<Char>::CharPtr CharPtr;\n        CharPtr out = CharPtr();\n        if (fmt_spec.width_ > 1)\n        {\n            Char fill = ' ';\n            out = w.grow_buffer(fmt_spec.width_);\n            if (fmt_spec.align_ != ALIGN_LEFT)\n            {\n                std::fill_n(out, fmt_spec.width_ - 1, fill);\n                out += fmt_spec.width_ - 1;\n            }\n            else\n            {\n                std::fill_n(out + 1, fmt_spec.width_ - 1, fill);\n            }\n        }\n        else\n        {\n            out = w.grow_buffer(1);\n        }\n        *out = static_cast<Char>(value);\n    }\n\n    /** Formats a null-terminated C string. */\n    void visit_cstring(const char *value)\n    {\n        if (value)\n            Base::visit_cstring(value);\n        else if (this->spec().type_ == 'p')\n            write_null_pointer();\n        else\n            this->write(\"(null)\");\n    }\n\n    /** Formats a pointer. */\n    void visit_pointer(const void *value)\n    {\n        if (value)\n            return Base::visit_pointer(value);\n        this->spec().type_ = 0;\n        write_null_pointer();\n    }\n\n    /** Formats an argument of a custom (user-defined) type. */\n    void visit_custom(internal::Arg::CustomValue c)\n    {\n        BasicFormatter<Char> formatter(ArgList(), this->writer());\n        const Char format_str[] = {'}', 0};\n        const Char *format = format_str;\n        c.format(&formatter, c.value, &format);\n    }\n};\n\n/** The default printf argument formatter. */\ntemplate<typename Char>\nclass PrintfArgFormatter : public BasicPrintfArgFormatter<PrintfArgFormatter<Char>, Char, FormatSpec>\n{\npublic:\n    /** Constructs an argument formatter object. */\n    PrintfArgFormatter(BasicWriter<Char> &w, FormatSpec &s)\n        : BasicPrintfArgFormatter<PrintfArgFormatter<Char>, Char, FormatSpec>(w, s)\n    {\n    }\n};\n\n/** This template formats data and writes the output to a writer. */\ntemplate<typename Char, typename ArgFormatter = PrintfArgFormatter<Char>>\nclass PrintfFormatter : private internal::FormatterBase\n{\nprivate:\n    BasicWriter<Char> &writer_;\n\n    void parse_flags(FormatSpec &spec, const Char *&s);\n\n    // Returns the argument with specified index or, if arg_index is equal\n    // to the maximum unsigned value, the next argument.\n    internal::Arg get_arg(const Char *s, unsigned arg_index = (std::numeric_limits<unsigned>::max)());\n\n    // Parses argument index, flags and width and returns the argument index.\n    unsigned parse_header(const Char *&s, FormatSpec &spec);\n\npublic:\n    /**\n     \\rst\n     Constructs a ``PrintfFormatter`` object. References to the arguments and\n     the writer are stored in the formatter object so make sure they have\n     appropriate lifetimes.\n     \\endrst\n     */\n    explicit PrintfFormatter(const ArgList &al, BasicWriter<Char> &w)\n        : FormatterBase(al)\n        , writer_(w)\n    {\n    }\n\n    /** Formats stored arguments and writes the output to the writer. */\n    void format(BasicCStringRef<Char> format_str);\n};\n\ntemplate<typename Char, typename AF>\nvoid PrintfFormatter<Char, AF>::parse_flags(FormatSpec &spec, const Char *&s)\n{\n    for (;;)\n    {\n        switch (*s++)\n        {\n        case '-':\n            spec.align_ = ALIGN_LEFT;\n            break;\n        case '+':\n            spec.flags_ |= SIGN_FLAG | PLUS_FLAG;\n            break;\n        case '0':\n            spec.fill_ = '0';\n            break;\n        case ' ':\n            spec.flags_ |= SIGN_FLAG;\n            break;\n        case '#':\n            spec.flags_ |= HASH_FLAG;\n            break;\n        default:\n            --s;\n            return;\n        }\n    }\n}\n\ntemplate<typename Char, typename AF>\ninternal::Arg PrintfFormatter<Char, AF>::get_arg(const Char *s, unsigned arg_index)\n{\n    (void)s;\n    const char *error = FMT_NULL;\n    internal::Arg arg = arg_index == std::numeric_limits<unsigned>::max() ? next_arg(error) : FormatterBase::get_arg(arg_index - 1, error);\n    if (error)\n        FMT_THROW(FormatError(!*s ? \"invalid format string\" : error));\n    return arg;\n}\n\ntemplate<typename Char, typename AF>\nunsigned PrintfFormatter<Char, AF>::parse_header(const Char *&s, FormatSpec &spec)\n{\n    unsigned arg_index = std::numeric_limits<unsigned>::max();\n    Char c = *s;\n    if (c >= '0' && c <= '9')\n    {\n        // Parse an argument index (if followed by '$') or a width possibly\n        // preceded with '0' flag(s).\n        unsigned value = internal::parse_nonnegative_int(s);\n        if (*s == '$') // value is an argument index\n        {\n            ++s;\n            arg_index = value;\n        }\n        else\n        {\n            if (c == '0')\n                spec.fill_ = '0';\n            if (value != 0)\n            {\n                // Nonzero value means that we parsed width and don't need to\n                // parse it or flags again, so return now.\n                spec.width_ = value;\n                return arg_index;\n            }\n        }\n    }\n    parse_flags(spec, s);\n    // Parse width.\n    if (*s >= '0' && *s <= '9')\n    {\n        spec.width_ = internal::parse_nonnegative_int(s);\n    }\n    else if (*s == '*')\n    {\n        ++s;\n        spec.width_ = internal::WidthHandler(spec).visit(get_arg(s));\n    }\n    return arg_index;\n}\n\ntemplate<typename Char, typename AF>\nvoid PrintfFormatter<Char, AF>::format(BasicCStringRef<Char> format_str)\n{\n    const Char *start = format_str.c_str();\n    const Char *s = start;\n    while (*s)\n    {\n        Char c = *s++;\n        if (c != '%')\n            continue;\n        if (*s == c)\n        {\n            write(writer_, start, s);\n            start = ++s;\n            continue;\n        }\n        write(writer_, start, s - 1);\n\n        FormatSpec spec;\n        spec.align_ = ALIGN_RIGHT;\n\n        // Parse argument index, flags and width.\n        unsigned arg_index = parse_header(s, spec);\n\n        // Parse precision.\n        if (*s == '.')\n        {\n            ++s;\n            if ('0' <= *s && *s <= '9')\n            {\n                spec.precision_ = static_cast<int>(internal::parse_nonnegative_int(s));\n            }\n            else if (*s == '*')\n            {\n                ++s;\n                spec.precision_ = internal::PrecisionHandler().visit(get_arg(s));\n            }\n            else\n            {\n                spec.precision_ = 0;\n            }\n        }\n\n        using internal::Arg;\n        Arg arg = get_arg(s, arg_index);\n        if (spec.flag(HASH_FLAG) && internal::IsZeroInt().visit(arg))\n            spec.flags_ &= ~internal::to_unsigned<int>(HASH_FLAG);\n        if (spec.fill_ == '0')\n        {\n            if (arg.type <= Arg::LAST_NUMERIC_TYPE)\n                spec.align_ = ALIGN_NUMERIC;\n            else\n                spec.fill_ = ' '; // Ignore '0' flag for non-numeric types.\n        }\n\n        // Parse length and convert the argument to the required type.\n        using internal::ArgConverter;\n        switch (*s++)\n        {\n        case 'h':\n            if (*s == 'h')\n                ArgConverter<signed char>(arg, *++s).visit(arg);\n            else\n                ArgConverter<short>(arg, *s).visit(arg);\n            break;\n        case 'l':\n            if (*s == 'l')\n                ArgConverter<fmt::LongLong>(arg, *++s).visit(arg);\n            else\n                ArgConverter<long>(arg, *s).visit(arg);\n            break;\n        case 'j':\n            ArgConverter<intmax_t>(arg, *s).visit(arg);\n            break;\n        case 'z':\n            ArgConverter<std::size_t>(arg, *s).visit(arg);\n            break;\n        case 't':\n            ArgConverter<std::ptrdiff_t>(arg, *s).visit(arg);\n            break;\n        case 'L':\n            // printf produces garbage when 'L' is omitted for long double, no\n            // need to do the same.\n            break;\n        default:\n            --s;\n            ArgConverter<void>(arg, *s).visit(arg);\n        }\n\n        // Parse type.\n        if (!*s)\n            FMT_THROW(FormatError(\"invalid format string\"));\n        spec.type_ = static_cast<char>(*s++);\n\n        if (spec.type_ == 's')\n        {\n            // set the format type to the default if 's' is specified\n            spec.type_ = internal::DefaultType().visit(arg);\n        }\n\n        if (arg.type <= Arg::LAST_INTEGER_TYPE)\n        {\n            // Normalize type.\n            switch (spec.type_)\n            {\n            case 'i':\n            case 'u':\n                spec.type_ = 'd';\n                break;\n            case 'c':\n                // TODO: handle wchar_t\n                internal::CharConverter(arg).visit(arg);\n                break;\n            }\n        }\n\n        start = s;\n\n        // Format argument.\n        AF(writer_, spec).visit(arg);\n    }\n    write(writer_, start, s);\n}\n\ninline void printf(Writer &w, CStringRef format, ArgList args)\n{\n    PrintfFormatter<char>(args, w).format(format);\n}\nFMT_VARIADIC(void, printf, Writer &, CStringRef)\n\ninline void printf(WWriter &w, WCStringRef format, ArgList args)\n{\n    PrintfFormatter<wchar_t>(args, w).format(format);\n}\nFMT_VARIADIC(void, printf, WWriter &, WCStringRef)\n\n/**\n  \\rst\n  Formats arguments and returns the result as a string.\n\n  **Example**::\n\n    std::string message = fmt::sprintf(\"The answer is %d\", 42);\n  \\endrst\n*/\ninline std::string sprintf(CStringRef format, ArgList args)\n{\n    MemoryWriter w;\n    printf(w, format, args);\n    return w.str();\n}\nFMT_VARIADIC(std::string, sprintf, CStringRef)\n\ninline std::wstring sprintf(WCStringRef format, ArgList args)\n{\n    WMemoryWriter w;\n    printf(w, format, args);\n    return w.str();\n}\nFMT_VARIADIC_W(std::wstring, sprintf, WCStringRef)\n\n/**\n  \\rst\n  Prints formatted data to the file *f*.\n\n  **Example**::\n\n    fmt::fprintf(stderr, \"Don't %s!\", \"panic\");\n  \\endrst\n */\nFMT_API int fprintf(std::FILE *f, CStringRef format, ArgList args);\nFMT_VARIADIC(int, fprintf, std::FILE *, CStringRef)\n\n/**\n  \\rst\n  Prints formatted data to ``stdout``.\n\n  **Example**::\n\n    fmt::printf(\"Elapsed time: %.2f seconds\", 1.23);\n  \\endrst\n */\ninline int printf(CStringRef format, ArgList args)\n{\n    return fprintf(stdout, format, args);\n}\nFMT_VARIADIC(int, printf, CStringRef)\n\n/**\n  \\rst\n  Prints formatted data to the stream *os*.\n\n  **Example**::\n\n    fprintf(cerr, \"Don't %s!\", \"panic\");\n  \\endrst\n */\ninline int fprintf(std::ostream &os, CStringRef format_str, ArgList args)\n{\n    MemoryWriter w;\n    printf(w, format_str, args);\n    internal::write(os, w);\n    return static_cast<int>(w.size());\n}\nFMT_VARIADIC(int, fprintf, std::ostream &, CStringRef)\n} // namespace fmt\n\n#ifdef FMT_HEADER_ONLY\n#include \"printf.cc\"\n#endif\n\n#endif // FMT_PRINTF_H_\n"
  },
  {
    "path": "spdlog/fmt/bundled/time.h",
    "content": "/*\n Formatting library for C++ - time formatting\n\n Copyright (c) 2012 - 2016, Victor Zverovich\n All rights reserved.\n\n For the license information refer to format.h.\n */\n\n#ifndef FMT_TIME_H_\n#define FMT_TIME_H_\n\n#include \"format.h\"\n#include <ctime>\n\n#ifdef _MSC_VER\n#pragma warning(push)\n#pragma warning(disable : 4702) // unreachable code\n#pragma warning(disable : 4996) // \"deprecated\" functions\n#endif\n\nnamespace fmt {\ntemplate<typename ArgFormatter>\nvoid format_arg(BasicFormatter<char, ArgFormatter> &f, const char *&format_str, const std::tm &tm)\n{\n    if (*format_str == ':')\n        ++format_str;\n    const char *end = format_str;\n    while (*end && *end != '}')\n        ++end;\n    if (*end != '}')\n        FMT_THROW(FormatError(\"missing '}' in format string\"));\n    internal::MemoryBuffer<char, internal::INLINE_BUFFER_SIZE> format;\n    format.append(format_str, end + 1);\n    format[format.size() - 1] = '\\0';\n    Buffer<char> &buffer = f.writer().buffer();\n    std::size_t start = buffer.size();\n    for (;;)\n    {\n        std::size_t size = buffer.capacity() - start;\n        std::size_t count = std::strftime(&buffer[start], size, &format[0], &tm);\n        if (count != 0)\n        {\n            buffer.resize(start + count);\n            break;\n        }\n        if (size >= format.size() * 256)\n        {\n            // If the buffer is 256 times larger than the format string, assume\n            // that `strftime` gives an empty result. There doesn't seem to be a\n            // better way to distinguish the two cases:\n            // https://github.com/fmtlib/fmt/issues/367\n            break;\n        }\n        const std::size_t MIN_GROWTH = 10;\n        buffer.reserve(buffer.capacity() + (size > MIN_GROWTH ? size : MIN_GROWTH));\n    }\n    format_str = end + 1;\n}\n\nnamespace internal {\ninline Null<> localtime_r(...)\n{\n    return Null<>();\n}\ninline Null<> localtime_s(...)\n{\n    return Null<>();\n}\ninline Null<> gmtime_r(...)\n{\n    return Null<>();\n}\ninline Null<> gmtime_s(...)\n{\n    return Null<>();\n}\n} // namespace internal\n\n// Thread-safe replacement for std::localtime\ninline std::tm localtime(std::time_t time)\n{\n    struct LocalTime\n    {\n        std::time_t time_;\n        std::tm tm_;\n\n        LocalTime(std::time_t t)\n            : time_(t)\n        {\n        }\n\n        bool run()\n        {\n            using namespace fmt::internal;\n            return handle(localtime_r(&time_, &tm_));\n        }\n\n        bool handle(std::tm *tm)\n        {\n            return tm != FMT_NULL;\n        }\n\n        bool handle(internal::Null<>)\n        {\n            using namespace fmt::internal;\n            return fallback(localtime_s(&tm_, &time_));\n        }\n\n        bool fallback(int res)\n        {\n            return res == 0;\n        }\n\n        bool fallback(internal::Null<>)\n        {\n            using namespace fmt::internal;\n            std::tm *tm = std::localtime(&time_);\n            if (tm)\n                tm_ = *tm;\n            return tm != FMT_NULL;\n        }\n    };\n    LocalTime lt(time);\n    if (lt.run())\n        return lt.tm_;\n    // Too big time values may be unsupported.\n    FMT_THROW(fmt::FormatError(\"time_t value out of range\"));\n    return std::tm();\n}\n\n// Thread-safe replacement for std::gmtime\ninline std::tm gmtime(std::time_t time)\n{\n    struct GMTime\n    {\n        std::time_t time_;\n        std::tm tm_;\n\n        GMTime(std::time_t t)\n            : time_(t)\n        {\n        }\n\n        bool run()\n        {\n            using namespace fmt::internal;\n            return handle(gmtime_r(&time_, &tm_));\n        }\n\n        bool handle(std::tm *tm)\n        {\n            return tm != FMT_NULL;\n        }\n\n        bool handle(internal::Null<>)\n        {\n            using namespace fmt::internal;\n            return fallback(gmtime_s(&tm_, &time_));\n        }\n\n        bool fallback(int res)\n        {\n            return res == 0;\n        }\n\n        bool fallback(internal::Null<>)\n        {\n            std::tm *tm = std::gmtime(&time_);\n            if (tm != FMT_NULL)\n                tm_ = *tm;\n            return tm != FMT_NULL;\n        }\n    };\n    GMTime gt(time);\n    if (gt.run())\n        return gt.tm_;\n    // Too big time values may be unsupported.\n    FMT_THROW(fmt::FormatError(\"time_t value out of range\"));\n    return std::tm();\n}\n} // namespace fmt\n\n#ifdef _MSC_VER\n#pragma warning(pop)\n#endif\n\n#endif // FMT_TIME_H_\n"
  },
  {
    "path": "spdlog/fmt/fmt.h",
    "content": "//\n// Copyright(c) 2016 Gabi Melman.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n//\n\n#pragma once\n\n//\n// Include a bundled header-only copy of fmtlib or an external one.\n// By default spdlog include its own copy.\n//\n\n#if !defined(SPDLOG_FMT_EXTERNAL)\n\n#ifndef FMT_HEADER_ONLY\n#define FMT_HEADER_ONLY\n#endif\n#ifndef FMT_USE_WINDOWS_H\n#define FMT_USE_WINDOWS_H 0\n#endif\n#include \"bundled/format.h\"\n#if defined(SPDLOG_FMT_PRINTF)\n#include \"bundled/printf.h\"\n#endif\n\n#else // external fmtlib\n\n#include <fmt/format.h>\n#if defined(SPDLOG_FMT_PRINTF)\n#include <fmt/printf.h>\n#endif\n\n#endif\n"
  },
  {
    "path": "spdlog/fmt/ostr.h",
    "content": "//\n// Copyright(c) 2016 Gabi Melman.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n//\n\n#pragma once\n//\n// include bundled or external copy of fmtlib's ostream support\n//\n#if !defined(SPDLOG_FMT_EXTERNAL)\n#ifndef FMT_HEADER_ONLY\n#define FMT_HEADER_ONLY\n#endif\n#include \"bundled/ostream.h\"\n#include \"fmt.h\"\n#else\n#include <fmt/ostream.h>\n#endif\n"
  },
  {
    "path": "spdlog/formatter.h",
    "content": "//\n// Copyright(c) 2015 Gabi Melman.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n//\n\n#pragma once\n\n#include \"details/log_msg.h\"\n\n#include <memory>\n#include <string>\n#include <vector>\n\nnamespace spdlog {\nnamespace details {\nclass flag_formatter;\n}\n\nclass formatter\n{\npublic:\n    virtual ~formatter() = default;\n    virtual void format(details::log_msg &msg) = 0;\n};\n\nclass pattern_formatter SPDLOG_FINAL : public formatter\n{\npublic:\n    explicit pattern_formatter(const std::string &pattern, pattern_time_type pattern_time = pattern_time_type::local,\n        std::string eol = spdlog::details::os::default_eol);\n    pattern_formatter(const pattern_formatter &) = delete;\n    pattern_formatter &operator=(const pattern_formatter &) = delete;\n    void format(details::log_msg &msg) override;\n\nprivate:\n    const std::string _eol;\n    const std::string _pattern;\n    const pattern_time_type _pattern_time;\n    std::vector<std::unique_ptr<details::flag_formatter>> _formatters;\n    std::tm get_time(details::log_msg &msg);\n    void handle_flag(char flag);\n    void compile_pattern(const std::string &pattern);\n};\n} // namespace spdlog\n\n#include \"details/pattern_formatter_impl.h\"\n"
  },
  {
    "path": "spdlog/logger.h",
    "content": "//\n// Copyright(c) 2015 Gabi Melman.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n//\n\n#pragma once\n\n// Thread safe logger (except for set_pattern(..), set_formatter(..) and set_error_handler())\n// Has name, log level, vector of std::shared sink pointers and formatter\n// Upon each log write the logger:\n// 1. Checks if its log level is enough to log the message\n// 2. Format the message using the formatter function\n// 3. Pass the formatted message to its sinks to performa the actual logging\n\n#include \"common.h\"\n#include \"sinks/base_sink.h\"\n\n#include <memory>\n#include <string>\n#include <vector>\n\nnamespace spdlog {\n\nclass logger\n{\npublic:\n    logger(const std::string &name, sink_ptr single_sink);\n    logger(const std::string &name, sinks_init_list sinks);\n\n    template<class It>\n    logger(std::string name, const It &begin, const It &end);\n\n    virtual ~logger();\n\n    logger(const logger &) = delete;\n    logger &operator=(const logger &) = delete;\n\n    template<typename... Args>\n    void log(level::level_enum lvl, const char *fmt, const Args &... args);\n\n    template<typename... Args>\n    void log(level::level_enum lvl, const char *msg);\n\n    template<typename Arg1, typename... Args>\n    void trace(const char *fmt, const Arg1 &, const Args &... args);\n\n    template<typename Arg1, typename... Args>\n    void debug(const char *fmt, const Arg1 &, const Args &... args);\n\n    template<typename Arg1, typename... Args>\n    void info(const char *fmt, const Arg1 &, const Args &... args);\n\n    template<typename Arg1, typename... Args>\n    void warn(const char *fmt, const Arg1 &, const Args &... args);\n\n    template<typename Arg1, typename... Args>\n    void error(const char *fmt, const Arg1 &, const Args &... args);\n\n    template<typename Arg1, typename... Args>\n    void critical(const char *fmt, const Arg1 &, const Args &... args);\n\n#ifdef SPDLOG_WCHAR_TO_UTF8_SUPPORT\n    template<typename... Args>\n    void log(level::level_enum lvl, const wchar_t *msg);\n\n    template<typename... Args>\n    void log(level::level_enum lvl, const wchar_t *fmt, const Args &... args);\n\n    template<typename... Args>\n    void trace(const wchar_t *fmt, const Args &... args);\n\n    template<typename... Args>\n    void debug(const wchar_t *fmt, const Args &... args);\n\n    template<typename... Args>\n    void info(const wchar_t *fmt, const Args &... args);\n\n    template<typename... Args>\n    void warn(const wchar_t *fmt, const Args &... args);\n\n    template<typename... Args>\n    void error(const wchar_t *fmt, const Args &... args);\n\n    template<typename... Args>\n    void critical(const wchar_t *fmt, const Args &... args);\n#endif // SPDLOG_WCHAR_TO_UTF8_SUPPORT\n\n    template<typename T>\n    void log(level::level_enum lvl, const T &);\n\n    template<typename T>\n    void trace(const T &msg);\n\n    template<typename T>\n    void debug(const T &msg);\n\n    template<typename T>\n    void info(const T &msg);\n\n    template<typename T>\n    void warn(const T &msg);\n\n    template<typename T>\n    void error(const T &msg);\n\n    template<typename T>\n    void critical(const T &msg);\n\n    bool should_log(level::level_enum msg_level) const;\n    void set_level(level::level_enum log_level);\n    level::level_enum level() const;\n    const std::string &name() const;\n    void set_pattern(const std::string &pattern, pattern_time_type pattern_time = pattern_time_type::local);\n    void set_formatter(formatter_ptr msg_formatter);\n\n    // automatically call flush() if message level >= log_level\n    void flush_on(level::level_enum log_level);\n\n    virtual void flush();\n\n    const std::vector<sink_ptr> &sinks() const;\n\n    // error handler\n    virtual void set_error_handler(log_err_handler err_handler);\n    virtual log_err_handler error_handler();\n\nprotected:\n    virtual void _sink_it(details::log_msg &msg);\n    virtual void _set_pattern(const std::string &pattern, pattern_time_type pattern_time);\n    virtual void _set_formatter(formatter_ptr msg_formatter);\n\n    // default error handler: print the error to stderr with the max rate of 1 message/minute\n    virtual void _default_err_handler(const std::string &msg);\n\n    // return true if the given message level should trigger a flush\n    bool _should_flush_on(const details::log_msg &msg);\n\n    // increment the message count (only if defined(SPDLOG_ENABLE_MESSAGE_COUNTER))\n    void _incr_msg_counter(details::log_msg &msg);\n\n    const std::string _name;\n    std::vector<sink_ptr> _sinks;\n    formatter_ptr _formatter;\n    spdlog::level_t _level;\n    spdlog::level_t _flush_level;\n    log_err_handler _err_handler;\n    std::atomic<time_t> _last_err_time;\n    std::atomic<size_t> _msg_counter;\n};\n} // namespace spdlog\n\n#include \"details/logger_impl.h\"\n"
  },
  {
    "path": "spdlog/sinks/android_sink.h",
    "content": "//\n// Copyright(c) 2015 Gabi Melman.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n//\n\n#pragma once\n\n#if defined(__ANDROID__)\n\n#include \"../details/os.h\"\n#include \"sink.h\"\n\n#include <android/log.h>\n#include <chrono>\n#include <mutex>\n#include <string>\n#include <thread>\n\n#if !defined(SPDLOG_ANDROID_RETRIES)\n#define SPDLOG_ANDROID_RETRIES 2\n#endif\n\nnamespace spdlog {\nnamespace sinks {\n\n/*\n * Android sink (logging using __android_log_write)\n * __android_log_write is thread-safe. No lock is needed.\n */\nclass android_sink : public sink\n{\npublic:\n    explicit android_sink(const std::string &tag = \"spdlog\", bool use_raw_msg = false)\n        : _tag(tag)\n        , _use_raw_msg(use_raw_msg)\n    {\n    }\n\n    void log(const details::log_msg &msg) override\n    {\n        const android_LogPriority priority = convert_to_android(msg.level);\n        const char *msg_output = (_use_raw_msg ? msg.raw.c_str() : msg.formatted.c_str());\n\n        // See system/core/liblog/logger_write.c for explanation of return value\n        int ret = __android_log_write(priority, _tag.c_str(), msg_output);\n        int retry_count = 0;\n        while ((ret == -11 /*EAGAIN*/) && (retry_count < SPDLOG_ANDROID_RETRIES))\n        {\n            details::os::sleep_for_millis(5);\n            ret = __android_log_write(priority, _tag.c_str(), msg_output);\n            retry_count++;\n        }\n\n        if (ret < 0)\n        {\n            throw spdlog_ex(\"__android_log_write() failed\", ret);\n        }\n    }\n\n    void flush() override {}\n\nprivate:\n    static android_LogPriority convert_to_android(spdlog::level::level_enum level)\n    {\n        switch (level)\n        {\n        case spdlog::level::trace:\n            return ANDROID_LOG_VERBOSE;\n        case spdlog::level::debug:\n            return ANDROID_LOG_DEBUG;\n        case spdlog::level::info:\n            return ANDROID_LOG_INFO;\n        case spdlog::level::warn:\n            return ANDROID_LOG_WARN;\n        case spdlog::level::err:\n            return ANDROID_LOG_ERROR;\n        case spdlog::level::critical:\n            return ANDROID_LOG_FATAL;\n        default:\n            return ANDROID_LOG_DEFAULT;\n        }\n    }\n\n    std::string _tag;\n    bool _use_raw_msg;\n};\n\n} // namespace sinks\n} // namespace spdlog\n\n#endif\n"
  },
  {
    "path": "spdlog/sinks/ansicolor_sink.h",
    "content": "//\n// Copyright(c) 2017 spdlog authors.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n//\n\n#pragma once\n\n#include \"../common.h\"\n#include \"../details/os.h\"\n#include \"base_sink.h\"\n\n#include <string>\n#include <unordered_map>\n\nnamespace spdlog {\nnamespace sinks {\n\n/**\n * This sink prefixes the output with an ANSI escape sequence color code depending on the severity\n * of the message.\n * If no color terminal detected, omit the escape codes.\n */\ntemplate<class Mutex>\nclass ansicolor_sink : public base_sink<Mutex>\n{\npublic:\n    explicit ansicolor_sink(FILE *file)\n        : target_file_(file)\n    {\n        should_do_colors_ = details::os::in_terminal(file) && details::os::is_color_terminal();\n        colors_[level::trace] = white;\n        colors_[level::debug] = cyan;\n        colors_[level::info] = green;\n        colors_[level::warn] = yellow + bold;\n        colors_[level::err] = red + bold;\n        colors_[level::critical] = bold + on_red;\n        colors_[level::off] = reset;\n    }\n\n    ~ansicolor_sink() override\n    {\n        _flush();\n    }\n\n    void set_color(level::level_enum color_level, const std::string &color)\n    {\n        std::lock_guard<Mutex> lock(base_sink<Mutex>::_mutex);\n        colors_[color_level] = color;\n    }\n\n    /// Formatting codes\n    const std::string reset = \"\\033[m\";\n    const std::string bold = \"\\033[1m\";\n    const std::string dark = \"\\033[2m\";\n    const std::string underline = \"\\033[4m\";\n    const std::string blink = \"\\033[5m\";\n    const std::string reverse = \"\\033[7m\";\n    const std::string concealed = \"\\033[8m\";\n    const std::string clear_line = \"\\033[K\";\n\n    // Foreground colors\n    const std::string black = \"\\033[30m\";\n    const std::string red = \"\\033[31m\";\n    const std::string green = \"\\033[32m\";\n    const std::string yellow = \"\\033[33m\";\n    const std::string blue = \"\\033[34m\";\n    const std::string magenta = \"\\033[35m\";\n    const std::string cyan = \"\\033[36m\";\n    const std::string white = \"\\033[37m\";\n\n    /// Background colors\n    const std::string on_black = \"\\033[40m\";\n    const std::string on_red = \"\\033[41m\";\n    const std::string on_green = \"\\033[42m\";\n    const std::string on_yellow = \"\\033[43m\";\n    const std::string on_blue = \"\\033[44m\";\n    const std::string on_magenta = \"\\033[45m\";\n    const std::string on_cyan = \"\\033[46m\";\n    const std::string on_white = \"\\033[47m\";\n\nprotected:\n    void _sink_it(const details::log_msg &msg) override\n    {\n        // Wrap the originally formatted message in color codes.\n        // If color is not supported in the terminal, log as is instead.\n        if (should_do_colors_ && msg.color_range_end > msg.color_range_start)\n        {\n            // before color range\n            _print_range(msg, 0, msg.color_range_start);\n            // in color range\n            _print_ccode(colors_[msg.level]);\n            _print_range(msg, msg.color_range_start, msg.color_range_end);\n            _print_ccode(reset);\n            // after color range\n            _print_range(msg, msg.color_range_end, msg.formatted.size());\n        }\n        else\n        {\n            _print_range(msg, 0, msg.formatted.size());\n        }\n        _flush();\n    }\n\n    void _flush() override\n    {\n        fflush(target_file_);\n    }\n\nprivate:\n    void _print_ccode(const std::string &color_code)\n    {\n        fwrite(color_code.data(), sizeof(char), color_code.size(), target_file_);\n    }\n    void _print_range(const details::log_msg &msg, size_t start, size_t end)\n    {\n        fwrite(msg.formatted.data() + start, sizeof(char), end - start, target_file_);\n    }\n    FILE *target_file_;\n    bool should_do_colors_;\n    std::unordered_map<level::level_enum, std::string, level::level_hasher> colors_;\n};\n\ntemplate<class Mutex>\nclass ansicolor_stdout_sink : public ansicolor_sink<Mutex>\n{\npublic:\n    ansicolor_stdout_sink()\n        : ansicolor_sink<Mutex>(stdout)\n    {\n    }\n};\n\nusing ansicolor_stdout_sink_mt = ansicolor_stdout_sink<std::mutex>;\nusing ansicolor_stdout_sink_st = ansicolor_stdout_sink<details::null_mutex>;\n\ntemplate<class Mutex>\nclass ansicolor_stderr_sink : public ansicolor_sink<Mutex>\n{\npublic:\n    ansicolor_stderr_sink()\n        : ansicolor_sink<Mutex>(stderr)\n    {\n    }\n};\n\nusing ansicolor_stderr_sink_mt = ansicolor_stderr_sink<std::mutex>;\nusing ansicolor_stderr_sink_st = ansicolor_stderr_sink<details::null_mutex>;\n\n} // namespace sinks\n} // namespace spdlog\n"
  },
  {
    "path": "spdlog/sinks/base_sink.h",
    "content": "//\n// Copyright(c) 2015 Gabi Melman.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n//\n\n#pragma once\n//\n// base sink templated over a mutex (either dummy or real)\n// concrete implementation should only override the _sink_it method.\n// all locking is taken care of here so no locking needed by the implementers..\n//\n\n#include \"../common.h\"\n#include \"../details/log_msg.h\"\n#include \"../formatter.h\"\n#include \"sink.h\"\n\n#include <mutex>\n\nnamespace spdlog {\nnamespace sinks {\ntemplate<class Mutex>\nclass base_sink : public sink\n{\npublic:\n    base_sink() = default;\n\n    base_sink(const base_sink &) = delete;\n    base_sink &operator=(const base_sink &) = delete;\n\n    void log(const details::log_msg &msg) SPDLOG_FINAL override\n    {\n        std::lock_guard<Mutex> lock(_mutex);\n        _sink_it(msg);\n    }\n\n    void flush() SPDLOG_FINAL override\n    {\n        std::lock_guard<Mutex> lock(_mutex);\n        _flush();\n    }\n\nprotected:\n    virtual void _sink_it(const details::log_msg &msg) = 0;\n    virtual void _flush() = 0;\n    Mutex _mutex;\n};\n} // namespace sinks\n} // namespace spdlog\n"
  },
  {
    "path": "spdlog/sinks/dist_sink.h",
    "content": "//\n// Copyright (c) 2015 David Schury, Gabi Melman\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n//\n\n#pragma once\n\n#include \"../details/log_msg.h\"\n#include \"../details/null_mutex.h\"\n#include \"base_sink.h\"\n#include \"sink.h\"\n\n#include <algorithm>\n#include <memory>\n#include <mutex>\n#include <vector>\n\n// Distribution sink (mux). Stores a vector of sinks which get called when log is called\n\nnamespace spdlog {\nnamespace sinks {\ntemplate<class Mutex>\nclass dist_sink : public base_sink<Mutex>\n{\npublic:\n    explicit dist_sink()\n        : _sinks()\n    {\n    }\n    dist_sink(const dist_sink &) = delete;\n    dist_sink &operator=(const dist_sink &) = delete;\n\nprotected:\n    std::vector<std::shared_ptr<sink>> _sinks;\n\n    void _sink_it(const details::log_msg &msg) override\n    {\n        for (auto &sink : _sinks)\n        {\n            if (sink->should_log(msg.level))\n            {\n                sink->log(msg);\n            }\n        }\n    }\n\n    void _flush() override\n    {\n        for (auto &sink : _sinks)\n            sink->flush();\n    }\n\npublic:\n    void add_sink(std::shared_ptr<sink> sink)\n    {\n        std::lock_guard<Mutex> lock(base_sink<Mutex>::_mutex);\n        _sinks.push_back(sink);\n    }\n\n    void remove_sink(std::shared_ptr<sink> sink)\n    {\n        std::lock_guard<Mutex> lock(base_sink<Mutex>::_mutex);\n        _sinks.erase(std::remove(_sinks.begin(), _sinks.end(), sink), _sinks.end());\n    }\n\n    void remove_all_sinks()\n    {\n        std::lock_guard<Mutex> lock(base_sink<Mutex>::_mutex);\n        _sinks.clear();\n    }\n};\n\nusing dist_sink_mt = dist_sink<std::mutex>;\nusing dist_sink_st = dist_sink<details::null_mutex>;\n\n} // namespace sinks\n} // namespace spdlog\n"
  },
  {
    "path": "spdlog/sinks/file_sinks.h",
    "content": "//\n// Copyright(c) 2015 Gabi Melman.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n//\n\n#pragma once\n\n#include \"../details/file_helper.h\"\n#include \"../details/null_mutex.h\"\n#include \"../fmt/fmt.h\"\n#include \"base_sink.h\"\n\n#include <algorithm>\n#include <cerrno>\n#include <chrono>\n#include <cstdio>\n#include <ctime>\n#include <mutex>\n#include <string>\n\nnamespace spdlog {\nnamespace sinks {\n/*\n * Trivial file sink with single file as target\n */\ntemplate<class Mutex>\nclass simple_file_sink SPDLOG_FINAL : public base_sink<Mutex>\n{\npublic:\n    explicit simple_file_sink(const filename_t &filename, bool truncate = false)\n        : _force_flush(false)\n    {\n        _file_helper.open(filename, truncate);\n    }\n\n    void set_force_flush(bool force_flush)\n    {\n        _force_flush = force_flush;\n    }\n\nprotected:\n    void _sink_it(const details::log_msg &msg) override\n    {\n        _file_helper.write(msg);\n        if (_force_flush)\n        {\n            _file_helper.flush();\n        }\n    }\n\n    void _flush() override\n    {\n        _file_helper.flush();\n    }\n\nprivate:\n    details::file_helper _file_helper;\n    bool _force_flush;\n};\n\nusing simple_file_sink_mt = simple_file_sink<std::mutex>;\nusing simple_file_sink_st = simple_file_sink<details::null_mutex>;\n\n/*\n * Rotating file sink based on size\n */\ntemplate<class Mutex>\nclass rotating_file_sink SPDLOG_FINAL : public base_sink<Mutex>\n{\npublic:\n    rotating_file_sink(filename_t base_filename, std::size_t max_size, std::size_t max_files)\n        : _base_filename(std::move(base_filename))\n        , _max_size(max_size)\n        , _max_files(max_files)\n    {\n        _file_helper.open(calc_filename(_base_filename, 0));\n        _current_size = _file_helper.size(); // expensive. called only once\n    }\n\n    // calc filename according to index and file extension if exists.\n    // e.g. calc_filename(\"logs/mylog.txt, 3) => \"logs/mylog.3.txt\".\n    static filename_t calc_filename(const filename_t &filename, std::size_t index)\n    {\n        typename std::conditional<std::is_same<filename_t::value_type, char>::value, fmt::MemoryWriter, fmt::WMemoryWriter>::type w;\n        if (index != 0u)\n        {\n            filename_t basename, ext;\n            std::tie(basename, ext) = details::file_helper::split_by_extenstion(filename);\n            w.write(SPDLOG_FILENAME_T(\"{}.{}{}\"), basename, index, ext);\n        }\n        else\n        {\n            w.write(SPDLOG_FILENAME_T(\"{}\"), filename);\n        }\n        return w.str();\n    }\n\nprotected:\n    void _sink_it(const details::log_msg &msg) override\n    {\n        _current_size += msg.formatted.size();\n        if (_current_size > _max_size)\n        {\n            _rotate();\n            _current_size = msg.formatted.size();\n        }\n        _file_helper.write(msg);\n    }\n\n    void _flush() override\n    {\n        _file_helper.flush();\n    }\n\nprivate:\n    // Rotate files:\n    // log.txt -> log.1.txt\n    // log.1.txt -> log.2.txt\n    // log.2.txt -> log.3.txt\n    // log.3.txt -> delete\n    void _rotate()\n    {\n        using details::os::filename_to_str;\n        _file_helper.close();\n        for (auto i = _max_files; i > 0; --i)\n        {\n            filename_t src = calc_filename(_base_filename, i - 1);\n            filename_t target = calc_filename(_base_filename, i);\n\n            if (details::file_helper::file_exists(target))\n            {\n                if (details::os::remove(target) != 0)\n                {\n                    throw spdlog_ex(\"rotating_file_sink: failed removing \" + filename_to_str(target), errno);\n                }\n            }\n            if (details::file_helper::file_exists(src) && details::os::rename(src, target) != 0)\n            {\n                throw spdlog_ex(\"rotating_file_sink: failed renaming \" + filename_to_str(src) + \" to \" + filename_to_str(target), errno);\n            }\n        }\n        _file_helper.reopen(true);\n    }\n\n    filename_t _base_filename;\n    std::size_t _max_size;\n    std::size_t _max_files;\n    std::size_t _current_size;\n    details::file_helper _file_helper;\n};\n\nusing rotating_file_sink_mt = rotating_file_sink<std::mutex>;\nusing rotating_file_sink_st = rotating_file_sink<details::null_mutex>;\n\n/*\n * Default generator of daily log file names.\n */\nstruct default_daily_file_name_calculator\n{\n    // Create filename for the form filename.YYYY-MM-DD_hh-mm.ext\n    static filename_t calc_filename(const filename_t &filename)\n    {\n        std::tm tm = spdlog::details::os::localtime();\n        filename_t basename, ext;\n        std::tie(basename, ext) = details::file_helper::split_by_extenstion(filename);\n        std::conditional<std::is_same<filename_t::value_type, char>::value, fmt::MemoryWriter, fmt::WMemoryWriter>::type w;\n        w.write(SPDLOG_FILENAME_T(\"{}_{:04d}-{:02d}-{:02d}_{:02d}-{:02d}{}\"), basename, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,\n            tm.tm_hour, tm.tm_min, ext);\n        return w.str();\n    }\n};\n\n/*\n * Generator of daily log file names in format basename.YYYY-MM-DD.ext\n */\nstruct dateonly_daily_file_name_calculator\n{\n    // Create filename for the form basename.YYYY-MM-DD\n    static filename_t calc_filename(const filename_t &filename)\n    {\n        std::tm tm = spdlog::details::os::localtime();\n        filename_t basename, ext;\n        std::tie(basename, ext) = details::file_helper::split_by_extenstion(filename);\n        std::conditional<std::is_same<filename_t::value_type, char>::value, fmt::MemoryWriter, fmt::WMemoryWriter>::type w;\n        w.write(SPDLOG_FILENAME_T(\"{}_{:04d}-{:02d}-{:02d}{}\"), basename, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, ext);\n        return w.str();\n    }\n};\n\n/*\n * Rotating file sink based on date. rotates at midnight\n */\ntemplate<class Mutex, class FileNameCalc = default_daily_file_name_calculator>\nclass daily_file_sink SPDLOG_FINAL : public base_sink<Mutex>\n{\npublic:\n    // create daily file sink which rotates on given time\n    daily_file_sink(filename_t base_filename, int rotation_hour, int rotation_minute)\n        : _base_filename(std::move(base_filename))\n        , _rotation_h(rotation_hour)\n        , _rotation_m(rotation_minute)\n    {\n        if (rotation_hour < 0 || rotation_hour > 23 || rotation_minute < 0 || rotation_minute > 59)\n        {\n            throw spdlog_ex(\"daily_file_sink: Invalid rotation time in ctor\");\n        }\n        _rotation_tp = _next_rotation_tp();\n        _file_helper.open(FileNameCalc::calc_filename(_base_filename));\n    }\n\nprotected:\n    void _sink_it(const details::log_msg &msg) override\n    {\n        if (std::chrono::system_clock::now() >= _rotation_tp)\n        {\n            _file_helper.open(FileNameCalc::calc_filename(_base_filename));\n            _rotation_tp = _next_rotation_tp();\n        }\n        _file_helper.write(msg);\n    }\n\n    void _flush() override\n    {\n        _file_helper.flush();\n    }\n\nprivate:\n    std::chrono::system_clock::time_point _next_rotation_tp()\n    {\n        auto now = std::chrono::system_clock::now();\n        time_t tnow = std::chrono::system_clock::to_time_t(now);\n        tm date = spdlog::details::os::localtime(tnow);\n        date.tm_hour = _rotation_h;\n        date.tm_min = _rotation_m;\n        date.tm_sec = 0;\n        auto rotation_time = std::chrono::system_clock::from_time_t(std::mktime(&date));\n        if (rotation_time > now)\n        {\n            return rotation_time;\n        }\n        return {rotation_time + std::chrono::hours(24)};\n    }\n\n    filename_t _base_filename;\n    int _rotation_h;\n    int _rotation_m;\n    std::chrono::system_clock::time_point _rotation_tp;\n    details::file_helper _file_helper;\n};\n\nusing daily_file_sink_mt = daily_file_sink<std::mutex>;\nusing daily_file_sink_st = daily_file_sink<details::null_mutex>;\n\n} // namespace sinks\n} // namespace spdlog\n"
  },
  {
    "path": "spdlog/sinks/msvc_sink.h",
    "content": "//\n// Copyright(c) 2016 Alexander Dalshov.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n//\n\n#pragma once\n\n#if defined(_WIN32)\n\n#include \"../details/null_mutex.h\"\n#include \"base_sink.h\"\n\n#include <winbase.h>\n\n#include <mutex>\n#include <string>\n\nnamespace spdlog {\nnamespace sinks {\n/*\n * MSVC sink (logging using OutputDebugStringA)\n */\ntemplate<class Mutex>\nclass msvc_sink : public base_sink<Mutex>\n{\npublic:\n    explicit msvc_sink() {}\n\nprotected:\n    void _sink_it(const details::log_msg &msg) override\n    {\n        OutputDebugStringA(msg.formatted.c_str());\n    }\n\n    void _flush() override {}\n};\n\nusing msvc_sink_mt = msvc_sink<std::mutex>;\nusing msvc_sink_st = msvc_sink<details::null_mutex>;\n\n} // namespace sinks\n} // namespace spdlog\n\n#endif\n"
  },
  {
    "path": "spdlog/sinks/null_sink.h",
    "content": "//\n// Copyright(c) 2015 Gabi Melman.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n//\n\n#pragma once\n\n#include \"../details/null_mutex.h\"\n#include \"base_sink.h\"\n\n#include <mutex>\n\nnamespace spdlog {\nnamespace sinks {\n\ntemplate<class Mutex>\nclass null_sink : public base_sink<Mutex>\n{\nprotected:\n    void _sink_it(const details::log_msg &) override {}\n\n    void _flush() override {}\n};\n\nusing null_sink_mt = null_sink<details::null_mutex>;\nusing null_sink_st = null_sink<details::null_mutex>;\n\n} // namespace sinks\n} // namespace spdlog\n"
  },
  {
    "path": "spdlog/sinks/ostream_sink.h",
    "content": "//\n// Copyright(c) 2015 Gabi Melman.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n//\n\n#pragma once\n\n#include \"../details/null_mutex.h\"\n#include \"base_sink.h\"\n\n#include <mutex>\n#include <ostream>\n\nnamespace spdlog {\nnamespace sinks {\ntemplate<class Mutex>\nclass ostream_sink : public base_sink<Mutex>\n{\npublic:\n    explicit ostream_sink(std::ostream &os, bool force_flush = false)\n        : _ostream(os)\n        , _force_flush(force_flush)\n    {\n    }\n    ostream_sink(const ostream_sink &) = delete;\n    ostream_sink &operator=(const ostream_sink &) = delete;\n\nprotected:\n    void _sink_it(const details::log_msg &msg) override\n    {\n        _ostream.write(msg.formatted.data(), msg.formatted.size());\n        if (_force_flush)\n            _ostream.flush();\n    }\n\n    void _flush() override\n    {\n        _ostream.flush();\n    }\n\n    std::ostream &_ostream;\n    bool _force_flush;\n};\n\nusing ostream_sink_mt = ostream_sink<std::mutex>;\nusing ostream_sink_st = ostream_sink<details::null_mutex>;\n\n} // namespace sinks\n} // namespace spdlog\n"
  },
  {
    "path": "spdlog/sinks/sink.h",
    "content": "//\n// Copyright(c) 2015 Gabi Melman.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n//\n\n#pragma once\n\n#include \"../details/log_msg.h\"\n\nnamespace spdlog {\nnamespace sinks {\nclass sink\n{\npublic:\n    virtual ~sink() = default;\n\n    virtual void log(const details::log_msg &msg) = 0;\n    virtual void flush() = 0;\n\n    bool should_log(level::level_enum msg_level) const;\n    void set_level(level::level_enum log_level);\n    level::level_enum level() const;\n\nprivate:\n    level_t _level{level::trace};\n};\n\ninline bool sink::should_log(level::level_enum msg_level) const\n{\n    return msg_level >= _level.load(std::memory_order_relaxed);\n}\n\ninline void sink::set_level(level::level_enum log_level)\n{\n    _level.store(log_level);\n}\n\ninline level::level_enum sink::level() const\n{\n    return static_cast<spdlog::level::level_enum>(_level.load(std::memory_order_relaxed));\n}\n\n} // namespace sinks\n} // namespace spdlog\n"
  },
  {
    "path": "spdlog/sinks/stdout_sinks.h",
    "content": "//\n// Copyright(c) 2015 Gabi Melman.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n//\n\n#pragma once\n\n#include \"../details/null_mutex.h\"\n#include \"base_sink.h\"\n\n#include <cstdio>\n#include <memory>\n#include <mutex>\n\nnamespace spdlog {\nnamespace sinks {\n\ntemplate<class Mutex>\nclass stdout_sink SPDLOG_FINAL : public base_sink<Mutex>\n{\n    using MyType = stdout_sink<Mutex>;\n\npublic:\n    explicit stdout_sink() = default;\n\n    static std::shared_ptr<MyType> instance()\n    {\n        static std::shared_ptr<MyType> instance = std::make_shared<MyType>();\n        return instance;\n    }\n\nprotected:\n    void _sink_it(const details::log_msg &msg) override\n    {\n        fwrite(msg.formatted.data(), sizeof(char), msg.formatted.size(), stdout);\n        _flush();\n    }\n\n    void _flush() override\n    {\n        fflush(stdout);\n    }\n};\n\nusing stdout_sink_mt = stdout_sink<std::mutex>;\nusing stdout_sink_st = stdout_sink<details::null_mutex>;\n\ntemplate<class Mutex>\nclass stderr_sink SPDLOG_FINAL : public base_sink<Mutex>\n{\n    using MyType = stderr_sink<Mutex>;\n\npublic:\n    explicit stderr_sink() = default;\n\n    static std::shared_ptr<MyType> instance()\n    {\n        static std::shared_ptr<MyType> instance = std::make_shared<MyType>();\n        return instance;\n    }\n\nprotected:\n    void _sink_it(const details::log_msg &msg) override\n    {\n        fwrite(msg.formatted.data(), sizeof(char), msg.formatted.size(), stderr);\n        _flush();\n    }\n\n    void _flush() override\n    {\n        fflush(stderr);\n    }\n};\n\nusing stderr_sink_mt = stderr_sink<std::mutex>;\nusing stderr_sink_st = stderr_sink<details::null_mutex>;\n\n} // namespace sinks\n} // namespace spdlog\n"
  },
  {
    "path": "spdlog/sinks/syslog_sink.h",
    "content": "//\n// Copyright(c) 2015 Gabi Melman.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n//\n\n#pragma once\n\n#include \"../common.h\"\n\n#ifdef SPDLOG_ENABLE_SYSLOG\n\n#include \"../details/log_msg.h\"\n#include \"sink.h\"\n\n#include <array>\n#include <string>\n#include <syslog.h>\n\nnamespace spdlog {\nnamespace sinks {\n/**\n * Sink that write to syslog using the `syscall()` library call.\n *\n * Locking is not needed, as `syslog()` itself is thread-safe.\n */\nclass syslog_sink : public sink\n{\npublic:\n    //\n    syslog_sink(const std::string &ident = \"\", int syslog_option = 0, int syslog_facility = LOG_USER)\n        : _ident(ident)\n    {\n        _priorities[static_cast<size_t>(level::trace)] = LOG_DEBUG;\n        _priorities[static_cast<size_t>(level::debug)] = LOG_DEBUG;\n        _priorities[static_cast<size_t>(level::info)] = LOG_INFO;\n        _priorities[static_cast<size_t>(level::warn)] = LOG_WARNING;\n        _priorities[static_cast<size_t>(level::err)] = LOG_ERR;\n        _priorities[static_cast<size_t>(level::critical)] = LOG_CRIT;\n        _priorities[static_cast<size_t>(level::off)] = LOG_INFO;\n\n        // set ident to be program name if empty\n        ::openlog(_ident.empty() ? nullptr : _ident.c_str(), syslog_option, syslog_facility);\n    }\n\n    ~syslog_sink() override\n    {\n        ::closelog();\n    }\n\n    syslog_sink(const syslog_sink &) = delete;\n    syslog_sink &operator=(const syslog_sink &) = delete;\n\n    void log(const details::log_msg &msg) override\n    {\n        ::syslog(syslog_prio_from_level(msg), \"%s\", msg.raw.str().c_str());\n    }\n\n    void flush() override {}\n\nprivate:\n    std::array<int, 7> _priorities;\n    // must store the ident because the man says openlog might use the pointer as is and not a string copy\n    const std::string _ident;\n\n    //\n    // Simply maps spdlog's log level to syslog priority level.\n    //\n    int syslog_prio_from_level(const details::log_msg &msg) const\n    {\n        return _priorities[static_cast<size_t>(msg.level)];\n    }\n};\n} // namespace sinks\n} // namespace spdlog\n\n#endif\n"
  },
  {
    "path": "spdlog/sinks/wincolor_sink.h",
    "content": "//\n// Copyright(c) 2016 spdlog\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n//\n\n#pragma once\n\n#include \"../common.h\"\n#include \"../details/null_mutex.h\"\n#include \"base_sink.h\"\n\n#include <mutex>\n#include <string>\n#include <unordered_map>\n#include <wincon.h>\n\nnamespace spdlog {\nnamespace sinks {\n/*\n * Windows color console sink. Uses WriteConsoleA to write to the console with colors\n */\ntemplate<class Mutex>\nclass wincolor_sink : public base_sink<Mutex>\n{\npublic:\n    const WORD BOLD = FOREGROUND_INTENSITY;\n    const WORD RED = FOREGROUND_RED;\n    const WORD GREEN = FOREGROUND_GREEN;\n    const WORD CYAN = FOREGROUND_GREEN | FOREGROUND_BLUE;\n    const WORD WHITE = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;\n    const WORD YELLOW = FOREGROUND_RED | FOREGROUND_GREEN;\n\n    wincolor_sink(HANDLE std_handle)\n        : out_handle_(std_handle)\n    {\n        colors_[level::trace] = WHITE;\n        colors_[level::debug] = CYAN;\n        colors_[level::info] = GREEN;\n        colors_[level::warn] = YELLOW | BOLD;\n        colors_[level::err] = RED | BOLD;                         // red bold\n        colors_[level::critical] = BACKGROUND_RED | WHITE | BOLD; // white bold on red background\n        colors_[level::off] = 0;\n    }\n\n    ~wincolor_sink() override\n    {\n        this->flush();\n    }\n\n    wincolor_sink(const wincolor_sink &other) = delete;\n    wincolor_sink &operator=(const wincolor_sink &other) = delete;\n\n    // change the color for the given level\n    void set_color(level::level_enum level, WORD color)\n    {\n        std::lock_guard<Mutex> lock(base_sink<Mutex>::_mutex);\n        colors_[level] = color;\n    }\n\nprotected:\n    void _sink_it(const details::log_msg &msg) override\n    {\n        if (msg.color_range_end > msg.color_range_start)\n        {\n            // before color range\n            _print_range(msg, 0, msg.color_range_start);\n\n            // in color range\n            auto orig_attribs = set_console_attribs(colors_[msg.level]);\n            _print_range(msg, msg.color_range_start, msg.color_range_end);\n            ::SetConsoleTextAttribute(out_handle_, orig_attribs); // reset to orig colors\n            // after color range\n            _print_range(msg, msg.color_range_end, msg.formatted.size());\n        }\n        else // print without colors if color range is invalid\n        {\n            _print_range(msg, 0, msg.formatted.size());\n        }\n    }\n\n    void _flush() override\n    {\n        // windows console always flushed?\n    }\n\nprivate:\n    HANDLE out_handle_;\n    std::unordered_map<level::level_enum, WORD, level::level_hasher> colors_;\n\n    // set color and return the orig console attributes (for resetting later)\n    WORD set_console_attribs(WORD attribs)\n    {\n        CONSOLE_SCREEN_BUFFER_INFO orig_buffer_info;\n        GetConsoleScreenBufferInfo(out_handle_, &orig_buffer_info);\n        WORD back_color = orig_buffer_info.wAttributes;\n        // retrieve the current background color\n        back_color &= static_cast<WORD>(~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY));\n        // keep the background color unchanged\n        SetConsoleTextAttribute(out_handle_, attribs | back_color);\n        return orig_buffer_info.wAttributes; // return orig attribs\n    }\n\n    // print a range of formatted message to console\n    void _print_range(const details::log_msg &msg, size_t start, size_t end)\n    {\n        DWORD size = static_cast<DWORD>(end - start);\n        WriteConsoleA(out_handle_, msg.formatted.data() + start, size, nullptr, nullptr);\n    }\n};\n\n//\n// windows color console to stdout\n//\ntemplate<class Mutex>\nclass wincolor_stdout_sink : public wincolor_sink<Mutex>\n{\npublic:\n    wincolor_stdout_sink()\n        : wincolor_sink<Mutex>(GetStdHandle(STD_OUTPUT_HANDLE))\n    {\n    }\n};\n\nusing wincolor_stdout_sink_mt = wincolor_stdout_sink<std::mutex>;\nusing wincolor_stdout_sink_st = wincolor_stdout_sink<details::null_mutex>;\n\n//\n// windows color console to stderr\n//\ntemplate<class Mutex>\nclass wincolor_stderr_sink : public wincolor_sink<Mutex>\n{\npublic:\n    wincolor_stderr_sink()\n        : wincolor_sink<Mutex>(GetStdHandle(STD_ERROR_HANDLE))\n    {\n    }\n};\n\nusing wincolor_stderr_sink_mt = wincolor_stderr_sink<std::mutex>;\nusing wincolor_stderr_sink_st = wincolor_stderr_sink<details::null_mutex>;\n\n} // namespace sinks\n} // namespace spdlog\n"
  },
  {
    "path": "spdlog/sinks/windebug_sink.h",
    "content": "//\n// Copyright(c) 2017 Alexander Dalshov.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n//\n\n#pragma once\n\n#if defined(_WIN32)\n\n#include \"msvc_sink.h\"\n\nnamespace spdlog {\nnamespace sinks {\n\n/*\n * Windows debug sink (logging using OutputDebugStringA, synonym for msvc_sink)\n */\ntemplate<class Mutex>\nusing windebug_sink = msvc_sink<Mutex>;\n\nusing windebug_sink_mt = msvc_sink_mt;\nusing windebug_sink_st = msvc_sink_st;\n\n} // namespace sinks\n} // namespace spdlog\n\n#endif\n"
  },
  {
    "path": "spdlog/spdlog.h",
    "content": "//\n// Copyright(c) 2015 Gabi Melman.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n//\n// spdlog main header file.\n// see example.cpp for usage example\n\n#pragma once\n\n#include \"common.h\"\n#include \"logger.h\"\n\n#include <chrono>\n#include <functional>\n#include <memory>\n#include <string>\n\nnamespace spdlog {\n\n//\n// Return an existing logger or nullptr if a logger with such name doesn't exist.\n// example: spdlog::get(\"my_logger\")->info(\"hello {}\", \"world\");\n//\nstd::shared_ptr<logger> get(const std::string &name);\n\n//\n// Set global formatting\n// example: spdlog::set_pattern(\"%Y-%m-%d %H:%M:%S.%e %l : %v\");\n//\nvoid set_pattern(const std::string &format_string);\nvoid set_formatter(formatter_ptr f);\n\n//\n// Set global logging level\n//\nvoid set_level(level::level_enum log_level);\n\n//\n// Set global flush level\n//\nvoid flush_on(level::level_enum log_level);\n\n//\n// Set global error handler\n//\nvoid set_error_handler(log_err_handler handler);\n\n//\n// Turn on async mode (off by default) and set the queue size for each async_logger.\n// effective only for loggers created after this call.\n// queue_size: size of queue (must be power of 2):\n//    Each logger will pre-allocate a dedicated queue with queue_size entries upon construction.\n//\n// async_overflow_policy (optional, block_retry by default):\n//    async_overflow_policy::block_retry - if queue is full, block until queue has room for the new log entry.\n//    async_overflow_policy::discard_log_msg - never block and discard any new messages when queue overflows.\n//\n// worker_warmup_cb (optional):\n//     callback function that will be called in worker thread upon start (can be used to init stuff like thread affinity)\n//\n// worker_teardown_cb (optional):\n//     callback function that will be called in worker thread upon exit\n//\nvoid set_async_mode(size_t queue_size, const async_overflow_policy overflow_policy = async_overflow_policy::block_retry,\n    const std::function<void()> &worker_warmup_cb = nullptr,\n    const std::chrono::milliseconds &flush_interval_ms = std::chrono::milliseconds::zero(),\n    const std::function<void()> &worker_teardown_cb = nullptr);\n\n// Turn off async mode\nvoid set_sync_mode();\n\n//\n// Create and register multi/single threaded basic file logger.\n// Basic logger simply writes to given file without any limitations or rotations.\n//\nstd::shared_ptr<logger> basic_logger_mt(const std::string &logger_name, const filename_t &filename, bool truncate = false);\nstd::shared_ptr<logger> basic_logger_st(const std::string &logger_name, const filename_t &filename, bool truncate = false);\n\n//\n// Create and register multi/single threaded rotating file logger\n//\nstd::shared_ptr<logger> rotating_logger_mt(\n    const std::string &logger_name, const filename_t &filename, size_t max_file_size, size_t max_files);\n\nstd::shared_ptr<logger> rotating_logger_st(\n    const std::string &logger_name, const filename_t &filename, size_t max_file_size, size_t max_files);\n\n//\n// Create file logger which creates new file on the given time (default in midnight):\n//\nstd::shared_ptr<logger> daily_logger_mt(const std::string &logger_name, const filename_t &filename, int hour = 0, int minute = 0);\nstd::shared_ptr<logger> daily_logger_st(const std::string &logger_name, const filename_t &filename, int hour = 0, int minute = 0);\n\n//\n// Create and register stdout/stderr loggers\n//\nstd::shared_ptr<logger> stdout_logger_mt(const std::string &logger_name);\nstd::shared_ptr<logger> stdout_logger_st(const std::string &logger_name);\nstd::shared_ptr<logger> stderr_logger_mt(const std::string &logger_name);\nstd::shared_ptr<logger> stderr_logger_st(const std::string &logger_name);\n//\n// Create and register colored stdout/stderr loggers\n//\nstd::shared_ptr<logger> stdout_color_mt(const std::string &logger_name);\nstd::shared_ptr<logger> stdout_color_st(const std::string &logger_name);\nstd::shared_ptr<logger> stderr_color_mt(const std::string &logger_name);\nstd::shared_ptr<logger> stderr_color_st(const std::string &logger_name);\n\n//\n// Create and register a syslog logger\n//\n#ifdef SPDLOG_ENABLE_SYSLOG\nstd::shared_ptr<logger> syslog_logger(\n    const std::string &logger_name, const std::string &ident = \"\", int syslog_option = 0, int syslog_facilty = (1 << 3));\n#endif\n\n#if defined(__ANDROID__)\nstd::shared_ptr<logger> android_logger(const std::string &logger_name, const std::string &tag = \"spdlog\");\n#endif\n\n// Create and register a logger with a single sink\nstd::shared_ptr<logger> create(const std::string &logger_name, const sink_ptr &sink);\n\n// Create and register a logger with multiple sinks\nstd::shared_ptr<logger> create(const std::string &logger_name, sinks_init_list sinks);\n\ntemplate<class It>\nstd::shared_ptr<logger> create(const std::string &logger_name, const It &sinks_begin, const It &sinks_end);\n\n// Create and register a logger with templated sink type\n// Example:\n// spdlog::create<daily_file_sink_st>(\"mylog\", \"dailylog_filename\");\ntemplate<typename Sink, typename... Args>\nstd::shared_ptr<spdlog::logger> create(const std::string &logger_name, Args... args);\n\n// Create and register an async logger with a single sink\nstd::shared_ptr<logger> create_async(const std::string &logger_name, const sink_ptr &sink, size_t queue_size,\n    const async_overflow_policy overflow_policy = async_overflow_policy::block_retry,\n    const std::function<void()> &worker_warmup_cb = nullptr,\n    const std::chrono::milliseconds &flush_interval_ms = std::chrono::milliseconds::zero(),\n    const std::function<void()> &worker_teardown_cb = nullptr);\n\n// Create and register an async logger with multiple sinks\nstd::shared_ptr<logger> create_async(const std::string &logger_name, sinks_init_list sinks, size_t queue_size,\n    const async_overflow_policy overflow_policy = async_overflow_policy::block_retry,\n    const std::function<void()> &worker_warmup_cb = nullptr,\n    const std::chrono::milliseconds &flush_interval_ms = std::chrono::milliseconds::zero(),\n    const std::function<void()> &worker_teardown_cb = nullptr);\n\ntemplate<class It>\nstd::shared_ptr<logger> create_async(const std::string &logger_name, const It &sinks_begin, const It &sinks_end, size_t queue_size,\n    const async_overflow_policy overflow_policy = async_overflow_policy::block_retry,\n    const std::function<void()> &worker_warmup_cb = nullptr,\n    const std::chrono::milliseconds &flush_interval_ms = std::chrono::milliseconds::zero(),\n    const std::function<void()> &worker_teardown_cb = nullptr);\n\n// Register the given logger with the given name\nvoid register_logger(std::shared_ptr<logger> logger);\n\n// Apply a user defined function on all registered loggers\n// Example:\n// spdlog::apply_all([&](std::shared_ptr<spdlog::logger> l) {l->flush();});\nvoid apply_all(std::function<void(std::shared_ptr<logger>)> fun);\n\n// Drop the reference to the given logger\nvoid drop(const std::string &name);\n\n// Drop all references from the registry\nvoid drop_all();\n\n///////////////////////////////////////////////////////////////////////////////\n//\n// Trace & Debug can be switched on/off at compile time for zero cost debug statements.\n// Uncomment SPDLOG_DEBUG_ON/SPDLOG_TRACE_ON in tweakme.h to enable.\n// SPDLOG_TRACE(..) will also print current file and line.\n//\n// Example:\n// spdlog::set_level(spdlog::level::trace);\n// SPDLOG_TRACE(my_logger, \"some trace message\");\n// SPDLOG_TRACE(my_logger, \"another trace message {} {}\", 1, 2);\n// SPDLOG_DEBUG(my_logger, \"some debug message {} {}\", 3, 4);\n///////////////////////////////////////////////////////////////////////////////\n\n#ifdef SPDLOG_TRACE_ON\n#define SPDLOG_STR_H(x) #x\n#define SPDLOG_STR_HELPER(x) SPDLOG_STR_H(x)\n#ifdef _MSC_VER\n#define SPDLOG_TRACE(logger, ...) logger->trace(\"[ \" __FILE__ \"(\" SPDLOG_STR_HELPER(__LINE__) \") ] \" __VA_ARGS__)\n#else\n#define SPDLOG_TRACE(logger, ...) logger->trace(\"[ \" __FILE__ \":\" SPDLOG_STR_HELPER(__LINE__) \" ] \" __VA_ARGS__)\n#endif\n#else\n#define SPDLOG_TRACE(logger, ...) (void)0\n#endif\n\n#ifdef SPDLOG_DEBUG_ON\n#define SPDLOG_DEBUG(logger, ...) logger->debug(__VA_ARGS__)\n#else\n#define SPDLOG_DEBUG(logger, ...) (void)0\n#endif\n\n} // namespace spdlog\n\n#include \"details/spdlog_impl.h\"\n"
  },
  {
    "path": "spdlog/tweakme.h",
    "content": "//\n// Copyright(c) 2015 Gabi Melman.\n// Distributed under the MIT License (http://opensource.org/licenses/MIT)\n//\n\n#pragma once\n\n///////////////////////////////////////////////////////////////////////////////\n//\n// Edit this file to squeeze more performance, and to customize supported features\n//\n///////////////////////////////////////////////////////////////////////////////\n\n///////////////////////////////////////////////////////////////////////////////\n// Under Linux, the much faster CLOCK_REALTIME_COARSE clock can be used.\n// This clock is less accurate - can be off by dozens of millis - depending on the kernel HZ.\n// Uncomment to use it instead of the regular clock.\n//\n// #define SPDLOG_CLOCK_COARSE\n///////////////////////////////////////////////////////////////////////////////\n\n///////////////////////////////////////////////////////////////////////////////\n// Uncomment if date/time logging is not needed and never appear in the log pattern.\n// This will prevent spdlog from querying the clock on each log call.\n//\n// WARNING: If the log pattern contains any date/time while this flag is on, the result is undefined.\n//          You must set new pattern(spdlog::set_pattern(..\") without any date/time in it\n//\n// #define SPDLOG_NO_DATETIME\n///////////////////////////////////////////////////////////////////////////////\n\n///////////////////////////////////////////////////////////////////////////////\n// Uncomment if thread id logging is not needed (i.e. no %t in the log pattern).\n// This will prevent spdlog from querying the thread id on each log call.\n//\n// WARNING: If the log pattern contains thread id (i.e, %t) while this flag is on, the result is undefined.\n//\n// #define SPDLOG_NO_THREAD_ID\n///////////////////////////////////////////////////////////////////////////////\n\n///////////////////////////////////////////////////////////////////////////////\n// Uncomment to prevent spdlog from caching thread ids in thread local storage.\n// By default spdlog saves thread ids in tls to gain a few micros for each call.\n//\n// WARNING: if your program forks, UNCOMMENT this flag to prevent undefined thread ids in the children logs.\n//\n// #define SPDLOG_DISABLE_TID_CACHING\n///////////////////////////////////////////////////////////////////////////////\n\n///////////////////////////////////////////////////////////////////////////////\n// Uncomment if logger name logging is not needed.\n// This will prevent spdlog from copying the logger name on each log call.\n//\n// #define SPDLOG_NO_NAME\n///////////////////////////////////////////////////////////////////////////////\n\n///////////////////////////////////////////////////////////////////////////////\n// Uncomment to enable the SPDLOG_DEBUG/SPDLOG_TRACE macros.\n//\n// #define SPDLOG_DEBUG_ON\n// #define SPDLOG_TRACE_ON\n///////////////////////////////////////////////////////////////////////////////\n\n///////////////////////////////////////////////////////////////////////////////\n// Uncomment to avoid locking in the registry operations (spdlog::get(), spdlog::drop() spdlog::register()).\n// Use only if your code never modifies concurrently the registry.\n// Note that upon creating a logger the registry is modified by spdlog..\n//\n// #define SPDLOG_NO_REGISTRY_MUTEX\n///////////////////////////////////////////////////////////////////////////////\n\n///////////////////////////////////////////////////////////////////////////////\n// Uncomment to avoid spdlog's usage of atomic log levels\n// Use only if your code never modifies a logger's log levels concurrently by different threads.\n//\n// #define SPDLOG_NO_ATOMIC_LEVELS\n///////////////////////////////////////////////////////////////////////////////\n\n///////////////////////////////////////////////////////////////////////////////\n// Uncomment to enable usage of wchar_t for file names on Windows.\n//\n// #define SPDLOG_WCHAR_FILENAMES\n///////////////////////////////////////////////////////////////////////////////\n\n///////////////////////////////////////////////////////////////////////////////\n// Uncomment to override default eol (\"\\n\" or \"\\r\\n\" under Linux/Windows)\n//\n// #define SPDLOG_EOL \";-)\\n\"\n///////////////////////////////////////////////////////////////////////////////\n\n///////////////////////////////////////////////////////////////////////////////\n// Uncomment to use your own copy of the fmt library instead of spdlog's copy.\n// In this case spdlog will try to include <fmt/format.h> so set your -I flag accordingly.\n//\n// #define SPDLOG_FMT_EXTERNAL\n///////////////////////////////////////////////////////////////////////////////\n\n///////////////////////////////////////////////////////////////////////////////\n// Uncomment to use printf-style messages in your logs instead of the usual\n// format-style used by default.\n//\n// #define SPDLOG_FMT_PRINTF\n///////////////////////////////////////////////////////////////////////////////\n\n///////////////////////////////////////////////////////////////////////////////\n// Uncomment to enable syslog (disabled by default)\n//\n// #define SPDLOG_ENABLE_SYSLOG\n///////////////////////////////////////////////////////////////////////////////\n\n///////////////////////////////////////////////////////////////////////////////\n// Uncomment to enable wchar_t support (convert to utf8)\n//\n// #define SPDLOG_WCHAR_TO_UTF8_SUPPORT\n///////////////////////////////////////////////////////////////////////////////\n\n///////////////////////////////////////////////////////////////////////////////\n// Uncomment to prevent child processes from inheriting log file descriptors\n//\n// #define SPDLOG_PREVENT_CHILD_FD\n///////////////////////////////////////////////////////////////////////////////\n\n///////////////////////////////////////////////////////////////////////////////\n// Uncomment if your compiler doesn't support the \"final\" keyword.\n// The final keyword allows more optimizations in release\n// mode with recent compilers. See GCC's documentation for -Wsuggest-final-types\n// for instance.\n//\n// #define SPDLOG_NO_FINAL\n///////////////////////////////////////////////////////////////////////////////\n\n///////////////////////////////////////////////////////////////////////////////\n// Uncomment to enable message counting feature.\n// Use the %i in the logger pattern to display log message sequence id.\n//\n// #define SPDLOG_ENABLE_MESSAGE_COUNTER\n///////////////////////////////////////////////////////////////////////////////\n\n///////////////////////////////////////////////////////////////////////////////\n// Uncomment to customize level names (e.g. \"MT TRACE\")\n//\n// #define SPDLOG_LEVEL_NAMES { \"MY TRACE\", \"MY DEBUG\", \"MY INFO\", \"MY WARNING\", \"MY ERROR\", \"MY CRITICAL\", \"OFF\" }\n///////////////////////////////////////////////////////////////////////////////\n"
  },
  {
    "path": "src/application.cpp",
    "content": "#include \"daqi/application.hpp\"\n\n#include <iostream>\n\nnamespace da4qi4\n{\n\nstatic char const* default_app_name = \"DAQI-APP\";\nstatic char const* abortive_app_name = \"ABORTIVE-APP\";\n\nnamespace\n{\nstd::string default_abortive_app_log_root = \"./\";\nstd::string abortive_app_log_root = default_abortive_app_log_root;\n}\n\nApplicationPtr Application::Abortive()\n{\n    ApplicationPtr app = Application::Default();\n\n    app->_root_log = abortive_app_log_root;\n    app->_name = abortive_app_name;\n\n#ifdef NDEBUG\n    app->_is_abortive = true;\n#endif\n    return app;\n}\n\nvoid ApplicationMgr::InitAbortiveAppLogRoot(std::string const& log_path)\n{\n    if (abortive_app_log_root == default_abortive_app_log_root\n        && log_path != default_abortive_app_log_root)\n    {\n        abortive_app_log_root = log_path;\n    }\n}\n\nstd::string const& ApplicationMgr::GetAbortiveAppLogRoot()\n{\n    return abortive_app_log_root;\n}\n\nApplicationMgr& AppMgr()\n{\n    static ApplicationMgr mgr;\n    return mgr;\n}\n\nvoid ApplicationMgr::CreateDefault(const std::string& app_name)\n{\n    auto app = Application::Default((!app_name.empty() ? app_name\n                                     : std::string(default_app_name)));\n\n    _map.insert(std::make_pair(app->GetUrlRoot(), app));\n}\n\nbool ApplicationMgr::MountApplication(ApplicationPtr app)\n{\n    if (_mounted)\n    {\n        return false;\n    }\n\n    assert(!app->GetName().empty());\n\n    if (!IsExists(app->GetName()))\n    {\n        _app_loggers.insert(std::make_pair(app->GetName(), app->GetLogger()));\n        _map.insert(std::make_pair(app->GetUrlRoot(), app));\n        return true;\n    }\n\n    return false;\n}\n\nvoid ApplicationMgr::Enable(std::string const& name)\n{\n    auto app = this->FindByName(name);\n\n    if (app && !app->IsEnable())\n    {\n        app->Enable();\n    }\n}\n\nvoid ApplicationMgr::Disable(std::string const& name)\n{\n    auto app = FindByName(name);\n\n    if (app && app->IsEnable())\n    {\n        app->Disable();\n    }\n}\n\nbool ApplicationMgr::IsExists(std::string const& name) const\n{\n    return FindByName(name) != nullptr;\n}\n\nbool ApplicationMgr::IsEnable(std::string const& name) const\n{\n    auto app = FindByName(name);\n    return app && app->IsEnable();\n}\n\nApplicationPtr ApplicationMgr::FindByURL(std::string const& url)\n{\n    auto l = _map.lower_bound(url);\n\n    if (l == _map.end())\n    {\n#ifdef NDEBUG\n        return _abortive_app;\n#else\n        return nullptr;\n#endif\n    }\n\n    if (Utilities::iStartsWith(url, l->first))\n    {\n        return l->second;\n    }\n\n    for (++l; l != _map.end(); ++l)\n    {\n        if (Utilities::iStartsWith(url, l->first))\n        {\n            return l->second;\n        }\n    }\n\n#ifdef NDEBUG\n    return _abortive_app;\n#else\n    return nullptr;\n#endif\n}\n\nApplicationPtr ApplicationMgr::FindByName(std::string const& name)\n{\n    for (auto& a : _map)\n    {\n        if (a.second->GetName() == name)\n        {\n            return a.second;\n        }\n    }\n\n#ifdef NDEBUG\n\n    if (name == abortive_app_name)\n    {\n        return _abortive_app;\n    }\n\n#endif\n\n    return nullptr;\n}\n\nApplicationPtr const ApplicationMgr::FindByName(std::string const& name) const\n{\n    for (auto const& a : _map)\n    {\n        if (a.second->GetName() == name)\n        {\n            return a.second;\n        }\n    }\n\n#ifdef NDEBUG\n\n    if (name == abortive_app_name)\n    {\n        return _abortive_app;\n    }\n\n#endif\n\n    return nullptr;\n}\n\nvoid ApplicationMgr::Mount()\n{\n    _mounted = true;\n\n    for (auto& a : _map)\n    {\n        a.second->Mount();\n    }\n}\n\nvoid ApplicationMgr::CheckTemplatesUpdate()\n{\n    for (auto& a : _map)\n    {\n        if (!a.second->GetTemplates().ReloadIfFindUpdate())\n        {\n            a.second->GetTemplates().ReloadIfFindNew();\n        }\n    }\n}\n\nbool UploadFileSaveOptions::IsNeedSave(std::string const& extension\n                                       , size_t filesize_kb) const\n{\n    return (strategy == always_save)\n            || ((strategy == size_greater_than) && (filesize_kb > size_base_kb))\n            || ((strategy == size_lesser_than) && (filesize_kb < size_base_kb))\n            || ((strategy == extension_is) && (extensions.find(extension) != extensions.cend()))\n            || ((strategy == extension_is_not) && (extensions.find(extension) == extensions.cend()));\n}\n\n\nApplication::Application()\n    : _name(default_app_name)\n    , _default_charset(\"utf-8\")\n    , _root_url(\"/\")\n{\n    default_init();\n}\n\nApplication::Application(std::string const& name)\n    : _name(name)\n    , _default_charset(\"utf-8\")\n    , _root_url(\"/\")\n    , _template_ext(get_daqi_HTML_template_ext())\n{\n    default_init();\n}\n\nApplication::Application(std::string const& name\n                         , std::string const& root_url\n                         , fs::path const& root_log\n                         , fs::path const& root_static\n                         , fs::path const& root_template\n                         , fs::path const& root_upload\n                         , fs::path const& root_temporary\n                         , std::string const& template_ext)\n    : _name(name)\n    , _root_url(root_url)\n    , _root_log(root_log)\n    , _root_static(root_static)\n    , _root_template(root_template)\n    , _root_upload(root_upload)\n    , _root_temporary(root_temporary)\n    , _template_ext(template_ext)\n    , _templates(root_template.native(), root_url, template_ext)\n\n{\n    this->InitPathes();\n}\n\nApplication::~Application()\n{\n}\n\nvoid Application::Disable()\n{\n    _disabled = true;\n}\n\nvoid Application::Enable()\n{\n    _disabled = false;\n}\n\nvoid Application::default_init()\n{\n    assert(!IsRuning());\n\n    default_init_pathes();\n    default_init_logger();\n    default_init_templates();\n}\n\nvoid Application::default_init_logger()\n{\n    if (_logger == nullptr)\n    {\n        _logger = log::Null();\n    }\n}\n\nvoid Application::default_init_pathes()\n{\n    _root_log = fs::current_path();\n    _root_template = fs::current_path();\n    _root_static = fs::current_path();\n\n    _root_upload = fs::temp_directory_path();\n    _root_temporary = fs::temp_directory_path();\n}\n\nvoid Application::default_init_templates()\n{\n    _templates.InitPathes(_root_template.native(), \"/\", get_daqi_HTML_template_ext());\n}\n\nbool Application::InitLogger(std::string const& log_root, log::Level level, size_t max_log_file_size_kb,\n                             size_t max_log_file_count)\n{\n    if (_root_log != log_root)\n    {\n        _root_log = log_root;\n    }\n\n    return InitLogger(level, max_log_file_size_kb, max_log_file_count);\n}\n\nbool Application::InitLogger(log::Level level, size_t max_log_file_size_kb, size_t max_log_file_count)\n{\n    assert(!IsRuning());\n    assert(log::IsNull(_logger));\n\n    if (!log::IsNull(_logger))\n    {\n        return false;\n    }\n\n    try\n    {\n        if (_root_log.empty())\n        {\n            _root_log = fs::current_path() / \"/\";\n        }\n\n        if (!_root_log.is_absolute())\n        {\n            _root_log = fs::absolute(_root_log);\n        }\n    }\n    catch (fs::filesystem_error const& e)\n    {\n        std::cerr << \"Init \" << _name << \" log path exception. \" << e.what() << std::endl;\n        return false;\n    }\n    catch (std::exception const& e)\n    {\n        std::cerr << \"Init \" << _name << \" log path exception. \" << e.what() << std::endl;\n        return false;\n    }\n    catch (...)\n    {\n        std::cerr << \"Init \" << _name << \" log path unknown exception.\" << std::endl;\n        return false;\n    }\n\n    _logger = log::CreateAppLogger(_name, _root_log.native()\n                                   , level, max_log_file_size_kb, max_log_file_count);\n\n    if (!_logger)\n    {\n        std::cerr << \"Create appliction\" << _name << \" logger fail.\" << std::endl;\n        return false;\n    }\n\n    return true;\n}\n\nbool Application::InitPathes()\n{\n    assert(!IsRuning());\n\n    std::stringstream ss;\n\n    try\n    {\n        if (_root_template.empty())\n        {\n            _root_template = fs::current_path();\n        }\n        else if (!_root_template.is_absolute())\n        {\n            _root_template = fs::absolute(_root_template);\n        }\n\n        if (_root_static.empty())\n        {\n            _root_static = fs::current_path();\n        }\n        else if (!_root_static.is_absolute())\n        {\n            _root_static = fs::absolute(_root_static);\n        }\n\n        if (_root_upload.empty())\n        {\n            _root_upload = fs::temp_directory_path();\n        }\n        else if (!_root_upload.is_absolute())\n        {\n            _root_upload = fs::absolute(_root_upload);\n        }\n\n        if (_root_temporary.empty())\n        {\n            _root_temporary = fs::current_path();\n        }\n        else if (!_root_temporary.is_absolute())\n        {\n            _root_temporary = fs::absolute(_root_temporary);\n        }\n\n        return true;\n    }\n    catch (fs::filesystem_error const& e)\n    {\n        ss << \"Init pathes filesystem-exception. \" << e.what();\n    }\n    catch (std::exception const& e)\n    {\n        ss << \"Init pathes exception. \" << e.what();\n    }\n    catch (...)\n    {\n        ss << \"Init pathes unknown exception.\";\n    }\n\n    if (log::IsNull(_logger))\n    {\n        std::cerr << ss.str() << std::endl;\n    }\n    else\n    {\n        _logger->error(ss.str());\n    }\n\n    return false;\n}\n\nvoid Application::UndesiredTemplates()\n{\n    _templates.Disable();\n}\n\nbool Application::InitTemplates(std::string const& template_ext)\n{\n    assert(!IsRuning());\n    assert(_logger != nullptr);\n\n#ifdef NDEBUG\n\n    if (IsAbortive())\n    {\n        return true;\n    }\n\n#endif\n\n    if (!template_ext.empty())\n    {\n        _template_ext = template_ext;\n    }\n\n    if (!_template_ext.empty())\n    {\n        _templates.InitPathes(_root_template.native(), _root_url, _template_ext);\n        return _templates.Preload(_logger);\n    }\n\n    return true;\n}\n\nbool Application::AddIntercepter(Intercepter::Handler intercepter)\n{\n    if (IsRuning())\n    {\n        _logger->warn(\"Add intercepter fail. application is running.\");\n        return false;\n    }\n\n    _intercepters.push_back(intercepter);\n    return true;\n}\n\nbool Application::AddHandler(HandlerMethod m, router_equals r, Handler h, std::string const& t)\n{\n    if (IsRuning())\n    {\n        _logger->warn(\"Add equals-router {} fail. application is running.\", r.s);\n        return false;\n    }\n\n    r.s = JoinUrlPath(_root_url, r.s);\n\n    std::string error;\n\n    if (!_equalRouter.Add(r, m, h, t, error))\n    {\n        _logger->error(\"Add equals-router {} fail. {}.\", r.s, error);\n        return false;\n    }\n\n    return true;\n}\n\nbool Application::AddHandler(HandlerMethod m, router_starts r, Handler h, std::string const& t)\n{\n    if (IsRuning())\n    {\n        _logger->warn(\"Add starts-router {} fail. application is running.\", r.s);\n        return false;\n    }\n\n    r.s = JoinUrlPath(_root_url, r.s);\n\n    std::string error;\n\n    if (!_startwithsRouter.Add(r, m, h, t, error))\n    {\n        _logger->error(\"Add starts-router {} fail. {}.\", r.s, t, error);\n        return false;\n    }\n\n    return true;\n}\n\nbool Application::AddHandler(HandlerMethod m, router_regex r, Handler h, std::string const& t)\n{\n    if (IsRuning())\n    {\n        _logger->warn(\"Add regex-router {} fail. application is running.\", r.s);\n        return false;\n    }\n\n    r.s = JoinUrlPath(_root_url, r.s);\n\n    std::string error;\n\n    if (!_regexRouter.Add(r, m, h, t, error))\n    {\n        _logger->error(\"Add regex-router {} fail. {}.\", r.s, error);\n        return false;\n    }\n\n    return true;\n}\n\nbool Application::AddHandler(HandlerMethods ms, router_equals r, Handler h, std::string const& t)\n{\n    if (IsRuning())\n    {\n        _logger->warn(\"Add euqals-router {} fail. application is running.\", r.s);\n        return false;\n    }\n\n    r.s = JoinUrlPath(_root_url, r.s);\n\n    std::string error;\n\n    if (!_equalRouter.Add(r, ms, h, t, error))\n    {\n        _logger->error(\"Add equals-router {} fail. {}.\", r.s, error);\n        return false;\n    }\n\n    return true;\n}\n\nbool Application::AddHandler(HandlerMethods ms, router_starts r, Handler h, std::string const& t)\n{\n    if (IsRuning())\n    {\n        _logger->warn(\"Add starts-router {} fail. application is running.\", r.s);\n        return false;\n    }\n\n    r.s = JoinUrlPath(_root_url, r.s);\n\n    std::string error;\n\n    if (!_startwithsRouter.Add(r, ms, h, t, error))\n    {\n        _logger->error(\"Add starts router {} fail. {}.\", r.s, error);\n        return false;\n    }\n\n    return true;\n}\n\nbool Application::AddHandler(HandlerMethods ms, router_regex r, Handler h, std::string const& t)\n{\n    if (IsRuning())\n    {\n        _logger->warn(\"Add regex-router {} fail. application is running.\", r.s);\n        return false;\n    }\n\n    r.s = JoinUrlPath(_root_url, r.s);\n\n    std::string error;\n\n    if (!_regexRouter.Add(r, ms, h, t, error))\n    {\n        _logger->error(\"Add regex-router {} fail. {}.\", r.s, error);\n        return false;\n    }\n\n    return true;\n}\n\nbool Application::AddEqualsRouter(HandlerMethod m, std::vector<std::string> const& urls, Handler h,\n                                  std::string const& t)\n{\n    for (auto a : urls)\n    {\n        if (!AddHandler(m, router_equals(a), h, t))\n        {\n            return false;\n        }\n    }\n\n    return true;\n}\n\nbool Application::AddStartsRouter(HandlerMethod m, std::vector<std::string> const& urls, Handler h,\n                                  std::string const& t)\n{\n    for (auto a : urls)\n    {\n        if (!AddHandler(m, router_starts(a), h, t))\n        {\n            return false;\n        }\n    }\n\n    return true;\n}\n\nbool Application::AddRegexRouter(HandlerMethod m, std::vector<std::string> const& urls, Handler h,\n                                 std::string const& t)\n{\n    for (auto a : urls)\n    {\n        if (!AddHandler(m, router_regex(a), h, t))\n        {\n            return false;\n        }\n    }\n\n    return true;\n}\n\nstd::vector<UniformItem> Application::GetEqualsRouterUniformItems() const\n{\n    return _equalRouter.Uniforms();\n}\n\nstd::vector<UniformItem> Application::GetStartsRouterUniformItems() const\n{\n    return _startwithsRouter.Uniforms();\n}\n\nstd::vector<UniformRegexItem> Application::GetRegexRouterUniformItems() const\n{\n    return _regexRouter.Uniforms();\n}\n\nHandler* Application::find_handler(Context const& ctx, bool& url_exists, bool& unsupport_method\n                                   , std::string const& retry_path)\n{\n    HandlerMethod m = from_http_method(ctx->Req().GetMethod());\n\n    if (m == HandlerMethod::UNSUPPORT)\n    {\n        unsupport_method = true;\n        ctx->ClearTemplateName();\n        return nullptr;\n    }\n\n    std::string const& url = (retry_path.empty() ? ctx->Req().GetUrl().path : retry_path);\n\n    RouterResult rr = _equalRouter.Search(url, m, url_exists);\n\n    if (!rr.error.empty())\n    {\n        _logger->warn(\"Match equals-router for {} exception. {}.\", url, rr.error);\n    }\n\n    if (rr.handler)\n    {\n        ctx->SetTemplateName(rr.template_name);\n        return rr.handler;\n    }\n\n    StartsRouterResult srr = _startwithsRouter.Search(url, m, url_exists);\n\n    if (!srr.error.empty())\n    {\n        _logger->warn(\"Match starts-router for {} exception. {}.\", url, srr.error);\n    }\n\n    if (srr.handler)\n    {\n        ctx->SetTemplateName(srr.template_name);\n        auto remain = url.size() - srr.key.size();\n        ctx->InitRequestPathParameter(url.substr(srr.key.size(), remain));\n\n        return srr.handler;\n    }\n\n    RegexRouterResult rrr = _regexRouter.Search(url, m, url_exists);\n\n    if (!rrr.error.empty())\n    {\n        _logger->warn(\"Match regex-router for {} exception. {}.\", url, rrr.error);\n    }\n\n    if (rrr.handler)\n    {\n        ctx->SetTemplateName(rrr.template_name);\n        ctx->InitRequestPathParameters(rrr.parameters, rrr.values);\n        return rrr.handler;\n    }\n\n    return nullptr;\n}\n\nvoid Application::Handle(Context ctx)\n{\n    do_handle(ctx);\n}\n\nvoid Application::do_handle(Context& ctx)\n{\n    bool url_exists = false;\n    bool unsupport_method = false;\n    bool retring = false;\n\n    Handler* h = find_handler(ctx, url_exists, unsupport_method);\n\n    while (!h || !*h)\n    {\n        if (url_exists || unsupport_method)\n        {\n            ctx->RenderNotImplemented().Pass();\n            return;\n        }\n\n        if (retring)\n        {\n            ctx->RenderWithoutData().Pass();\n            return;\n        }\n\n        retring = true;\n\n        if (Utilities::EndsWith(ctx->Req().GetUrl().path, \"/index\"))\n        {\n            const int len_of_str_index = 5; //len of \"index\"\n            std::size_t len = ctx->Req().GetUrl().path.length();\n            auto try_path = ctx->Req().GetUrl().path.substr(0, len - len_of_str_index);\n\n            h = find_handler(ctx, url_exists, unsupport_method, try_path);\n        }\n    }\n\n    try\n    {\n        (*h)(ctx);\n    }\n    catch (std::exception const& e)\n    {\n        _logger->error(\"Handler {} exception. {}\", ctx->Req().GetUrl().full, e.what());\n    }\n}\n\nbool Application::RegistWebSocket(std::string const& url, UrlFlag urlflag\n                                  , Websocket::EventHandlersFactory factory)\n{\n    if (IsRuning())\n    {\n        _logger->warn(\"Regist websocket-handlers-factory on {} fail. application is running.\", url);\n        return false;\n    }\n\n    auto fullpath = MakesureFullUrlPath(url, urlflag, _root_url);\n    _websocket_handlers_factory.insert(std::make_pair(fullpath, std::move(factory)));\n\n    return true;\n}\n\nbool Application::IsWebSocketRegistered(std::string const& url, UrlFlag urlflag) const\n{\n    auto fullpath = MakesureFullUrlPath(url, urlflag, _root_url);\n    return _websocket_handlers_factory.find(fullpath) != _websocket_handlers_factory.cend();\n}\n\nstd::unique_ptr<Websocket::EventsHandler> Application::CreateWebSocketHandler(std::string const& url, UrlFlag urlflag)\n{\n    auto fullpath = MakesureFullUrlPath(url, urlflag, _root_url);\n    auto it = _websocket_handlers_factory.find(fullpath);\n    return (it == _websocket_handlers_factory.end()) ? nullptr\n           : std::unique_ptr<Websocket::EventsHandler>(it->second());\n}\n\nvoid Application::AddWebSocketConnection(Websocket::Connection::Ptr connection)\n{\n    assert(connection != nullptr);\n    assert(!connection->GetID().empty());\n\n    auto full_url_path = connection->GetURLPath();\n    assert(!full_url_path.empty());\n\n    {\n        std::scoped_lock<std::mutex> lock(_m_4_websocket_connections);\n        auto it = _websocket_connections.find(full_url_path);\n\n        if (it != _websocket_connections.end())\n        {\n            it->second.Add(connection);\n        }\n        else\n        {\n            Websocket::Connections storage(connection);\n            _websocket_connections.emplace(std::move(full_url_path), std::move(storage));\n        }\n    }\n}\n\nbool Application::RemoveWebSocketConnection(std::string const& url, UrlFlag urlflag, std::string const& id)\n{\n    auto fullpath = MakesureFullUrlPath(url, urlflag, _root_url);\n\n    std::scoped_lock<std::mutex> lock(_m_4_websocket_connections);\n\n    auto it = _websocket_connections.find(fullpath);\n\n    if (it == _websocket_connections.end())\n    {\n        return false;\n    }\n\n    return it->second.Remove(id);\n}\n\nbool Application::RenameWebSocketConnectionID(std::string const& url, UrlFlag urlflag\n                                              , std::string const& old_id, std::string const& new_id)\n{\n    auto fullpath = MakesureFullUrlPath(url, urlflag, _root_url);\n\n    std::scoped_lock<std::mutex> lock(_m_4_websocket_connections);\n\n    auto it = _websocket_connections.find(fullpath);\n\n    if (it == _websocket_connections.end())\n    {\n        return false;\n    }\n\n    return it->second.RenameID(old_id, new_id);\n}\n\nWebsocket::Connection::Ptr Application::WebsocketConnection(std::string const& url, UrlFlag urlflag\n                                                            , std::string const& id)\n{\n    auto fullpath = MakesureFullUrlPath(url, urlflag, _root_url);\n\n    std::scoped_lock<std::mutex> lock(_m_4_websocket_connections);\n\n    auto it = _websocket_connections.find(fullpath);\n\n    if (it == _websocket_connections.end())\n    {\n        return nullptr;\n    }\n\n    return it->second.Get(id);\n}\n\nstd::list<Websocket::Connection::Ptr> Application::AllWebSocketConnections(std::string const& url, UrlFlag urlflag)\n{\n    auto fullpath = MakesureFullUrlPath(url, urlflag, _root_url);\n\n    std::scoped_lock<std::mutex> lock(_m_4_websocket_connections);\n\n    auto it = _websocket_connections.find(fullpath);\n\n    return (it == _websocket_connections.end()) ? std::list<Websocket::Connection::Ptr>() : it->second.All();\n}\n\nstd::list<std::string> Application::AllWebSocketConnectionsID(std::string const& url, UrlFlag urlflag)\n{\n    auto fullpath = MakesureFullUrlPath(url, urlflag, _root_url);\n\n    std::scoped_lock<std::mutex> lock(_m_4_websocket_connections);\n\n    auto it = _websocket_connections.find(fullpath);\n\n    return (it == _websocket_connections.end()) ? std::list<std::string>() : it->second.AllID();\n}\n\nlog::LoggerPtr ApplicationMgr::GetApplicationLogger(std::string const& application_name)\n{\n    auto it = _app_loggers.find(application_name);\n#ifndef NDEBUG\n    return (it == _app_loggers.end() ? log::Null() : it->second);\n#else\n\n    return (it != _app_loggers.end()) ? it->second :\n           ((application_name == abortive_app_name) ? _abortive_app->GetLogger() : log::Null());\n#endif\n}\n\nvoid AddDa4Qi4DefaultHandler(ApplicationPtr app)\n{\n    app->AddHandler(_GET_, \"/.da4qi4\", [app](Context ctx)\n    {\n        std::stringstream ss;\n        ss << \"<!DOCTYPE html>\\n<html>\\n<head>\\n<title>\"\n           << app->GetName() << \" on da4qi4</title>\\n\"\n           << \"<meta http-equiv=\\\"Content-Type\\\" content=\\\"text/html; charset=UTF-8\\\">\\n\"\n           << \"<meta name=\\\"description\\\" content=\\\"default da4qi4-web-routers page\\\" />\\n\"\n           << \"</head>\\n<body>\";\n\n        {\n            ss << \"<h1>\" << app->GetName() << \"</h1>\\n\";\n            ss << \"<ul>\\n\"\n               << \"<li>url-root : \" << app->GetUrlRoot() << \"</li>\\n\"\n#ifndef NDEBUG\n               << \"<li>template-root : \" << app->GetTemplateRoot().string() << \"</li>\\n\"\n               << \"<li>static-root : \" << app->GetStaticRootPath().string() << \"</li>\\n\"\n               << \"<li>upload-root : \" << app->GetUploadRoot().string() << \"</li>\\n\"\n#endif\n               << \"<li>max-upload-bytes : \" << app->GetUpoadMaxSizeLimitKB() << \"KB</li>\\n\"\n               << \"<li>default-charset : \" << app->GetDefaultCharset() << \"</li>\\n\";\n            ss << \"</ul>\\n\";\n        }\n\n        {\n            auto items = app->GetEqualsRouterUniformItems();\n            ss << \"<h2>Equals-Routers</h2>\\n<ol>\\n\";\n\n            for (auto const& i : items)\n            {\n                ss << \"<li>\" << i.method << \"&nbsp;&nbsp; \"\n                   << i.url_matcher << \"&nbsp;&nbsp;\"\n                   << i.template_name << \"</li>\\n\";\n            }\n\n            ss << \"</ol>\\n\";\n        }\n\n        {\n            auto items = app->GetStartsRouterUniformItems();\n            ss << \"<h2>Starts-Routers</h2>\\n<ol>\\n\";\n\n            for (auto const& i : items)\n            {\n                ss << \"<li>\" << i.method << \"&nbsp;&nbsp; \"\n                   << i.url_matcher << \"&nbsp;&nbsp;\"\n                   << i.template_name << \"</li>\\n\";\n            }\n\n            ss << \"</ol>\\n\";\n        }\n\n        {\n            auto items = app->GetRegexRouterUniformItems();\n            ss << \"<h2>Regex-Routers</h2>\\n<ol>\\n\";\n\n            for (auto const& i : items)\n            {\n                ss << \"<li>\" << i.method << \"&nbsp;&nbsp;\" << i.url_matcher\n                   << \"&nbsp;&nbsp;\" << i.regex_matcher\n                   << \"&nbsp;&nbsp;\" << i.template_name << \"</li>\\n\";\n            }\n\n            ss << \"</ol>\\n\";\n        }\n\n        ss << \"</body></html>\";\n\n        ctx->Res().ReplyOk(ss.str());\n        ctx->Pass();\n    });\n}\n\n} //namespace da4qi4\n"
  },
  {
    "path": "src/client/connection_client.cpp",
    "content": "#include \"daqi/client/connection_client.hpp\"\n\n#include \"daqi/utilities/asio_utilities.hpp\"\n\n#include <iostream>\n#include <condition_variable>\n\nnamespace da4qi4\n{\nnamespace Client\n{\n\nnamespace\n{\nstd::string port_to_service(unsigned short port)\n{\n    return std::to_string(port);\n}\n}\n\nConnection::Connection(IOC& ioc, std::string const& server)\n    : _with_ssl(false), _ioc(ioc), _resolver(ioc),\n      _socket_ptr(new net_detail::Socket(ioc)),\n      _parser(new http_parser), _server(server),\n      _method(\"GET\"), _uri(\"/\"), _http_version(\"1.1\")\n{\n    init();\n}\n\nConnection::Connection(IOC& ioc, std::string const& server, std::string const& service)\n    : _with_ssl(false), _ioc(ioc), _resolver(ioc),\n      _socket_ptr(new net_detail::Socket(ioc)),\n      _parser(new http_parser), _server(server), _service(service),\n      _method(\"GET\"), _uri(\"/\"), _http_version(\"1.1\")\n{\n    init();\n}\n\nConnection::Connection(IOC& ioc, std::string const& server, unsigned short port)\n    : _with_ssl(false), _ioc(ioc), _resolver(ioc),\n      _socket_ptr(new net_detail::Socket(ioc)),\n      _parser(new http_parser), _server(server), _service(port_to_service(port)),\n      _method(\"GET\"), _uri(\"/\"), _http_version(\"1.1\")\n{\n    init();\n}\n\nConnection::Connection(IOC& ioc, boost::asio::ssl::context& ctx, const std::string& server)\n    : _with_ssl(true), _ioc(ioc), _resolver(ioc),\n      _socket_ptr(new net_detail::SocketWithSSL(ioc, ctx)),\n      _parser(new http_parser), _server(server),\n      _method(\"GET\"), _uri(\"/\"), _http_version(\"1.1\")\n{\n    init();\n}\n\nConnection::Connection(IOC& ioc, boost::asio::ssl::context& ctx, std::string const& server\n                       , const std::string& service)\n    : _with_ssl(true), _ioc(ioc), _resolver(ioc),\n      _socket_ptr(new net_detail::SocketWithSSL(ioc, ctx)),\n      _parser(new http_parser), _server(server), _service(service),\n      _method(\"GET\"), _uri(\"/\"), _http_version(\"1.1\")\n{\n    init();\n}\n\nConnection::Connection(IOC& ioc, boost::asio::ssl::context& ctx, std::string const& server\n                       , unsigned short port)\n    : _with_ssl(true), _ioc(ioc), _resolver(ioc),\n      _socket_ptr(new net_detail::SocketWithSSL(ioc, ctx)),\n      _parser(new http_parser), _server(server), _service(port_to_service(port)),\n      _method(\"GET\"), _uri(\"/\"), _http_version(\"1.1\")\n{\n    init();\n}\n\nConnection::~Connection()\n{\n    do_close();\n\n    delete _parser;\n    delete _socket_ptr;\n}\n\nvoid Connection::init()\n{\n    this->init_parser_setting();\n    this->init_parser();\n\n    ResetHeaders();\n}\n\nvoid Connection::Reset()\n{\n    reset();\n}\n\nvoid Connection::Close()\n{\n    do_close();\n}\n\nvoid Connection::do_close()\n{\n    if (!_is_connected)\n    {\n        return;\n    }\n\n    errorcode ec;\n    _socket_ptr->close(ec);\n\n    if (ec)\n    {\n        _error = Error::on_close;\n        _error_msg = \"Socket close exception. \" + ec.message();\n    }\n\n    _is_connected = false;\n}\n\nvoid Connection::init_parser_setting()\n{\n    llhttp_settings_init(&_parser_setting);\n\n    _parser_setting.on_message_begin = &Connection::on_message_begin;\n    _parser_setting.on_message_complete = &Connection::on_message_complete;\n    _parser_setting.on_headers_complete = &Connection::on_headers_complete;\n    _parser_setting.on_header_field = &Connection::on_header_field;\n    _parser_setting.on_header_value = &Connection::on_header_value;\n    _parser_setting.on_status = &Connection::on_status;\n    _parser_setting.on_body = &Connection::on_body;\n}\n\nvoid Connection::init_parser()\n{\n    llhttp_init(_parser, HTTP_RESPONSE, &_parser_setting);\n    _parser->data = this;\n}\n\nConnection& Connection::SetMethod(std::string const& method, std::string const& uri)\n{\n    this->_method = method;\n    this->_uri = uri.empty() ? \"/\" : uri;\n    return *this;\n}\n\nConnection& Connection::SetHTTPVersion(std::string const& version)\n{\n    this->_http_version = version;\n    return *this;\n}\n\nConnection& Connection::ResetHeaders()\n{\n    _request_headers.clear();\n    std::string user_agent_with_version = the_daqi_name + std::string(\"/\") + the_daqi_version;\n    _request_headers.insert(std::make_pair(\"User-Agent\", user_agent_with_version));\n    return *this;\n}\n\nConnection& Connection::AddHeader(std::string const& name, std::string const& value)\n{\n    auto it = _request_headers.find(name);\n\n    if (it != _request_headers.end())\n    {\n        it->second = value;\n    }\n    else\n    {\n        _request_headers.insert(std::make_pair(name, value));\n    }\n\n    return *this;\n}\n\nConnection& Connection::SetBody(std::string body, BodySetAction action)\n{\n    if (action == BodySetAction::reset_content_length)\n    {\n        AddHeader(\"Content-Length\", std::to_string(body.length()));\n    }\n\n    this->_request_body = std::move(body);\n    return *this;\n}\n\nnamespace\n{\nstd::string const default_http_services [] = {\"http\", \"https\"};\n}\n\nerrorcode Connection::do_resolver()\n{\n    errorcode ec;\n\n    auto results = Utilities::from_host(_server\n                                        , (_service.empty()\n                                           ? default_http_services[_with_ssl ? 1 : 0] : _service)\n                                        , _resolver\n                                        , ec);\n\n    if (ec)\n    {\n        _error = Error::on_resolver;\n        _error_msg = \"Resolver host address exception.\";\n        return ec;\n    }\n\n\n#ifdef HAS_RESOLVER_RESULT\n\n    if (results.empty())\n    {\n        _error = Error::on_resolver;\n        _error_msg = \"Resolver host address got a empty results.\";\n    }\n    else\n    {\n        this->_server_endpoint = *results.cbegin();\n    }\n\n#else\n\n    if (results == Tcp::resolver::iterator())\n    {\n        _error = Error::on_resolver;\n        _error_msg = \"Resolver host address got a empty results.\";\n    }\n    else\n    {\n        this->_server_endpoint = *results;\n    }\n\n#endif\n\n    return ec;\n}\n\nvoid Connection::do_resolver(NotifyFunction notify)\n{\n    Utilities::from_host(_server\n                         , (_service.empty() ? default_http_services[_with_ssl ? 1 : 0] : _service)\n                         , _resolver\n                         , [this, notify](errorcode const & ec, ResolverResultT results)\n    {\n        if (ec)\n        {\n            _error = Error::on_resolver;\n            _error_msg = \"Resolver host address exception.\";\n            notify(ec);\n            return;\n        }\n\n#ifdef HAS_RESOLVER_RESULT\n\n        if (results.empty())\n        {\n            _error = Error::on_resolver;\n            _error_msg = \"Resolver host address got a empty results.\";\n            notify(ec);\n            return;\n        }\n\n        this->_server_endpoint = *results.cbegin();\n#else\n\n        if (results == Tcp::resolver::iterator())\n        {\n            _error = Error::on_resolver;\n            _error_msg = \"Resolver host address got a empty results.\";\n            notify(ec);\n            return;\n        }\n\n        this->_server_endpoint = *results;\n#endif\n        this->do_connect(notify);\n    });\n}\n\nerrorcode Connection::do_connect()\n{\n    if (_is_connected)\n    {\n        return errorcode();\n    }\n\n    auto ec = _socket_ptr->sync_connect(this->_server_endpoint);\n\n    if (!ec)\n    {\n        _is_connected = true;\n        reset();\n    }\n    else\n    {\n        _error = Error::on_connect;\n        _error_msg = \"Connect to server fail. \" + ec.message();\n    }\n\n    return ec;\n}\n\nvoid Connection::do_connect(NotifyFunction notify)\n{\n    assert(_server_endpoint.port() != 0);\n\n    if (_is_connected)\n    {\n        notify(errorcode());\n        return;\n    }\n\n    _socket_ptr->async_connect(this->_server_endpoint, [this, notify](errorcode const & ec)\n    {\n        if (ec)\n        {\n            _error = Error::on_connect;\n            _error_msg = \"Connect to server fail. \";\n        }\n        else\n        {\n            _is_connected = true;\n            reset();\n        }\n\n        notify(ec);\n    });\n}\n\nstd::string Connection::make_request_buffer()\n{\n    std::stringstream os;\n\n    os << _method << ' ' << _uri << \" HTTP/\" << _http_version << \"\\r\\n\"\n       << \"Host:\" << _server << \"\\r\\n\";\n\n    for (auto kv : _request_headers)\n    {\n        os << kv.first << \":\" << kv.second << \"\\r\\n\";\n    }\n\n    os << \"\\r\\n\";\n\n    if (!_request_body.empty())\n    {\n        os << _request_body;\n    }\n\n    return os.str();\n}\n\nerrorcode Connection::do_write(std::size_t& bytes_transferred)\n{\n    auto request_buffer = make_request_buffer();\n\n    auto ec = _socket_ptr->sync_write(request_buffer.c_str(), request_buffer.size()\n                                      , bytes_transferred);\n\n    if (ec)\n    {\n        _error = Error::on_write;\n        _error_msg = \"Write to server fail. \" + ec.message();\n    }\n\n    return ec;\n}\n\nvoid Connection::do_write(NotifyFunction notify)\n{\n    auto request_buffer = make_request_buffer();\n\n    _socket_ptr->async_write(request_buffer.data(), request_buffer.size(),\n                             [this, notify](errorcode const & ec, size_t /*bytes_transferred*/)\n    {\n        if (ec)\n        {\n            _error = Error::on_write;\n            _error_msg = \"Write to server fail.\";\n        }\n\n        notify(ec);\n    });\n}\n\nerrorcode Connection::do_read(std::size_t& bytes_transferred)\n{\n    bytes_transferred = 0;\n\n    do\n    {\n        std::size_t read = 0;\n        errorcode ec = _socket_ptr->sync_read_some(_read_buffer, read);\n        bytes_transferred += read;\n\n        if (ec)\n        {\n            _error = Error::on_read;\n            _error_msg = \"Read from server fail. \" + ec.message();\n            return ec;\n        }\n\n        auto parsed_errno = llhttp_execute(_parser, _read_buffer.data(), read);\n\n        if (parsed_errno != HPE_OK)\n        {\n            _error = Error::on_read;\n            _error_msg = \"Parse response content error. \" + std::to_string(parsed_errno) + \". \"\n                         + llhttp_errno_name(parsed_errno) + \".\";\n            return ec;\n        }\n\n    }\n    while (_read_complete != read_message_complete);\n\n    return errorcode();\n}\n\nvoid Connection::do_read(NotifyFunction notify)\n{\n    _socket_ptr->async_read_some(_read_buffer, [this, notify](errorcode const & ec,\n                                                              std::size_t bytes_transferred)\n    {\n        if (ec)\n        {\n            _error = Error::on_read;\n            _error_msg = \"Read from server fail.\";\n            notify(ec);\n            return;\n        }\n\n        auto parsed_errno = llhttp_execute(_parser, _read_buffer.data(), bytes_transferred);\n\n        if (parsed_errno != HPE_OK)\n        {\n            _error = Error::on_read;\n            _error_msg = \"Parse response content error. \" + std::to_string(parsed_errno) + \". \"\n                         + llhttp_errno_name(parsed_errno) + \".\";\n\n            notify(ec);\n            return;\n        }\n\n        if (_read_complete != read_message_complete)\n        {\n            do_read(notify);\n            return;\n        }\n\n        notify(ec);\n    });\n}\n\nvoid Connection::try_commit_reading_response_header()\n{\n    bool have_a_uncommit_header = _reading_header_part == Connection::header_value_part\n                                  && !_reading_header_field.empty();\n\n    if (have_a_uncommit_header)\n    {\n        this->_response_headers.insert(std::make_pair(\n                                                   std::move(_reading_header_field),\n                                                   std::move(_reading_header_value))\n                                      );\n        _reading_header_part = Connection::header_none_part;\n    }\n}\n\nint Connection::on_headers_complete(http_parser* parser)\n{\n    Connection* cnt = static_cast<Connection*>(parser->data);\n    cnt->try_commit_reading_response_header();\n\n    cnt->_read_complete = Connection::read_header_complete;\n\n    return 0;\n}\n\nint Connection::on_message_begin(http_parser* parser)\n{\n    Connection* cnt = static_cast<Connection*>(parser->data);\n    cnt->_read_complete = Connection::read_none_complete;\n    cnt->_response_body.clear();\n\n    return HPE_OK;\n}\n\nint Connection::on_message_complete(http_parser* parser)\n{\n    Connection* cnt = static_cast<Connection*>(parser->data);\n    cnt->_read_complete = Connection::read_message_complete;\n\n    return HPE_OK;\n}\n\nint Connection::on_header_field(http_parser* parser, char const* at, size_t length)\n{\n    Connection* cnt = static_cast<Connection*>(parser->data);\n    cnt->try_commit_reading_response_header();\n\n    if (length > 0)\n    {\n        cnt->_reading_header_part = Connection::header_field_part;\n        cnt->_reading_header_field.append(at, length);\n    }\n\n    return HPE_OK;\n}\n\nint Connection::on_header_value(http_parser* parser, char const* at, size_t length)\n{\n    Connection* cnt = static_cast<Connection*>(parser->data);\n\n    if (cnt->_reading_header_part == Connection::header_field_part\n        && !cnt->_reading_header_value.empty())\n    {\n        cnt->_reading_header_value.clear();\n    }\n\n    if (length > 0)\n    {\n        cnt->_reading_header_value.append(at, length);\n    }\n\n    if (cnt->_reading_header_part != Connection::header_value_part)\n    {\n        cnt->_reading_header_part = Connection::header_value_part;\n    }\n\n    return HPE_OK;\n}\n\nint Connection::on_status(http_parser* parser, char const* at, size_t length)\n{\n    Connection* cnt = static_cast<Connection*>(parser->data);\n    cnt->_status_buffer.append(at, length);\n    return HPE_OK;\n}\n\nint Connection::on_body(http_parser* parser, char const* at, size_t length)\n{\n    Connection* cnt = static_cast<Connection*>(parser->data);\n\n    cnt->_response_body.append(at, length);\n\n    return HPE_OK;\n}\n\nvoid Connection::reset()\n{\n    _error  = Error::on_none;\n    _error_msg.clear();\n\n    _status_buffer.clear();\n    _url_buffer.clear();\n    _response_headers.clear();\n    _response_body.clear();\n\n    _reading_header_part = header_none_part;\n    _reading_header_field.clear();\n    _reading_header_value.clear();\n    _read_complete = read_none_complete;\n}\n\nvoid Connection::Connect(NotifyFunction notify)\n{\n    if (this->_server_endpoint.port() != 0)\n    {\n        this->do_connect(notify);\n        return;\n    }\n\n    this->do_resolver([this, notify](errorcode const & ec)\n    {\n        if (ec)\n        {\n            notify(ec);\n            return;\n        }\n\n        this->do_connect(notify);\n    });\n}\n\nbool Connection::ConnectSync()\n{\n    if (!this->_server_endpoint.port())\n    {\n        auto ec = this->do_resolver();\n\n        if (ec || HasError())\n        {\n            return false;\n        }\n    }\n\n    auto ec = this->do_connect();\n    return (!ec && !HasError());\n}\n\nvoid Connection::Write(NotifyFunction notify)\n{\n    do_write(notify);\n}\n\nbool Connection::WriteSync(std::size_t& bytes_transferred)\n{\n    auto ec = do_write(bytes_transferred);\n    return (!ec && !this->HasError());\n}\n\nvoid Connection::Read(NotifyFunction notify)\n{\n    do_read(notify);\n}\n\nbool Connection::ReadSync(std::size_t& bytes_transferred)\n{\n    auto ec = do_read(bytes_transferred);\n    return (!ec && !this->HasError());\n}\n\nvoid Connection::Request(NotifyFunction notify, ActionAfterRequest action)\n{\n    this->Connect([this, notify, action](errorcode const & ec)\n    {\n        if (ec)\n        {\n            notify(ec);\n            return;\n        }\n\n        do_write([this, notify, action](errorcode const & ec)\n        {\n            if (ec)\n            {\n                notify(ec);\n                return;\n            }\n\n            do_read([this, notify, action](errorcode const & ec)\n            {\n                notify(ec);\n\n                if (action == ActionAfterRequest::close_connection)\n                {\n                    this->do_close();\n                }\n            });\n        });\n    });\n}\n\nbool Connection::RequestSync(std::size_t& bytes_wrote, std::size_t& bytes_read\n                             , ActionAfterRequest action)\n{\n    bytes_wrote = 0;\n    bytes_read = 0;\n\n    if (!this->_is_connected)\n    {\n        if (!this->ConnectSync())\n        {\n            return false;\n        }\n    }\n\n    auto success = (this->WriteSync(bytes_wrote) && this->ReadSync(bytes_read));\n\n    if (action == ActionAfterRequest::close_connection)\n    {\n        this->do_close();\n    }\n\n    return success;\n}\n\n} // namespace Client\n} // namespace da4qi4\n"
  },
  {
    "path": "src/connection.cpp",
    "content": "#include \"daqi/connection.hpp\"\n\n#include <ctime>\n#include <ostream>\n\n#include \"daqi/utilities/string_utilities.hpp\"\n\n#include \"daqi/def/log_def.hpp\"\n#include \"daqi/def/boost_def.hpp\"\n#include \"daqi/def/asio_def.hpp\"\n#include \"daqi/application.hpp\"\n\n#include \"daqi/websocket/connection_websocket.hpp\"\n#include \"daqi/websocket/context_websocket.hpp\"\n\nnamespace da4qi4\n{\n\nConnection::Connection(IOC& ioc, size_t ioc_index)\n    : _with_ssl(false), _socket_ptr(new net_detail::Socket(ioc))\n    , _ioc_index(ioc_index)\n    , _parser(new http_parser)\n    , _mp_parser(nullptr, &::multipart_parser_free)\n{\n    this->init_parser_setting();\n    this->init_parser();\n}\n\nConnection::Connection(IOC& ioc, size_t ioc_index, boost::asio::ssl::context& ssl_ctx)\n    : _with_ssl(true), _socket_ptr(new net_detail::SocketWithSSL(ioc, ssl_ctx))\n    , _ioc_index(ioc_index)\n    , _parser(new http_parser)\n    , _mp_parser(nullptr, &::multipart_parser_free)\n{\n    this->init_parser_setting();\n    this->init_parser();\n}\n\nApplicationPtr Connection::GetApplication()\n{\n    return _app;\n}\n\nvoid Connection::init_parser()\n{\n    llhttp_init(_parser.get(), HTTP_REQUEST, &_parser_setting);\n    _parser->data = this;\n}\n\nvoid Connection::init_parser_setting()\n{\n    llhttp_settings_init(&_parser_setting);\n\n    _parser_setting.on_message_begin = &Connection::on_message_begin;\n    _parser_setting.on_message_complete = &Connection::on_message_complete;\n    _parser_setting.on_headers_complete = &Connection::on_headers_complete;\n    _parser_setting.on_header_field = &Connection::on_header_field;\n    _parser_setting.on_header_value = &Connection::on_header_value;\n    _parser_setting.on_url = &Connection::on_url;\n    _parser_setting.on_body = &Connection::on_body;\n}\n\nvoid Connection::Start()\n{\n    if (!_with_ssl)\n    {\n        StartRead();\n        return;\n    }\n\n    this->do_handshake();\n}\n\nvoid Connection::StartRead()\n{\n    this->do_read();\n}\n\nvoid Connection::Stop()\n{\n    this->do_close();\n}\n\nvoid Connection::StartWrite()\n{\n    if (!_response.IsChunked())\n    {\n        this->do_write();\n    }\n    else\n    {\n        this->do_write_header_for_chunked();\n    }\n}\n\nvoid Connection::update_request_after_header_parsed()\n{\n    if (!_url_buffer.empty())\n    {\n        _request.ParseUrl(std::move(_url_buffer));\n    }\n\n    _request.SetFlags(_parser->flags);\n\n    if (_parser->flags &  F_CONTENT_LENGTH)\n    {\n        _request.SetContentLength(_parser->content_length);\n    }\n\n    _request.MarkKeepAlive(llhttp_should_keep_alive(_parser.get()));\n    _request.MarkUpgrade(_parser->upgrade);\n    _request.SetMethod(_parser->method);\n    _request.SetVersion(_parser->http_major, _parser->http_minor);\n    _response.SetVersion(_parser->http_major, _parser->http_minor);\n    try_commit_reading_request_header();\n    _request.TransferHeadersToCookies();\n    _request.ParseContentType();\n}\n\nvoid Connection::update_request_url_after_app_resolve()\n{\n    assert(_app != nullptr);\n    _request.ApplyApplication(_app->GetUrlRoot());\n}\n\nvoid Connection::try_commit_reading_request_header()\n{\n    bool have_a_uncommit_header = _reading_header_part == Connection::header_value_part\n                                  && !_reading_header_field.empty();\n\n    if (have_a_uncommit_header)\n    {\n        _request.AppendHeader(std::move(_reading_header_field), std::move(_reading_header_value));\n        _reading_header_part = Connection::header_none_part;\n    }\n}\n\nbool is_100_continue(Request& req)\n{\n    auto value = req.TryGetHeader(\"Expect\");\n    return (value && Utilities::iEquals(*value, \"100-continue\"));\n}\n\nvoid Connection::process_100_continue_request()\n{\n    assert(is_100_continue(_request));\n    _response.ReplyContinue();\n    this->StartWrite();\n}\n\nvoid Connection::process_app_no_found()\n{\n    _response.ReplyNofound();\n    this->StartWrite();\n}\n\nvoid Connection::process_too_large_size_upload()\n{\n    _response.ReplyPayloadTooLarge();\n    this->StartWrite();\n}\n\nvoid Connection::try_init_multipart_parser()\n{\n    assert(_request.IsMultiPart());\n\n    if (!_request.GetMultiPartBoundary().empty()) //boundary is unset on some bad request.\n    {\n        init_multipart_parser(_request.GetMultiPartBoundary());\n    }\n}\n\nbool Connection::try_route_application()\n{\n    if (!_request.GetUrl().schema.empty() || !_request.GetUrl().host.empty())\n    {\n        return false;\n    }\n\n    _app = AppMgr().FindByURL(_request.GetUrl().path);\n    return _app != nullptr;\n}\n\nint Connection::on_headers_complete(http_parser* parser)\n{\n    Connection* cnt = static_cast<Connection*>(parser->data);\n\n    cnt->update_request_after_header_parsed();  //_url parsed!\n\n    cnt->_read_complete = Connection::read_header_complete;\n\n    if (!cnt->try_route_application())\n    {\n        cnt->process_app_no_found();\n        return -1;\n    }\n\n    cnt->update_request_url_after_app_resolve();\n\n    if ((cnt->_request.GetContentLength() / 1024) > cnt->_app->GetUpoadMaxSizeLimitKB())\n    {\n        log::Server()->debug(\"Host {} : {} > {} KB. {}.\"\n                             , cnt->GetRequest().GetHost()\n                             , cnt->_request.GetContentLength()\n                             , cnt->_app->GetUpoadMaxSizeLimitKB()\n                             , cnt->_app->GetName());\n        cnt->process_too_large_size_upload();\n        return -1;\n    }\n\n    if (is_100_continue(cnt->_request))\n    {\n        cnt->process_100_continue_request(); //async write\n    }\n    else if (cnt->_request.IsMultiPart())\n    {\n        cnt->try_init_multipart_parser();\n    }\n\n    return HPE_OK;\n}\n\nint Connection::on_message_begin(http_parser* parser)\n{\n    Connection* cnt = static_cast<Connection*>(parser->data);\n    cnt->_read_complete = Connection::read_none_complete;\n    cnt->_body_buffer.clear();\n\n    return HPE_OK;\n}\n\nint Connection::on_message_complete(http_parser* parser)\n{\n    Connection* cnt = static_cast<Connection*>(parser->data);\n    cnt->_request.SetBody(std::move(cnt->_body_buffer));\n    cnt->_read_complete = Connection::read_message_complete;\n\n    return HPE_OK;\n}\n\nint Connection::on_header_field(http_parser* parser, char const* at, size_t length)\n{\n    Connection* cnt = static_cast<Connection*>(parser->data);\n    cnt->try_commit_reading_request_header();\n\n    if (length > 0)\n    {\n        cnt->_reading_header_part = Connection::header_field_part;\n        cnt->_reading_header_field.append(at, length);\n    }\n\n    return HPE_OK;\n}\n\nint Connection::on_header_value(http_parser* parser, char const* at, size_t length)\n{\n    Connection* cnt = static_cast<Connection*>(parser->data);\n\n    if (cnt->_reading_header_part == Connection::header_field_part\n        && !cnt->_reading_header_value.empty())\n    {\n        cnt->_reading_header_value.clear();\n    }\n\n    if (length > 0)\n    {\n        cnt->_reading_header_value.append(at, length);\n    }\n\n    if (cnt->_reading_header_part != Connection::header_value_part)\n    {\n        cnt->_reading_header_part = Connection::header_value_part;\n    }\n\n    return HPE_OK;\n}\n\n\nint Connection::on_url(http_parser* parser, char const* at, size_t length)\n{\n    Connection* cnt = static_cast<Connection*>(parser->data);\n    cnt->_url_buffer.append(at, length);\n\n    return HPE_OK;\n}\n\nvoid Connection::try_fix_multipart_bad_request_without_boundary()\n{\n    assert(!_mp_parser);\n\n    if (_body_buffer.find(\"--\") == 0)\n    {\n        constexpr int const length_of_boundary_start_flag = 2;\n        std::string::size_type endln_pos = _body_buffer.find(\"\\r\\n\", length_of_boundary_start_flag);\n\n        if (endln_pos != std::string::npos)\n        {\n            std::string boundary = _body_buffer.substr(length_of_boundary_start_flag\n                                                       , endln_pos - length_of_boundary_start_flag);\n            std::string::size_type len = boundary.size();\n\n            if (len > 2 && boundary[len - 2] == '-' && boundary[len - 1] == '-')\n            {\n                len -= 2;\n            }\n\n            _request.SetMultiPartBoundary(boundary.c_str(), len);\n            init_multipart_parser(_request.GetMultiPartBoundary());\n        }\n    }\n}\n\nConnection::MultpartParseStatus Connection::do_multipart_parse()\n{\n    assert(_request.IsMultiPart());\n\n    if (!_mp_parser)\n    {\n        try_fix_multipart_bad_request_without_boundary();\n    }\n\n    if (!_mp_parser)\n    {\n        return mp_cannot_init;\n    }\n\n    size_t parsed_bytes = multipart_parser_execute(_mp_parser.get(), _body_buffer.c_str(), _body_buffer.length());\n\n    if (parsed_bytes != _body_buffer.length())\n    {\n        return mp_parse_fail;\n    }\n\n    _body_buffer.clear(); //body -> multi parts\n    return mp_parsing;\n}\n\nint Connection::on_body(http_parser* parser, char const* at, size_t length)\n{\n    Connection* cnt = static_cast<Connection*>(parser->data);\n\n    size_t upload_max_size_limit_kb = (cnt->_app) ? cnt->_app->GetUpoadMaxSizeLimitKB() : 15 * 1024;\n\n    size_t total_byte_kb = (cnt->_body_buffer.size() + length) / 1024;\n\n    if (total_byte_kb > upload_max_size_limit_kb)\n    {\n        cnt->process_too_large_size_upload();\n        return -1;\n    }\n\n    cnt->_body_buffer.append(at, length);\n\n    if (cnt->_request.IsMultiPart())\n    {\n        MultpartParseStatus status = cnt->do_multipart_parse();\n\n        switch (status)\n        {\n            case mp_cannot_init:\n            case mp_parsing:\n                break;\n\n            case   mp_parse_fail:\n                log::Server()->error(\"Parse multi-part data fail.\");\n                return -1;\n        }\n    }\n\n    return HPE_OK;\n}\n\nint Connection::on_multipart_header_field(multipart_parser* parser, char const* at, size_t length)\n{\n    Connection* cnt = static_cast<Connection*>(multipart_parser_get_data(parser));\n    cnt->_multipart_parse_part = mp_parse_header_field;\n\n    if (cnt->_reading_header_part == header_value_part && !cnt->_reading_header_field.empty())\n    {\n        cnt->_reading_part.AppendHeader(std::move(cnt->_reading_header_field)\n                                        , std::move(cnt->_reading_header_value));\n        cnt->_reading_header_part = header_field_part;\n    }\n\n    cnt->_reading_header_field.append(at, length);\n\n    return 0;\n}\n\nint Connection::on_multipart_header_value(multipart_parser* parser, char const* at, size_t length)\n{\n    Connection* cnt = static_cast<Connection*>(multipart_parser_get_data(parser));\n    cnt->_multipart_parse_part = mp_parse_header_value;\n\n    if (cnt->_reading_header_part == Connection::header_field_part\n        && !cnt->_reading_header_value.empty())\n    {\n        cnt->_reading_header_value.clear();\n    }\n\n    if (length > 0)\n    {\n        cnt->_reading_header_value.append(at, length);\n    }\n\n    if (cnt->_reading_header_part != Connection::header_value_part)\n    {\n        cnt->_reading_header_part = Connection::header_value_part;\n    }\n\n    return 0;\n}\n\nint Connection::on_multipart_headers_complete(multipart_parser* parser)\n{\n    Connection* cnt = static_cast<Connection*>(multipart_parser_get_data(parser));\n    cnt->_multipart_parse_part = mp_parse_headers_complete;\n\n    if (cnt->_reading_header_part == header_value_part && !cnt->_reading_header_field.empty())\n    {\n        cnt->_reading_part.AppendHeader(std::move(cnt->_reading_header_field)\n                                        , std::move(cnt->_reading_header_value));\n        cnt->_reading_header_part = header_none_part;\n    }\n\n    return 0;\n}\n\nint Connection::on_multipart_data_begin(multipart_parser* parser)\n{\n    Connection* cnt = static_cast<Connection*>(multipart_parser_get_data(parser));\n    cnt->_multipart_parse_part = mp_parse_data_begin;\n\n    cnt->_reading_header_part = header_none_part;\n    cnt->_reading_header_field.clear();\n    cnt->_reading_header_value.clear();\n    cnt->_reading_part_buffer.clear();\n\n    return 0;\n}\n\nint Connection::on_multipart_data(multipart_parser* parser, char const* at, size_t length)\n{\n    Connection* cnt = static_cast<Connection*>(multipart_parser_get_data(parser));\n    cnt->_multipart_parse_part = mp_parse_data;\n    cnt->_reading_part_buffer.append(at, length);\n\n    return 0;\n}\n\nint Connection::on_multipart_data_end(multipart_parser* parser)\n{\n    Connection* cnt = static_cast<Connection*>(multipart_parser_get_data(parser));\n    cnt->_multipart_parse_part = mp_parse_data_end;\n\n    cnt->_reading_part.SetData(std::move(cnt->_reading_part_buffer));\n    cnt->_request.AddMultiPart(std::move(cnt->_reading_part));\n\n    return 0;\n}\n\nint Connection::on_multipart_body_end(multipart_parser* parser)\n{\n    Connection* cnt = static_cast<Connection*>(multipart_parser_get_data(parser));\n    cnt->_multipart_parse_part = mp_parse_body_end;\n\n    return 0;\n}\n\nvoid Connection::init_multipart_parser(std::string const& boundary)\n{\n    if (!_mp_parser_setting || !_mp_parser)\n    {\n        if (!_mp_parser_setting)\n        {\n            _mp_parser_setting.reset(new multipart_parser_settings);\n\n            _mp_parser_setting->on_part_data_begin = &Connection::on_multipart_data_begin;\n            _mp_parser_setting->on_part_data = &Connection::on_multipart_data;\n            _mp_parser_setting->on_part_data_end = &Connection::on_multipart_data_end;\n            _mp_parser_setting->on_header_field = &Connection::on_multipart_header_field;\n            _mp_parser_setting->on_header_value = &Connection::on_multipart_header_value;\n            _mp_parser_setting->on_headers_complete = &Connection::on_multipart_headers_complete;\n            _mp_parser_setting->on_body_end = &Connection::on_multipart_body_end;\n        }\n\n        if (_mp_parser)\n        {\n            this->free_multipart_parser(will_free_mp_parser);\n        }\n\n        std::string boundary_with_prefix(\"--\" + boundary);\n        _mp_parser.reset(::multipart_parser_init(boundary_with_prefix.c_str(), _mp_parser_setting.get()));\n        multipart_parser_set_data(_mp_parser.get(), this);\n    }\n}\n\nvoid Connection::free_multipart_parser(mp_free_flag flag)\n{\n    if (flag & will_free_mp_setting) //reuse if created\n    {\n        _mp_parser_setting.reset();\n    }\n\n    if (_mp_parser && (flag & will_free_mp_parser))\n    {\n        _mp_parser.reset(); //will call ::multipart_parser_free()\n    }\n}\n\nvoid Connection::do_close()\n{\n    errorcode ec;\n    _socket_ptr->close(ec);\n\n    if (ec)\n    {\n        log::Server()->warn(\"Socket close exception. {}\", ec.message());\n    }\n}\n\nvoid Connection::do_handshake()\n{\n    assert(this->_with_ssl);\n\n    auto socket_withssl = dynamic_cast<net_detail::SocketWithSSL*>(_socket_ptr.get());\n    assert(socket_withssl != nullptr);\n\n    auto& stream = socket_withssl->get_stream();\n\n    auto self(this->shared_from_this());\n\n    stream.async_handshake(boost::asio::ssl::stream_base::server\n                           , [self](errorcode const & ec)\n    {\n        if (ec)\n        {\n            log::Server()->error(\"Socket handshake on SSL fail. {}\", ec.message());\n            return;\n        }\n\n        self->StartRead();\n    });\n}\n\nvoid Connection::do_read()\n{\n    auto self(shared_from_this());\n\n    _socket_ptr->async_read_some(_buffer, [self, this](errorcode ec\n                                                       , std::size_t bytes_transferred)\n    {\n        if (ec)\n        {\n            if (ec != boost::asio::error::eof)\n            {\n                log::Server()->error(\"Client connection closed not graceful. {}\", ec.message());\n            }\n\n            return;\n        }\n\n        auto parsed_errno = llhttp_execute(_parser.get(), _buffer.data(), bytes_transferred);\n\n        if (parsed_errno != HPE_OK && parsed_errno != HPE_PAUSED_UPGRADE)\n        {\n            return;\n        }\n\n        if (_read_complete != read_message_complete)\n        {\n            do_read();\n            return;\n        }\n\n        free_multipart_parser(will_free_mp_parser);\n\n        assert((_app != nullptr) && \"MUST HAVE A APPLICATION AFTER REQUEST READ MESSAGE COMPLETED.\");\n\n        if (_parser->upgrade)\n        {\n            do_upgrade();\n            return;\n        }\n\n        if (_request.IsFormUrlEncoded())\n        {\n            _request.ParseFormUrlEncodedData();\n        }\n        else if (_request.IsFormData())\n        {\n            auto const& options = _app->GetUploadFileSaveOptions();\n            std::string dir = _app->GetUploadRoot().native();\n            _request.TransferMultiPartsToFormData(options, dir);\n        }\n\n        _response.SetCharset(_app->GetDefaultCharset());\n        ContextIMP::Make(shared_from_this())->Start(); //cnt -> app -> ctx\n    });\n}\n\nvoid Connection::do_upgrade()\n{\n    assert(_request.IsUpgrade());\n\n    auto ws_upgrade_value = _request.GetHeader(\"Upgrade\");\n\n    if (ws_upgrade_value.empty() || !Utilities::iEquals(ws_upgrade_value, \"websocket\"))\n    {\n        log::Server()->warn(\"Bad websocket upgrade header value {}. {}. connection will close.\"\n                            , ws_upgrade_value, _request.GetUrl().full);\n        return;\n    }\n\n    auto ws_key_value = _request.GetHeader(\"Sec-WebSocket-Key\");\n\n    if (ws_key_value.empty())\n    {\n        log::Server()->warn(\"No found websocket Sec-WebSocket-Key. {}. connection will close.\"\n                            , _request.GetUrl().full);\n        return;\n    }\n\n    auto ws_evts_handler = _app->CreateWebSocketHandler(_request.GetUrl().full, UrlFlag::url_full_path);\n\n    if (!ws_evts_handler)\n    {\n        log::Server()->warn(\"No found websocket event handler. {}. connection will close.\"\n                            , _request.GetUrl().full);\n        return;\n    }\n\n    auto ws_connection = Websocket::Connection::Create(_ioc_index\n                                                       , _socket_ptr.release()\n                                                       , std::move(this->_request.GetUrl())\n                                                       , std::move(this->_request.GetHeader())\n                                                       , std::move(this->_request.GetCookies())\n                                                       , ws_evts_handler.release());\n\n    auto ctx = Websocket::ContextIMP::Create(ws_connection, _app);\n\n    if (!ws_connection->GetEventHandler()->OnOpen(ctx))\n    {\n        return;\n    }\n\n    if (ws_connection->GetID().empty())\n    {\n        ws_connection->SetID(Utilities::GetUUID(_app->GetName()));\n    }\n\n    _app->AddWebSocketConnection(ws_connection);\n    ws_connection->Start(ctx, ws_key_value);\n\n    return;\n}\n\nvoid Connection::prepare_response_headers_about_connection()\n{\n    auto v = _request.GetVersion();\n    bool keepalive = _request.IsKeepAlive();\n\n    if (v.first < 1 || (v.first == 1 && v.second == 0))\n    {\n        _response.SetVersion(1, 0);\n\n        if (keepalive)\n        {\n            _response.MarkKeepAlive();\n        }\n    }\n    else\n    {\n        _response.SetVersion(1, 1);\n\n        if (!keepalive)\n        {\n            _response.MarkClose();\n        }\n    }\n}\n\nvoid Connection::do_write()\n{\n    prepare_response_headers_about_connection();\n\n    std::ostream os(&_write_buffer);\n    os << _response;\n\n    ConnectionPtr self = shared_from_this();\n\n    _socket_ptr->async_write(_write_buffer, [self, this](errorcode const & ec, size_t bytes_transferred)\n    {\n        if (ec)\n        {\n            return;\n        }\n\n        _write_buffer.consume(bytes_transferred);\n\n        if (_request.IsKeepAlive() && _response.IsKeepAlive())\n        {\n            this->reset();\n            this->do_read();\n        }\n    });\n}\n\nvoid Connection::prepare_response_headers_for_chunked_write()\n{\n    if (!_response.IsChunked())\n    {\n        _response.MarkChunked();\n    }\n\n    auto v = _response.GetVersion();\n\n    if (v.first < 1 || (v.first == 1 && v.second == 0))\n    {\n        _response.SetVersion(1, 1);\n    }\n\n    if (!_response.IsClose())\n    {\n        _response.MarkKeepAlive();\n    }\n}\n\nvoid Connection::do_write_header_for_chunked()\n{\n    prepare_response_headers_for_chunked_write();\n\n    std::ostream os(&_write_buffer);\n    os << _response;\n\n    ConnectionPtr self = shared_from_this();\n    _socket_ptr->async_write(_write_buffer\n                             , [self, this](errorcode const & ec, size_t bytes_transferred)\n    {\n        if (ec)\n        {\n            return;\n        }\n\n        _write_buffer.consume(bytes_transferred);\n        do_write_next_chunked_body();\n    });\n}\n\nvoid Connection::do_write_next_chunked_body(std::clock_t start_wait_clock)\n{\n    bool is_last = false;\n    _current_chunked_body_buffer = _response.PopChunkedBody(is_last);\n\n    if (is_last)\n    {\n        return;\n    }\n\n    ConnectionPtr self = shared_from_this();\n\n    if (_current_chunked_body_buffer.empty())\n    {\n        std::clock_t now = std::clock();\n\n        if (start_wait_clock > 0 && (now - start_wait_clock) / CLOCKS_PER_SEC > 5)\n        {\n            log::Server()->error(\"Wait next chunked response data timeout.\");\n            return;\n        }\n\n        if (start_wait_clock == 0)\n        {\n            start_wait_clock = now;\n        }\n\n        _socket_ptr->get_ioc().post(std::bind(&Connection::do_write_next_chunked_body\n                                              , self, start_wait_clock));\n    }\n    else\n    {\n        _socket_ptr->async_write(_current_chunked_body_buffer\n                                 , [self](errorcode const & ec, size_t bytes_transferred)\n        {\n            self->do_write_chunked_body_finished(ec, bytes_transferred);\n        });\n    }\n}\n\nvoid Connection::do_write_chunked_body_finished(errorcode const& ec, size_t bytes_transferred)\n{\n    if (ec)\n    {\n        log::Server()->warn(\"Write chunked body fail. body size {}, transferred {}. {}\"\n                            , _current_chunked_body_buffer.size(), bytes_transferred, ec.message());\n        return;\n    }\n\n    do_write_next_chunked_body();\n}\n\nvoid Connection::reset()\n{\n    _url_buffer.clear();\n    _body_buffer.clear();\n    _reading_header_part = header_none_part;\n    _reading_header_field.clear();\n    _reading_header_value.clear();\n    _read_complete = read_none_complete;\n    _reading_part.Clear();\n    _reading_part_buffer.clear();\n    _multipart_parse_part = mp_parse_none;\n    _request.Reset();\n    _response.Reset();\n    _app.reset();\n}\n\n} //namespace da4qi4\n"
  },
  {
    "path": "src/context.cpp",
    "content": "#include \"daqi/context.hpp\"\n\n#include <iterator>\n\n#include \"daqi/def/log_def.hpp\"\n#include \"daqi/connection.hpp\"\n#include \"daqi/application.hpp\"\n\n\nnamespace da4qi4\n{\n\nstd::string ContextIMP::session_data_name = \"_session_data_\";\nstd::string ContextIMP::model_data_name = \"_model_data_\";\n\nRedisClientPtr init_redis_client(ConnectionPtr cnt)\n{\n    size_t index = cnt->GetIOContextIndex();\n    return RedisPool().Get(index);\n}\n\nContext ContextIMP::Make(ConnectionPtr cnt)\n{\n    return std::shared_ptr<ContextIMP>(new ContextIMP(cnt));\n}\n\nContextIMP::ContextIMP(ConnectionPtr cnt)\n    : _cnt(cnt)\n    , _env(cnt->HasApplication() ? cnt->GetApplication()->GetTemplateRoot().native() : \"\")\n    , _redis(init_redis_client(cnt))\n{\n    prepair_template_env();\n}\n\nContextIMP::~ContextIMP()\n{\n}\n\nvoid ContextIMP::prepair_template_env()\n{\n    init_template_env(_env);\n\n    if (_cnt->HasApplication())\n    {\n        _cnt->GetApplication()->GetTemplates().CopyIncludeTemplateTo(_env);\n    }\n\n    regist_template_enginer_common_functions();\n}\n\nsize_t ContextIMP::IOContextIndex() const\n{\n    return _cnt->GetIOContextIndex();\n}\n\nlog::LoggerPtr ContextIMP::logger()\n{\n    assert(_cnt);\n    assert(_cnt->GetApplication());\n    assert(_cnt->GetApplication()->GetLogger());\n\n    return _cnt->GetApplication()->GetLogger();\n}\n\nvoid ContextIMP::regist_string_function_with_one_string_parameter(char const* function_name,\n                                                                  PSSFun func,\n                                                                  std::string defaultValue)\n{\n    _env.add_callback(function_name, 1\n                      , [this, func, function_name, defaultValue](inja::Arguments & args) -> std::string\n    {\n        try\n        {\n            if (args.size() == 1)\n            {\n                std::string name = args.at(0)->get<std::string>();\n\n                if (!name.empty())\n                {\n                    return (this->*func)(name);\n                }\n            }\n\n            return defaultValue;\n        }\n        catch (std::exception const& e)\n        {\n            logger()\n            ->error(\"Regist templage enginer function {} exception. {}\", function_name, e.what());\n        }\n\n        return defaultValue;\n    });\n}\n\nvoid ContextIMP::regist_bool_function_with_one_string_parameter(char const* function_name,\n                                                                PBSFun func,\n                                                                bool defaultValue)\n{\n    _env.add_callback(function_name, 1\n                      , [this, func, function_name, defaultValue](inja::Arguments & args) -> bool\n    {\n        try\n        {\n            if (args.size() == 1)\n            {\n                std::string name = args.at(0)->get<std::string>();\n\n                if (!name.empty())\n                {\n                    return (this->*func)(name);\n                }\n            }\n\n            return defaultValue;\n        }\n        catch (std::exception const& e)\n        {\n            logger()\n            ->error(\"Regist templage enginer function {} exception. {}\"\n                    , function_name, e.what());\n        }\n\n        return defaultValue;\n    });\n}\n\nvoid ContextIMP::regist_template_enginer_common_functions()\n{\n    regist_string_function_with_one_string_parameter(\"_PARAMETER_\", &Self::parameter);\n    regist_bool_function_with_one_string_parameter(\"_IS_EXISTS_PARAMETER_\", &Self::is_exists_parameter);\n\n    regist_string_function_with_one_string_parameter(\"_HEADER_\", &Self::header);\n    regist_bool_function_with_one_string_parameter(\"_IS_EXISTS_HEADER_\", &Self::is_exists_header);\n\n    regist_string_function_with_one_string_parameter(\"_URL_PARAMETER_\", &Self::url_parameter);\n    regist_bool_function_with_one_string_parameter(\"_IS_EXISTS_URL_PARAMETER_\", &Self::is_exists_url_parameter);\n\n    regist_string_function_with_one_string_parameter(\"_PATH_PARAMETER_\", &Self::path_parameter);\n    regist_bool_function_with_one_string_parameter(\"_IS_EXISTS_PATH_PARAMETER_\", &Self::is_exists_path_parameter);\n\n    regist_string_function_with_one_string_parameter(\"_FORM_DATA_\", &Self::form_data);\n    regist_bool_function_with_one_string_parameter(\"_IS_EXISTS_FORM_DATA_\", &Self::is_exists_form_data);\n\n    regist_string_function_with_one_string_parameter(\"_COOKIE_\", &Self::cookie);\n    regist_bool_function_with_one_string_parameter(\"_IS_EXISTS_COOKIE_\", &Self::is_exists_cookie);\n}\n\nRequest const& ContextIMP::Req() const\n{\n    return _cnt->GetRequest();\n}\n\nResponse& ContextIMP::Res()\n{\n    return _cnt->GetResponse();\n}\n\nApplication&  ContextIMP::App()\n{\n    assert(_cnt->GetApplication() != nullptr);\n    return *(_cnt->GetApplication());\n}\n\nApplication const& ContextIMP::App() const\n{\n    assert(_cnt->GetApplication() != nullptr);\n    return *(_cnt->GetApplication());\n}\n\nIOC& ContextIMP::IOContext()\n{\n#ifdef HAS_IO_CONTEXT\n    return _cnt->GetSocket().get_executor().context();\n#else\n    return _cnt->GetSocket().get_io_service();\n#endif\n}\n\nvoid ContextIMP::InitRequestPathParameters(std::vector<std::string> const& names\n                                           , std::vector<std::string> const& values)\n{\n    _cnt->GetRequest().InitPathParameters(names, values);\n}\n\nvoid ContextIMP::InitRequestPathParameter(std::string const& value)\n{\n    this->InitRequestPathParameters({\"\"}, {value});\n}\n\nstd::string ContextIMP::GetSessionID() const\n{\n    Json const& session = this->SessionData();\n\n    if (session.is_discarded() || session.is_null() || !session.is_object())\n    {\n        return Utilities::theEmptyString;\n    }\n\n    Cookie cookie = da4qi4::GetSessionCookie(session);\n\n    if (cookie.IsEmpty())\n    {\n        return Utilities::theEmptyString;\n    }\n\n    return cookie.GetValue();\n}\n\nCookie ContextIMP::GetSessionCookie() const\n{\n    Cookie cookie;\n\n    Json const& session = this->SessionData();\n\n    if (session.is_discarded() || session.is_null() || !session.is_object())\n    {\n        return cookie;\n    }\n\n    return da4qi4::GetSessionCookie(session);\n}\n\nvoid ContextIMP::ClearSessionData()\n{\n    auto& session = this->SessionData();\n\n    for (auto it = session.begin(); it != session.end();)\n    {\n        if (it.key() != da4qi4::session_cookie_name)\n        {\n            it = session.erase(it);\n        }\n        else\n        {\n            ++it;\n        }\n    }\n}\n\nstd::string ContextIMP::render_on_template(std::string const& templ_name, Template const& templ\n                                           , Json const& data\n                                           , bool& server_render_error\n                                           , std::string& error_what)\n{\n    server_render_error = false;\n    error_what.clear();\n\n    if (templ_name != _template_name)\n    {\n        _template_name = templ_name;\n    }\n\n    try\n    {\n        return _env.render(templ, data);\n    }\n    catch (std::runtime_error const& e)\n    {\n        server_render_error = true;\n        error_what = e.what();\n    }\n    catch (std::exception const& e)\n    {\n        server_render_error = true;\n        error_what = e.what();\n    }\n    catch (std::string const& s)\n    {\n        server_render_error = true;\n        error_what = s;\n    }\n    catch (...)\n    {\n        server_render_error = true;\n        error_what = \"unknown render error.\";\n    }\n\n    if (server_render_error)\n    {\n        logger()->error(\"Render template exception. {}. \\\"{}\\\".\", error_what, templ_name);\n    }\n\n    return Utilities::theEmptyString;\n}\n\nvoid ContextIMP::render_on_template(std::string const& templ_name, Template const& templ\n                                    , Json const& data, http_status status)\n{\n    bool error = false;\n    std::string error_detail;\n\n    std::string view = render_on_template(templ_name, templ, data, error, error_detail);\n\n    if (error)\n    {\n        if (status != HTTP_STATUS_INTERNAL_SERVER_ERROR)\n        {\n            Json error_data;\n            error_data[\"internal_server_error_detail\"] = error_detail;\n            RenderInternalServerError(error_data);\n        }\n        else\n        {\n            Res().ReplyStatus(status);\n        }\n\n        return;\n    }\n\n    Res().SetStatusCode(status);\n\n    if (!view.empty())\n    {\n        auto content_type = Res().GetContentType(Response::ContentTypePart::without_chartset);\n\n        if (content_type.empty())\n        {\n            Res().SetContentType(\"text/html\");\n        }\n\n        Res().SetBody(std::move(view));\n    }\n}\n\nContextIMP& ContextIMP::Render()\n{\n    Json& page_data = ModelData();\n    return (page_data.is_null()) ? this->RenderWithoutData() : this->render_with_data(page_data);\n}\n\nContextIMP& ContextIMP::Render(Json const& data)\n{\n    return render_with_data(data);\n}\n\nContextIMP& ContextIMP::Render(std::string const& template_name, Json const& data)\n{\n    if (!data.is_null())\n    {\n        return render_with_data(template_name, data);\n    }\n\n    Json& page_data = ModelData();\n    return (page_data.is_null()) ?\n           RenderWithoutData(template_name) : render_with_data(template_name, page_data);\n}\n\nContextIMP& ContextIMP::Render(std::string const& template_name, http_status status, Json const& data)\n{\n    if (!data.is_null())\n    {\n        return render_with_data(template_name, status, data);\n    }\n\n    Json& page_data = ModelData();\n\n    return (page_data.is_null()) ?\n           RenderWithoutData(template_name, status) : render_with_data(template_name, status, page_data);\n}\n\nContextIMP& ContextIMP::render_with_data(http_status status, Json const& data)\n{\n    std::string template_name = std::to_string(static_cast<int>(status));\n\n    if (auto templ = App().GetTemplates().Get(template_name))\n    {\n        render_on_template(template_name, *templ, data, status);\n    }\n    else\n    {\n        Res().ReplyStatus(status);\n    }\n\n    return *this;\n}\n\nContextIMP& ContextIMP::render_with_data(std::string const& template_name, Json const& data)\n{\n    if (template_name.empty())\n    {\n        return render_with_data(data);\n    }\n\n    auto templ = App().GetTemplates().Get(template_name);\n\n    if (!templ)\n    {\n        logger()->error(\"No found template {0}.\", template_name);\n        RenderNofound();\n        return *this;\n    }\n\n    render_on_template(template_name, *templ, data, HTTP_STATUS_OK);\n    return *this;\n}\n\nstd::string ContextIMP::auto_match_template()\n{\n    std::string const& path = Req().GetUrl().path;\n\n    if (path.empty())\n    {\n        return \"/index\";\n    }\n\n    std::string::const_iterator first = path.begin();\n    std::string::const_reverse_iterator last = path.crbegin();\n\n    if (first == std::prev(last.base())) // path.size() == 1\n    {\n        return (*first == '/') ? \"/index\" : \"\";\n    }\n\n    if (*last != '/' && *first == '/')\n    {\n        return path;\n    }\n\n    std::string template_name;\n    template_name.reserve(path.size() + 2);\n\n    if (*first != '/')\n    {\n        template_name = \"/\";\n    }\n\n    template_name += path;\n\n    if (*last == '/')\n    {\n        template_name += \"index\";\n    }\n\n    return template_name;\n}\n\nContextIMP& ContextIMP::render_with_data(std::string const& template_name, http_status status, Json const& data)\n{\n    std::string template_name_use;\n\n    if (template_name.empty())\n    {\n        template_name_use = std::to_string(static_cast<int>(status));\n    }\n    else\n    {\n        template_name_use = template_name;\n    }\n\n    if (auto templ = App().GetTemplates().Get(template_name))\n    {\n        render_on_template(template_name, *templ, data, status);\n    }\n    else\n    {\n        Res().ReplyStatus(status);\n    }\n\n    return *this;\n}\n\nContextIMP& ContextIMP::render_with_data(Json const& data)\n{\n    if (!_template_name.empty()) // explicit template name\n    {\n        if (auto templ = App().GetTemplates().Get(_template_name))\n        {\n            render_on_template(_template_name, *templ, data, HTTP_STATUS_OK);\n        }\n        else\n        {\n            RenderNofound();\n        }\n\n        return *this;\n    }\n\n    std::string auto_matched_template_name = auto_match_template();\n\n    if (auto_matched_template_name.empty())\n    {\n        RenderNofound();\n        return *this;\n    }\n\n    auto templ = App().GetTemplates().Get(auto_matched_template_name);\n\n    if (templ)\n    {\n        render_on_template(auto_matched_template_name, *templ, data, HTTP_STATUS_OK);\n        return *this;\n    }\n\n    RenderNofound();\n    return *this;\n}\n\nvoid ContextIMP::end()\n{\n    _cnt->StartWrite();\n}\n\nvoid ContextIMP::StartChunkedResponse()\n{\n    Res().MarkChunked();\n}\n\nvoid ContextIMP::NextChunkedResponse(std::string const& body)\n{\n    Res().PushChunkedBody(body, false);\n}\n\nvoid ContextIMP::StopChunkedResponse()\n{\n    Res().PushChunkedBody(Utilities::theEmptyString, true);\n}\n\nvoid ContextIMP::Start()\n{\n    _intercepter_on = Intercepter::On::Request;\n\n    auto range = App().GetIntercepterChainRange();\n    _intercepter_beg = _intercepter_iter = range.first;\n    _intercepter_end = range.second;\n\n    do_intercepter_on_req_dir();\n}\n\nvoid ContextIMP::Pass()\n{\n    next(Intercepter::Result::Pass);\n}\n\nvoid ContextIMP::Stop()\n{\n    next(Intercepter::Result::Stop);\n}\n\nvoid ContextIMP::do_intercepter_on_req_dir()\n{\n    assert(_intercepter_on == Intercepter::On::Request);\n\n    if (_intercepter_iter == _intercepter_end)\n    {\n        _intercepter_on = Intercepter::On::Handle;\n        App().Handle(shared_from_this());\n        return;\n    }\n\n    auto& handler = *_intercepter_iter; //ref!!\n    handler(shared_from_this(), Intercepter::On::Request);\n}\n\nvoid ContextIMP::do_intercepter_on_res_dir()\n{\n    assert(_intercepter_on == Intercepter::On::Response);\n\n    Intercepter::ChainReverseIterator r_intercepter_iter(_intercepter_iter);\n    Intercepter::ChainReverseIterator r_end(_intercepter_beg);\n\n    if (r_intercepter_iter == r_end)\n    {\n        end();\n        return;\n    }\n\n    auto& handler = *r_intercepter_iter; //ref!!\n    handler(shared_from_this(), Intercepter::On::Response);\n}\n\nvoid ContextIMP::next(Intercepter::Result result)\n{\n    if (_intercepter_on == Intercepter::On::Request)\n    {\n        next_intercepter_on_req_dir(result);\n    }\n    else if (_intercepter_on == Intercepter::On::Handle)\n    {\n        _intercepter_on = Intercepter::On::Response;\n        start_intercepter_on_res_dir(result);\n    }\n    else if (_intercepter_on == Intercepter::On::Response)\n    {\n        next_intercepter_on_res_dir(result);\n    }\n}\n\nvoid ContextIMP::next_intercepter_on_req_dir(Intercepter::Result result)\n{\n    assert(_intercepter_on == Intercepter::On::Request);\n\n    ++_intercepter_iter;\n\n    switch (result)\n    {\n        case Intercepter::Result::Pass :\n            do_intercepter_on_req_dir();\n            break;\n\n        case  Intercepter::Result::Stop :\n            _intercepter_on = Intercepter::On::Response;\n            do_intercepter_on_res_dir();\n            break;\n    }\n}\n\nvoid ContextIMP::start_intercepter_on_res_dir(Intercepter::Result result)\n{\n    switch (result)\n    {\n        case Intercepter::Result::Pass :\n            do_intercepter_on_res_dir();\n            break;\n\n        case  Intercepter::Result::Stop :\n            end();\n            break;\n    }\n}\n\nvoid ContextIMP::next_intercepter_on_res_dir(Intercepter::Result result)\n{\n    assert(_intercepter_on == Intercepter::On::Response);\n\n    --_intercepter_iter;\n    start_intercepter_on_res_dir(result);\n}\n\n} //namespace da4qi4\n"
  },
  {
    "path": "src/cookie.cpp",
    "content": "#include \"daqi/cookie.hpp\"\n\n#include \"nlohmann/json.hpp\"\n#include \"daqi/utilities/string_utilities.hpp\"\n\nnamespace da4qi4\n{\nCookie& Cookie::SetExpires(std::time_t a_time_point)\n{\n    std::time_t now(std::time(nullptr));\n    _max_age = static_cast<int>(a_time_point - now);\n    return *this;\n}\n\nstruct QV\n{\n    QV(std::string const& v, char const* q = \"\")\n        : v(v), q(q)\n    {}\n\n    std::string const& v;\n    std::string q;\n};\n\nstd::ostream& operator << (std::ostream& os, QV const& qv)\n{\n    if (qv.q.empty())\n    {\n        return os << qv.v;\n    }\n\n    bool need_esc = qv.v.find(qv.q) != std::string::npos;\n\n    if (!need_esc)\n    {\n        return os << qv.q << qv.v << qv.q;\n    }\n\n    std::string dst = std::string(\"\\\\\") + qv.q;\n    std::string esc = Utilities::ReplaceAll(qv.v, qv.q, dst);\n    return os << qv.q << esc << qv.q;\n}\n\nstd::ostream& operator << (std::ostream& os, Cookie const& c)\n{\n    char const* qs[] = {\"\", \"\\\"\"};\n    char const* q = qs[!!c._old_version];\n    os << c._name << '=' << QV(c._value, q);\n\n    if (c.IsExpiredImmediately())\n    {\n        os << ((!c._old_version) ? \"; Max-Age=-1\" : \"; Expires=Thu, 01 Jan 1970 00:00:00 GMT\");\n    }\n    else if (!c.IsExpiredAfterBrowerClose())\n    {\n        if (!c._old_version)\n        {\n            os << \"; Max-Age=\" << QV(std::to_string(c._max_age), q);\n        }\n        else\n        {\n            std::time_t expires = std::time(nullptr) + c._max_age;\n            os << \"; Expires=\" << QV(Utilities::GMTFormatTime(expires), q);\n        }\n    }\n\n    if (!c._domain.empty())\n    {\n        os << \"; Domain=\" << QV(c._domain, q);\n    }\n\n    if (!c._path.empty())\n    {\n        os << \"; Path=\" << QV(c._path, q);\n    }\n\n    if (!c._old_version)\n    {\n        if (c._samesite != Cookie::SameSite::none)\n        {\n            std::string v = (c._samesite == Cookie::SameSite::lax) ? \"Lax\" : \"Strict\";\n            os << \"; SameSite=\" << QV(v, q);\n        }\n    }\n\n    if (c._secure)\n    {\n        os << \"; Secure\";\n    }\n\n    if (c._http_only)\n    {\n        os << \"; HttpOnly\";\n    }\n\n    return os;\n}\n\nvoid to_json(Json& j,  Cookie const& c)\n{\n    j[\"order_version\"] = c._old_version;\n    j[\"name\"] = c._name;\n    j[\"value\"] = c._value;\n    j[\"domain\"] = c._domain;\n    j[\"path\"] = c._path;\n    j[\"max_age\"] = c._max_age;\n    j[\"http_only\"] = c._http_only;\n    j[\"secure\"] = c._secure;\n    j[\"samesite\"] = static_cast<int>(c._samesite);\n}\n\nvoid from_json(Json const& j, Cookie& c)\n{\n    j.at(\"order_version\").get_to(c._old_version);\n    j.at(\"name\").get_to(c._name);\n    j.at(\"value\").get_to(c._value);\n    j.at(\"domain\").get_to(c._domain);\n    j.at(\"path\").get_to(c._path);\n    j.at(\"max_age\").get_to(c._max_age);\n    j.at(\"http_only\").get_to(c._http_only);\n    j.at(\"secure\").get_to(c._secure);\n    j.at(\"samesite\").get_to(c._samesite);\n}\n\n} //namespace da4qi4\n"
  },
  {
    "path": "src/def/boost_def.cpp",
    "content": "#include \"daqi/def/boost_def.hpp\"\n\nnamespace da4qi4\n{\nboost::none_t NoneObject = boost::none;\n}//namsepace da4qi4\n"
  },
  {
    "path": "src/def/def.cpp",
    "content": "#include \"daqi/def/def.hpp\"\n\nnamespace da4qi4\n{\n\nchar const* const the_daqi_name = \"da4qi4\";\nchar const* const the_daqi_version = \"1.10\";\n\n} //namespace da4qi4\n"
  },
  {
    "path": "src/def/json_def.cpp",
    "content": "#include \"daqi/def/json_def.hpp\"\n\n#include <string>\n#include <vector>\n\nnamespace da4qi4\n{\n\nJson const theNullJson;\n\nnamespace Valuetool\n{\n\ndouble const zero_compare_value = 0.0000000001;\n\nbool is_exists(Json const& j, std::string const& item_name)\n{\n    return j.find(item_name) != j.cend();\n}\n\nbool is_exists(Json const& j, std::vector<std::string> const& name_pathes)\n{\n    if (!j.is_object())\n    {\n        return false;\n    }\n\n    if (name_pathes.empty())\n    {\n        return false;\n    }\n\n    auto parent = j.find(name_pathes[0]);\n\n    if (parent == j.cend())\n    {\n        return false;\n    }\n\n    for (size_t i = 1; i < name_pathes.size(); ++i)\n    {\n        if (!parent->is_object())\n        {\n            return false;\n        }\n\n        auto child = parent->find(name_pathes[i]);\n\n        if (child == parent->cend())\n        {\n            return false;\n        }\n\n        parent = child;\n    }\n\n    return true;\n}\n\nbool boolean_value(Json const& j, bool default_value)\n{\n    if (j.is_discarded())\n    {\n        return default_value;\n    }\n\n    if (j.is_boolean())\n    {\n        return j.get<bool>();\n    }\n\n    if (j.is_null())\n    {\n        return false;\n    }\n\n    if (j.is_array())\n    {\n        return !j.empty();\n    }\n\n    if (j.is_number_integer())\n    {\n        return j.get<std::size_t>() != 0;\n    }\n\n    if (j.is_number_float())\n    {\n        auto const d = j.get<double>();\n        return (d < -zero_compare_value || d > zero_compare_value);\n    }\n\n    return default_value;\n}\n\nbool boolean_value(Json const& j, std::string const& item_name, bool default_value)\n{\n    if (item_name.empty())\n    {\n        return boolean_value(j, default_value);\n    }\n\n    if (!j.is_object())\n    {\n        return default_value;\n    }\n\n    auto it = j.find(item_name);\n\n    if (it == j.cend())\n    {\n        return default_value;\n    }\n\n    return boolean_value(*it, default_value);\n}\n\nbool boolean_value(Json const& j, std::vector<std::string>const& name_pathes, bool default_value)\n{\n    if (name_pathes.empty())\n    {\n        return boolean_value(j, default_value);\n    }\n\n    if (!j.is_object())\n    {\n        return default_value;\n    }\n\n    auto parent = j.find(name_pathes[0]);\n\n    if (parent == j.cend())\n    {\n        return default_value;\n    }\n\n    for (size_t i = 1; i < name_pathes.size(); ++i)\n    {\n        if (!parent->is_object())\n        {\n            return default_value;\n        }\n\n        auto child = parent->find(name_pathes[i]);\n\n        if (child == parent->cend())\n        {\n            return default_value;\n        }\n\n        parent = child;\n    }\n\n    return boolean_value(*parent, default_value);\n}\n\nint integer_value(Json const& j, int default_value)\n{\n    if (j.is_discarded())\n    {\n        return default_value;\n    }\n\n    if (j.is_number_integer())\n    {\n        return j.get<int>();\n    }\n\n    if (j.is_null())\n    {\n        return 0;\n    }\n\n    if (j.is_boolean())\n    {\n        return (j.get<bool>()) ? 1 : 0;\n    }\n\n    if (j.is_number_float())\n    {\n        auto const d = j.get<double>();\n        return static_cast<int>(d);\n    }\n\n    return default_value;\n}\n\nint integer_value(Json const& j, std::string const& item_name, int default_value)\n{\n    if (item_name.empty())\n    {\n        return integer_value(j, default_value);\n    }\n\n    if (!j.is_object())\n    {\n        return default_value;\n    }\n\n    auto it = j.find(item_name);\n\n    if (it == j.cend())\n    {\n        return default_value;\n    }\n\n    return integer_value(*it, default_value);\n}\n\nint integer_value(Json const& j, std::vector<std::string>const& name_pathes, int default_value)\n{\n    if (name_pathes.empty())\n    {\n        return integer_value(j, default_value);\n    }\n\n    if (!j.is_object())\n    {\n        return default_value;\n    }\n\n    auto parent = j.find(name_pathes[0]);\n\n    if (parent == j.cend())\n    {\n        return default_value;\n    }\n\n    for (size_t i = 1; i < name_pathes.size(); ++i)\n    {\n        if (!parent->is_object())\n        {\n            return default_value;\n        }\n\n        auto child = parent->find(name_pathes[i]);\n\n        if (child == parent->cend())\n        {\n            return default_value;\n        }\n\n        parent = child;\n    }\n\n    return integer_value(*parent, default_value);\n}\n\ndouble double_value(Json const& j, double default_value)\n{\n    if (j.is_discarded())\n    {\n        return default_value;\n    }\n\n    if (j.is_number_float())\n    {\n        return j.get<double>();\n    }\n\n    if (j.is_null())\n    {\n        return 0.0;\n    }\n\n    if (j.is_boolean())\n    {\n        return (j.get<bool>()) ? 1 : 0;\n    }\n\n    if (j.is_number_integer())\n    {\n        auto const i = j.get<int>();\n        return i;\n    }\n\n    return default_value;\n}\n\ndouble double_value(Json const& j, std::string const& item_name, double default_value)\n{\n    if (item_name.empty())\n    {\n        return double_value(j, default_value);\n    }\n\n    if (!j.is_object())\n    {\n        return default_value;\n    }\n\n    auto it = j.find(item_name);\n\n    if (it == j.cend())\n    {\n        return default_value;\n    }\n\n    return double_value(*it, default_value);\n}\n\ndouble double_value(Json const& j, std::vector<std::string>const& name_pathes, double default_value)\n{\n    if (name_pathes.empty())\n    {\n        return double_value(j, default_value);\n    }\n\n    if (!j.is_object())\n    {\n        return default_value;\n    }\n\n    auto parent = j.find(name_pathes[0]);\n\n    if (parent == j.cend())\n    {\n        return default_value;\n    }\n\n    for (size_t i = 1; i < name_pathes.size(); ++i)\n    {\n        if (!parent->is_object())\n        {\n            return default_value;\n        }\n\n        auto child = parent->find(name_pathes[i]);\n\n        if (child == parent->cend())\n        {\n            return default_value;\n        }\n\n        parent = child;\n    }\n\n    return double_value(*parent, default_value);\n}\n\nstd::string string_value(Json const& j)\n{\n    if (j.is_discarded())\n    {\n        return \"\";\n    }\n\n    if (j.is_string())\n    {\n        return j.get<std::string>();\n    }\n\n    if (j.is_number_float())\n    {\n        return std::to_string(j.get<double>());\n    }\n\n    if (j.is_null())\n    {\n        return \"null\";\n    }\n\n    if (j.is_boolean())\n    {\n        return (j.get<bool>()) ? \"true\" : \"false\";\n    }\n\n    if (j.is_number_integer())\n    {\n        auto const i = j.get<int>();\n        return std::to_string(i);\n    }\n\n    return j.dump(2);\n}\n\nstd::string string_value(Json const& j, std::string const& item_name, std::string const& default_value)\n{\n    if (item_name.empty())\n    {\n        return string_value(j);\n    }\n\n    if (!j.is_object())\n    {\n        return default_value;\n    }\n\n    auto it = j.find(item_name);\n\n    if (it == j.cend())\n    {\n        return default_value;\n    }\n\n    return string_value(*it, default_value);\n}\n\nstd::string string_value(Json const& j, std::vector<std::string>const& name_pathes,\n                         std::string const& default_value)\n{\n    if (name_pathes.empty())\n    {\n        return string_value(j, default_value);\n    }\n\n    if (!j.is_object())\n    {\n        return default_value;\n    }\n\n    auto parent = j.find(name_pathes[0]);\n\n    if (parent == j.cend())\n    {\n        return default_value;\n    }\n\n    for (size_t i = 1; i < name_pathes.size(); ++i)\n    {\n        if (!parent->is_object())\n        {\n            return default_value;\n        }\n\n        auto child = parent->find(name_pathes[i]);\n\n        if (child == parent->cend())\n        {\n            return default_value;\n        }\n\n        parent = child;\n    }\n\n    return string_value(*parent, default_value);\n}\n\nstd::size_t size_value(Json const& j, std::size_t default_value)\n{\n    if (j.is_discarded())\n    {\n        return default_value;\n    }\n\n    if (j.is_number_integer())\n    {\n        return j.get<std::size_t>();\n    }\n\n    if (j.is_null())\n    {\n        return 0;\n    }\n\n    if (j.is_boolean())\n    {\n        return (j.get<bool>()) ? 1 : 0;\n    }\n\n    if (j.is_number_float())\n    {\n        auto const d = j.get<double>();\n        return static_cast<std::size_t>(d);\n    }\n\n    return default_value;\n}\n\nstd::size_t size_value(Json const& j, std::string const& item_name, std::size_t default_value)\n{\n    if (item_name.empty())\n    {\n        return size_value(j, default_value);\n    }\n\n    if (!j.is_object())\n    {\n        return default_value;\n    }\n\n    auto it = j.find(item_name);\n\n    if (it == j.cend())\n    {\n        return default_value;\n    }\n\n    return size_value(*it, default_value);\n}\n\nstd::size_t size_value(Json const& j, std::vector<std::string>const& name_pathes, std::size_t default_value)\n{\n    if (name_pathes.empty())\n    {\n        return size_value(j, default_value);\n    }\n\n    if (!j.is_object())\n    {\n        return default_value;\n    }\n\n    auto parent = j.find(name_pathes[0]);\n\n    if (parent == j.cend())\n    {\n        return default_value;\n    }\n\n    for (size_t i = 1; i < name_pathes.size(); ++i)\n    {\n        if (!parent->is_object())\n        {\n            return default_value;\n        }\n\n        auto child = parent->find(name_pathes[i]);\n\n        if (child == parent->cend())\n        {\n            return default_value;\n        }\n\n        parent = child;\n    }\n\n    return size_value(*parent, default_value);\n}\n\n\nstd::time_t time_value(Json const& j, std::time_t default_value)\n{\n    if (j.is_discarded())\n    {\n        return default_value;\n    }\n\n    if (j.is_number_integer())\n    {\n        return j.get<std::time_t>();\n    }\n\n    if (j.is_null())\n    {\n        return 0;\n    }\n\n    if (j.is_boolean())\n    {\n        return (j.get<bool>()) ? 1 : 0;\n    }\n\n    if (j.is_number_float())\n    {\n        auto const d = j.get<double>();\n        return static_cast<std::time_t>(d);\n    }\n\n    return default_value;\n}\n\nstd::time_t time_value(Json const& j, std::string const& item_name, std::time_t default_value)\n{\n    if (item_name.empty())\n    {\n        return time_value(j, default_value);\n    }\n\n    if (!j.is_object())\n    {\n        return default_value;\n    }\n\n    auto it = j.find(item_name);\n\n    if (it == j.cend())\n    {\n        return default_value;\n    }\n\n    return time_value(*it, default_value);\n}\n\nstd::time_t time_value(Json const& j, std::vector<std::string>const& name_pathes, std::time_t default_value)\n{\n    if (name_pathes.empty())\n    {\n        return time_value(j, default_value);\n    }\n\n    if (!j.is_object())\n    {\n        return default_value;\n    }\n\n    auto parent = j.find(name_pathes[0]);\n\n    if (parent == j.cend())\n    {\n        return default_value;\n    }\n\n    for (size_t i = 1; i < name_pathes.size(); ++i)\n    {\n        if (!parent->is_object())\n        {\n            return default_value;\n        }\n\n        auto child = parent->find(name_pathes[i]);\n\n        if (child == parent->cend())\n        {\n            return default_value;\n        }\n\n        parent = child;\n    }\n\n    return time_value(*parent, default_value);\n}\n\n} // namespace Valuetool\n\n} //namespace da4qi4\n"
  },
  {
    "path": "src/def/log_def.cpp",
    "content": "#include \"daqi/def/log_def.hpp\"\n\n#include <iostream>\n\n#include \"spdlog/sinks/null_sink.h\"\n\n#include \"daqi/def/def.hpp\"\n#include \"daqi/application.hpp\"\n\nnamespace da4qi4\n{\n\nnamespace\n{\n\nstd::shared_ptr<spdlog::logger> the_null_log;\n\nstruct InitNullLogger\n{\n    InitNullLogger()\n    {\n        auto null_sink = std::make_shared<spdlog::sinks::null_sink_mt>();\n        the_null_log = std::make_shared<spdlog::logger>(\"null\", null_sink);\n    }\n};\n\n}\n\nnamespace log\n{\n\nLoggerPtr Null()\n{\n    static InitNullLogger _init_null_log_;\n    return the_null_log;\n}\n\nbool IsNull(LoggerPtr logger)\n{\n    return (logger == nullptr) || (logger == the_null_log);\n}\n\nbool InitLogger(std::string const& name //logger's name\n                , std::string const& server_name\n                , std::string& error\n                , std::string const& log_dir\n                , Level level\n                , size_t max_file_size_kb, size_t max_file_count)\n{\n    try\n    {\n        std::string log_filename = log_dir + name + \".log\";\n        auto file_sink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(\n                                     log_filename, 1024 * max_file_size_kb, max_file_count);\n\n        auto console_sink = std::make_shared<spdlog::sinks::ansicolor_stdout_sink_mt>();\n\n        std::vector<spdlog::sink_ptr> sinks {file_sink, console_sink};\n\n        auto logger = std::make_shared<spdlog::logger>(name\n                                                       , std::begin(sinks)\n                                                       , std::end(sinks));\n        logger->set_level(level);\n        spdlog::register_logger(logger);\n\n        logger->info(\"Welcome to {}.\", server_name);\n\n        return true;\n    }\n    catch (std::exception const& e)\n    {\n        error = e.what();\n        return false;\n    }\n}\n\nbool InitServerLogger(const std::string& log_dir, Level level\n                      , size_t max_file_size_kb, size_t max_file_count)\n{\n    std::string err;\n    bool ok = InitLogger(\"server\", the_daqi_name, err, log_dir, level, max_file_size_kb, max_file_count);\n\n    if (!ok)\n    {\n        std::cerr << \"Init \" << the_daqi_name << \" logger fail. \" << err << \" on \" << log_dir << std::endl;\n    }\n\n    return ok;\n}\n\nLoggerPtr CreateAppLogger(std::string const& application_name\n                          , std::string const& application_root_log\n                          , Level level\n                          , size_t max_file_size_kb, size_t max_file_count)\n{\n    try\n    {\n        std::string log_filename = application_root_log + application_name + \".log\";\n        auto file_sink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(\n                                     log_filename, 1024 * max_file_size_kb, max_file_count);\n\n        auto console_sink = std::make_shared<spdlog::sinks::ansicolor_stdout_sink_mt>();\n\n        std::vector<spdlog::sink_ptr> sinks {file_sink, console_sink};\n\n        auto app_log = std::make_shared<spdlog::logger>(application_name\n                                                        , std::begin(sinks)\n                                                        , std::end(sinks));\n        app_log->set_level(level);\n        spdlog::register_logger(app_log);\n\n        return app_log;\n    }\n    catch (std::exception const& e)\n    {\n        std::cerr << e.what() << std::endl;\n        return nullptr;\n    }\n}\n\nLoggerPtr Server()\n{\n    auto log = spdlog::get(\"server\");\n    return (log ? log : Null());\n}\n\nLoggerPtr App(std::string const& application_name)\n{\n    return AppMgr().GetApplicationLogger(application_name);\n}\n\nvoid SetLogLevel(Level level)\n{\n    spdlog::set_level(level);\n}\n\nvoid SetServerLogLevel(Level level)\n{\n    Server()->set_level(level);\n}\n\nvoid SetAppLogLevel(std::string const& application_name, Level level)\n{\n    App(application_name)->set_level(level);\n}\n\n\n} // namespace log\n} //namespace da4qi4\n"
  },
  {
    "path": "src/def/redis_def.cpp",
    "content": "#include \"daqi/def/redis_def.hpp\"\n\n#include <string>\n\nnamespace da4qi4\n{\n\nchar const* const redis_server_default_host = \"127.0.0.1\";\nunsigned short int const redis_server_default_port = 6379;\n\n} //nampespace da4qi4\n"
  },
  {
    "path": "src/handler.cpp",
    "content": "#include \"daqi/handler.hpp\"\n\nnamespace da4qi4\n{\n\nHandler theEmptyHandler;\n\nHandlerMethod _DELETE_ = HandlerMethod::DELETE;\nHandlerMethod _GET_ = HandlerMethod ::GET;\nHandlerMethod _HEAD_ = HandlerMethod::HEAD;\nHandlerMethod _POST_ = HandlerMethod::POST;\nHandlerMethod _PUT_ = HandlerMethod::PUT;\n\nchar const* HandlerMethodName(HandlerMethod hm)\n{\n    switch (hm)\n    {\n        case HandlerMethod::UNSUPPORT :\n            return \"UNSUPPORT\";\n\n        case HandlerMethod::DELETE :\n            return \"DELETE\";\n\n        case HandlerMethod::GET :\n            return \"GET\";\n\n        case  HandlerMethod::HEAD :\n            return \"HEAD\";\n\n        case HandlerMethod::POST :\n            return \"POST\";\n\n        case HandlerMethod::PUT :\n            return \"PUT\";\n\n        case HandlerMethod::ANY :\n            return \"ANY\";\n    }\n\n    return \"\";\n}\n\nHandlerMethod from_http_method(llhttp_method_t m)\n{\n    switch (m)\n    {\n        case HTTP_DELETE :\n            return HandlerMethod::DELETE;\n\n        case HTTP_GET :\n            return HandlerMethod::GET;\n\n        case HTTP_HEAD :\n            return HandlerMethod::HEAD;\n\n        case HTTP_POST :\n            return HandlerMethod::POST;\n\n        case HTTP_PUT :\n            return HandlerMethod::PUT;\n\n        default:\n            break;\n    }\n\n    return HandlerMethod::UNSUPPORT;\n}\n\n\nHandlerMethods::HandlerMethods(HandlerMethod m)\n{\n    Set(m);\n}\n\nbool HandlerMethods::IsSet(HandlerMethod m) const\n{\n    switch (m)\n    {\n        case HandlerMethod::DELETE :\n            return mark[0];\n\n        case HandlerMethod::GET :\n            return mark[1];\n\n        case HandlerMethod::HEAD :\n            return mark[2];\n\n        case HandlerMethod::POST :\n            return mark[3];\n\n        case HandlerMethod::PUT :\n            return mark[4];\n\n        case HandlerMethod::ANY :\n            return mark.any();\n\n        case HandlerMethod::UNSUPPORT :\n            return !mark.any();\n    }\n\n    return false;\n}\n\nvoid HandlerMethods::Set(HandlerMethod m)\n{\n    switch (m)\n    {\n        case HandlerMethod::DELETE :\n            mark.set(0);\n            break;\n\n        case HandlerMethod::GET :\n            mark.set(1);\n            break;\n\n        case HandlerMethod::HEAD :\n            mark.set(2);\n            break;\n\n        case HandlerMethod::POST :\n            mark.set(3);\n            break;\n\n        case HandlerMethod::PUT :\n            mark.set(4);\n            break;\n\n        case HandlerMethod::ANY :\n            mark.reset();\n            mark.flip();\n            break;\n\n        case HandlerMethod::UNSUPPORT :\n            mark.reset();\n    }\n}\n\nHandlerMethods::HandlerMethods(std::initializer_list<HandlerMethod> lst)\n{\n    for (auto m : lst)\n    {\n        Set(m);\n    }\n}\n\n\n\n} //namespace da4qi4\n"
  },
  {
    "path": "src/intercepter.cpp",
    "content": "#include \"daqi/intercepter.hpp\"\n\nnamespace da4qi4\n{\nnamespace Intercepter\n{\n\n} //Intercepter\n} //namespace da4qi4\n"
  },
  {
    "path": "src/intercepters/session_redis.cpp",
    "content": "#include \"daqi/intercepters/session_redis.hpp\"\n\n#include <ctime>\n#include <string>\n\n#include <boost/uuid/uuid_generators.hpp>\n#include <boost/uuid/uuid_io.hpp>\n\n#include \"daqi/utilities/asio_utilities.hpp\"\n#include \"daqi/utilities/string_utilities.hpp\"\n\n#include \"daqi/context.hpp\"\n\nnamespace da4qi4\n{\nnamespace Intercepter\n{\n\nstd::string make_session_id(std::string const& prefix, bool prefix_with_time)\n{\n    if (!prefix_with_time)\n    {\n        return Utilities::GetUUID(prefix);\n    }\n\n    char buf[16];\n    auto now = std::time(nullptr);\n    std::tm tm_now = *std::localtime(&now);\n    std::strftime(buf, sizeof(buf), \"%Y%m%d-%H%M%S\", &tm_now);\n    buf[15] = '\\0';\n    std::string new_prefix = prefix + std::string(buf) + \":\";\n\n    return Utilities::GetUUID(new_prefix);\n}\n\nJson SessionOnRedis::create_new_session() const\n{\n    std::string session_id = make_session_id(_options.prefix, _options.prefix_with_time);\n\n    Cookie cookie(_options.name, session_id, _options.domain, _options.path);\n    cookie.SetMaxAge(_options.max_age);\n    cookie.SetHttpOnly(_options.http_only);\n    cookie.SetSecure(_options.secure);\n    cookie.SetSameSite(_options.samesite);\n\n    return MakeNewSession(cookie);\n}\n\nvoid SessionOnRedis::on_request(Context& ctx) const\n{\n    std::string session_id = ctx->Req().GetCookie(this->_options.name);\n\n    if (session_id.empty())\n    {\n        ctx->SaveSessionData(create_new_session());\n        ctx->Pass();\n        return;\n    }\n\n    if (auto redis = ctx->Redis())\n    {\n        redis->Command(\"GET\", {session_id}, [session_id, ctx, this](RedisValue value)\n        {\n            if (value.IsError())\n            {\n                ctx->Logger()->error(\"Get session cache fail. {}. {}\",\n                                     session_id, value.ToString());\n\n                ctx->RenderInternalServerError();\n                ctx->Stop();\n                return;\n            }\n\n            Json session;\n\n            try\n            {\n                if (!value.ToString().empty())\n                {\n                    session = Json::parse(value.ToString());\n                }\n\n                if (session.empty())\n                {\n                    session = create_new_session();\n                }\n            }\n            catch (Json::parse_error const& e)\n            {\n                ctx->Logger()->error(\"Parse session data exception. {}. {}\", session_id, e.what());\n                ctx->RenderInternalServerError();\n                ctx->Stop();\n            }\n            catch (std::exception const& e)\n            {\n                ctx->Logger()->error(\"Parse session data exception. {}. {}\", session_id, e.what());\n                ctx->RenderInternalServerError();\n                ctx->Stop();\n            }\n\n            ctx->SaveSessionData(std::move(session));\n            ctx->Pass();\n        });\n    }\n}\n\nvoid SessionOnRedis::on_response(Context& ctx) const\n{\n    Json const& session = ctx->LoadSessionData();\n\n    if (session.empty())\n    {\n        ctx->Pass();\n        return;\n    }\n\n    Cookie cookie = GetSessionCookie(session);\n\n    if (cookie.IsEmpty())\n    {\n        ctx->Pass();\n        return;\n    }\n\n    ctx->Res().SetCookie(cookie);\n\n    std::string session_timeout_s = std::to_string(cookie.GetMaxAge());\n    std::string session_id = cookie.GetValue();\n    size_t const indent = 2;\n    std::string session_value = session.dump(indent);\n\n    if (auto redis = ctx->Redis())\n    {\n        redis->Command(\"SETEX\"\n                       , {session_id, session_timeout_s, session_value}\n                       , [ctx](RedisValue value)\n        {\n            if (value.IsError())\n            {\n                ctx->Logger()->critical(\"Cache session data fail. {}\", value.ToString());\n\n                ctx->RenderInternalServerError();\n                ctx->Stop();\n            }\n\n            ctx->Pass();\n        });\n    }\n}\n\nvoid SessionOnRedis::operator()(Context ctx, On on) const\n{\n    if (_options.name.empty())\n    {\n        ctx->Pass();\n        return;\n    }\n\n    if (!Utilities::iStartsWith(ctx->Req().GetUrl().path, _options.path))\n    {\n        ctx->Pass();\n        return;\n    }\n\n    if (!ctx->HasRedis())\n    {\n        ctx->Pass();\n        return;\n    }\n\n    if (on == Intercepter::On::Request)\n    {\n        on_request(ctx);\n    }\n    else\n    {\n        on_response(ctx);\n    }\n}\n\n} //namespace Intercepter\n} //namespace da4qi4\n"
  },
  {
    "path": "src/intercepters/static_file.cpp",
    "content": "#include \"daqi/intercepters/static_file.hpp\"\n\n#include <fstream>\n\n#include \"daqi/application.hpp\"\n#include \"daqi/utilities/string_utilities.hpp\"\n#include \"daqi/utilities/html_utilities.hpp\"\n\nnamespace da4qi4\n{\nnamespace Intercepter\n{\n\nstd::string const StaticFile::data_name = \"static-file\";\n\nStaticFile& StaticFile::AddEntry(std::string const& url_root\n                                 , std::string const& dir_root)\n{\n    _root_entries.insert(std::make_pair(url_root, (dir_root.empty() ? url_root : dir_root)));\n    return *this;\n}\n\nStaticFile& StaticFile::AddDefaultFileName(std::string const& index_filename)\n{\n    for (auto fn : _default_filenames)\n    {\n        if (fn == index_filename)\n        {\n            return *this;\n        }\n    }\n\n    _default_filenames.push_back(index_filename);\n\n    return *this;\n}\n\nStaticFile& StaticFile::AddDefaultFileNames(std::vector<std::string> const&\n                                            index_filenames)\n{\n    for (auto s : index_filenames)\n    {\n        AddDefaultFileName(s);\n    }\n\n    return *this;\n}\n\nvoid StaticFile::on_request(Context& ctx) const\n{\n    HandlerMethod m = from_http_method(ctx->Req().GetMethod());\n\n    if ((m != HandlerMethod::GET))\n    {\n        ctx->Pass();\n        return;\n    }\n\n    std::string url = ctx->Req().GetUrl().full;\n\n    bool entry_found = false;\n    fs::path dst_file;\n\n    for (auto const& entry : _root_entries)\n    {\n        std::string url_starts = ((_url_resolve_type == PathResolve::is_relative)\n                                  ? ctx->App().GetUrlRoot() + entry.first\n                                  : entry.first);\n\n        if (Utilities::iStartsWith(url, url_starts))\n        {\n            std::string dir_root = ((_dir_resolve_type == PathResolve::is_relative)\n                                    ? ctx->App().GetStaticRootPath().native() + entry.second\n                                    : entry.second);\n\n            std::string::size_type beg_pos = url_starts.size();\n            std::string::size_type end_pos = (url.find('?', beg_pos));\n            std::string::size_type url_size = url.size();\n            std::string::size_type sub_len = url_size - beg_pos\n                                             - (end_pos != std::string::npos\n                                                ? (url_size - end_pos) : 0);\n\n            dst_file = dir_root;\n            dst_file /= url.substr(beg_pos, sub_len);\n            entry_found = true;\n            break;\n        }\n    }\n\n    if (entry_found)\n    {\n        Json status_data =\n        {\n            {\"found\", entry_found},\n            {\"file\", dst_file.string()}\n        };\n\n        ctx->SaveData(data_name, std::move(status_data));\n        ctx->Stop();\n        return;\n    }\n\n    ctx->Pass();\n}\n\nvoid StaticFile::on_response(Context& ctx) const\n{\n    Json status_data = ctx->LoadData(data_name);\n\n    if (status_data.empty())\n    {\n        ctx->Pass();\n        return;\n    }\n\n    auto it = status_data.find(\"found\");\n    bool entry_found = (it == status_data.end() ? false : it->get<bool>());\n\n    if (!entry_found)\n    {\n        ctx->Pass();\n        return;\n    }\n\n    it = status_data.find(\"file\");\n    std::string dst_file_name = (it == status_data.end() ? \"\" : *it);\n\n    if (dst_file_name.empty())\n    {\n        ctx->RenderBadRequest();\n        return;\n    }\n\n    fs::path dst_file(dst_file_name);\n\n    try\n    {\n        bool file_exists = dst_file.has_filename()\n                           && dst_file.filename() != \".\" && fs::exists(dst_file);\n\n        if (!file_exists)\n        {\n            bool found = false;\n\n            if (!dst_file.has_filename() || dst_file.filename() == \".\")\n            {\n                for (auto fn : _default_filenames)\n                {\n                    fs::path with_default_file = dst_file / fn;\n\n                    if (fs::exists(with_default_file))\n                    {\n                        found = true;\n                        dst_file = with_default_file;\n                        break;\n                    }\n                }\n            }\n\n            if (!found)\n            {\n                ctx->RenderNofound();\n                ctx->Pass();\n                return;\n            }\n        }\n    }\n    catch (std::exception const& e)\n    {\n        ctx->Logger()->error(\"Locate static file {} exception. {}\", dst_file_name, e.what());\n\n        ctx->RenderInternalServerError();\n        ctx->Pass();\n        return;\n    }\n\n    std::ifstream ifs(dst_file.native().c_str(), std::ios_base::binary);\n\n    if (!ifs)\n    {\n        ctx->Logger()->error(\"Open {} file fail.\", dst_file_name);\n\n        ctx->RenderInternalServerError();\n        ctx->Pass();\n        return;\n    }\n\n    size_t const max_byte_read_one_time = 1024 * 10;\n    char rdbuf[max_byte_read_one_time];\n\n    size_t const max_byte_one_chunked_body = 1024 * 100;\n    std::string a_chunk_body;\n    a_chunk_body.reserve(max_byte_one_chunked_body);\n\n    std::string content_type = Utilities::GetMIMEType(dst_file.extension().string());\n\n    if (!content_type.empty())\n    {\n        ctx->Res().SetContentType(content_type);\n    }\n\n    ctx->Res().CacheControlMaxAge(_cache_max_age);\n    ctx->StartChunkedResponse();\n\n    while (ifs)\n    {\n        ifs.read(rdbuf, max_byte_read_one_time);\n        auto count = ifs.gcount();\n\n        if (count > 0)\n        {\n            a_chunk_body.append(rdbuf, rdbuf + count);\n        }\n\n        if (a_chunk_body.size() > max_byte_one_chunked_body)\n        {\n            ctx->NextChunkedResponse(a_chunk_body);\n            a_chunk_body.clear();\n        }\n    }\n\n    if (!a_chunk_body.empty())\n    {\n        ctx->NextChunkedResponse(a_chunk_body);\n        a_chunk_body.clear();\n    }\n\n    ctx->RemoveData(data_name);\n    ctx->StopChunkedResponse();\n    ctx->Pass();\n}\n\nvoid StaticFile::operator()(Context ctx, On on) const\n{\n    if (on == Intercepter::On::Request)\n    {\n        on_request(ctx);\n    }\n    else\n    {\n        on_response(ctx);\n    }\n}\n\n} //namespace Intercepter\n} //namespace da4qi4\n"
  },
  {
    "path": "src/main_demo.cpp",
    "content": "#include <iostream>\n\n#include \"daqi/da4qi4.hpp\"\n\n#include \"daqi/intercepters/static_file.hpp\"\n#include \"daqi/intercepters/session_redis.hpp\"\n\nusing namespace da4qi4;\n\n#ifdef _BUILD_DAQI_DEMO_SERVER_\n\nint main()\n{\n    std::string www_root = \"../d2_daqi/\";\n\n    if (!log::InitServerLogger(www_root + \"logs/\", log::Level::debug))\n    {\n        std::cerr << \"Create server logger fail.\" << std::endl;\n        return -1;\n    }\n\n    auto svc = Server::Supply(4099);\n\n    std::string app_root = www_root;\n    auto web = Application::Customize(\"web\"\n                                      , \"/\"\n                                      , app_root + \"logs/\"\n                                      , app_root + \"static/\"\n                                      , app_root + \"view/\"\n                                      , app_root + \"upload/\"\n                                     );\n\n    if (!web->Init(Application::ActualLogger::yes))\n    {\n        std::cerr << \"Init application \" << web->GetName() << \" fail.\" << std::endl;\n        return -2;\n    }\n\n    Intercepter::StaticFile static_file;\n    static_file.SetCacheMaxAge(600).AddEntry(\"css/\").AddEntry(\"js/\").AddEntry(\"img/\")\n    .AddEntry(\"favicon.ico\", \"img/favicon.ico\");\n\n    web->AddIntercepter(static_file);\n\n    Intercepter::SessionOnRedis session_redis;\n    web->AddIntercepter(session_redis);\n\n    web->AddHandler(_GET_, \"/\", [](Context ctx)\n    {\n        ctx->RenderWithoutData();\n        ctx->Pass();\n    });\n\n    web->AddHandler(_GET_, \"/login\", [](Context ctx)\n    {\n        ctx->RenderWithoutData();\n        ctx->Pass();\n    });\n    web->AddHandler(_GET_, \"/regist\", [](Context ctx)\n    {\n        ctx->RenderWithoutData();\n        ctx->Pass();\n    });\n\n    if (!svc->Mount(web))\n    {\n        std::cerr << \"Mount application \" << web->GetName() << \" fail.\" << std::endl;\n        return -2;\n    }\n\n    svc->SetIdleTimerInterval(5);\n    svc->EnableDetectTemplates();\n\n    RedisPool().CreateClients(svc->GetIOContextPool());\n\n    try\n    {\n        svc->Run();\n    }\n    catch (std::exception const& e)\n    {\n        log::Server()->error(\"Run exception. {}.\", e.what());\n    }\n\n    RedisPool().Stop();\n    svc.reset();\n    log::Server()->info(\"Bye.\");\n\n    return 0;\n}\n\n#endif\n"
  },
  {
    "path": "src/net-detail/net_detail_client.cpp",
    "content": "#include \"daqi/net-detail/net_detail_client.hpp\"\n\nnamespace da4qi4\n{\nnamespace Client\n{\n\nnamespace net_detail\n{\n\nSocketBase::~SocketBase() {};\n\nSocket::~Socket()\n{\n}\n\nTcp::socket& Socket::get_socket()\n{\n    return _socket;\n}\n\nvoid Socket::async_connect(Tcp::endpoint const& ep,\n                           SocketConnectionCompletionCallback on_connect)\n{\n    _socket.async_connect(ep, on_connect);\n}\n\nvoid Socket::async_read_some(ReadBuffer& read_buffer,\n                             SocketCompletionCallback on_read)\n{\n    _socket.async_read_some(boost::asio::buffer(read_buffer), on_read);\n}\n\nvoid Socket::async_write(char const* write_buffer, std::size_t size,\n                         SocketCompletionCallback on_wrote)\n{\n    boost::asio::async_write(_socket, boost::asio::buffer(write_buffer, size), on_wrote);\n}\n\nerrorcode Socket::sync_connect(Tcp::endpoint const& ep)\n{\n    errorcode ec;\n    _socket.connect(ep, ec);\n    return ec;\n}\n\nerrorcode Socket::sync_read_some(ReadBuffer& read_buffer, std::size_t& bytes_transferred)\n{\n    errorcode ec;\n    bytes_transferred = _socket.read_some(boost::asio::buffer(read_buffer), ec);\n    return ec;\n}\n\nerrorcode Socket::sync_write(char const* write_buffer, std::size_t write_buffer_size\n                             , std::size_t& bytes_transferred)\n{\n    errorcode ec;\n    bytes_transferred = boost::asio::write(_socket\n                                           , boost::asio::buffer(write_buffer, write_buffer_size)\n                                           , ec);\n    return ec;\n}\n\nvoid Socket::close(errorcode& ec)\n{\n    _socket.shutdown(boost::asio::socket_base::shutdown_both, ec);\n    _socket.close(ec);\n}\n\nSocketWithSSL::~SocketWithSSL()\n{\n}\n\nvoid SocketWithSSL::async_connect(Tcp::endpoint const& ep,\n                                  SocketConnectionCompletionCallback on_connect)\n{\n    _stream.lowest_layer().async_connect(ep\n                                         , [this, on_connect](errorcode const & ec)\n    {\n        if (ec)\n        {\n            on_connect(ec);\n            return;\n        }\n\n        _stream.set_verify_mode(boost::asio::ssl::verify_none);\n        _stream.async_handshake(boost::asio::ssl::stream_base::client, on_connect);\n    });\n}\n\nvoid SocketWithSSL::async_read_some(ReadBuffer& read_buffer,\n                                    SocketCompletionCallback on_read)\n{\n    _stream.async_read_some(boost::asio::buffer(read_buffer), on_read);\n}\n\nvoid SocketWithSSL::async_write(char const*  write_buffer, std::size_t size,\n                                SocketCompletionCallback on_wrote)\n{\n    boost::asio::async_write(_stream, boost::asio::buffer(write_buffer, size), on_wrote);\n}\n\nerrorcode SocketWithSSL::sync_connect(Tcp::endpoint const& ep)\n{\n    errorcode ec;\n    _stream.lowest_layer().connect(ep, ec);\n    return ec;\n}\n\nerrorcode SocketWithSSL::sync_read_some(ReadBuffer& read_buffer, std::size_t& bytes_transferred)\n{\n    errorcode ec;\n    bytes_transferred = _stream.read_some(boost::asio::buffer(read_buffer), ec);\n    return ec;\n}\n\nerrorcode SocketWithSSL::sync_write(const char* write_buffer\n                                    , std::size_t write_buffer_size\n                                    , std::size_t& bytes_transferred)\n{\n    errorcode ec;\n    bytes_transferred = boost::asio::write(_stream\n                                           , boost::asio::buffer(write_buffer, write_buffer_size), ec);\n    return ec;\n}\n\nvoid SocketWithSSL::close(errorcode& ec)\n{\n    _stream.lowest_layer().cancel();\n    _stream.shutdown(ec);\n    _stream.next_layer().close(ec);\n}\n\nTcp::socket& SocketWithSSL::get_socket()\n{\n    return _stream.next_layer();\n}\n\n} // namespace net_detail\n} // namespace Client\n} // namespace da4qi4\n"
  },
  {
    "path": "src/net-detail/net_detail_server.cpp",
    "content": "#include \"daqi/net-detail/net_detail_server.hpp\"\n\nnamespace da4qi4\n{\nnamespace net_detail\n{\n\nSocketInterface::~SocketInterface() {}\nSocket::~Socket() {}\nSocketWithSSL::~SocketWithSSL() {}\n\ntemplate <typename T>\nIOC& get_io_context_from(T& socket_obj)\n{\n#ifdef HAS_IO_CONTEXT\n    return socket_obj.get_executor().get_io_context();\n#else\n    return socket_obj.get_io_service();\n#endif\n}\n\nIOC& Socket::get_ioc()\n{\n    return get_io_context_from(_socket);\n}\n\nIOC& SocketWithSSL::get_ioc()\n{\n    return get_io_context_from(_stream);\n}\n\n} //namespace net_detail\n} // namespace da4qi4\n"
  },
  {
    "path": "src/redis-client/redis_buffer.cpp",
    "content": "#include \"daqi/redis-client/redis_buffer.hpp\"\n\nnamespace da4qi4\n{\n\nRedisBuffer::RedisBuffer(const char* ptr, size_t dataSize)\n    : data(ptr + 0, ptr + dataSize)\n{\n}\n\nRedisBuffer::RedisBuffer(const char* s)\n    : data(std::string(s))\n{\n}\n\nRedisBuffer::RedisBuffer(std::string s)\n    : data(std::move(s))\n{\n}\n\nRedisBuffer::RedisBuffer(std::vector<char> buf)\n    : data(buf.cbegin(), buf.cend())\n{\n}\n\nsize_t RedisBuffer::size() const\n{\n    return data.size();\n}\n\n} // namespace da4qi4\n"
  },
  {
    "path": "src/redis-client/redis_client.cpp",
    "content": "#include \"daqi/redis-client/redis_client.hpp\"\n\n#include <iostream>\n#include <functional>\n\n#include <boost/date_time/posix_time/posix_time.hpp>\n\n#include \"daqi/def/log_def.hpp\"\n\n#include \"daqi/redis-client/redis_command.hpp\"\n#include \"daqi/redis-client/redis_parser.hpp\"\n\n\nnamespace da4qi4\n{\n\nnamespace\n{\n\nunsigned int redis_server_reconnect_interval_seconds(unsigned int const reconnect_count)\n{\n    if (reconnect_count < 10) //0s~10s\n    {\n        return 1;\n    }\n\n    if (reconnect_count < 32) //10s~2m\n    {\n        return 5;\n    }\n\n    //after 2 minutes\n    if (reconnect_count < 200) //2m~0.5h\n    {\n        return 10;\n    }\n\n    if (reconnect_count < 260)  //0.5h~1h\n    {\n        return 30;\n    }\n\n    // 1h\n    return 300; //reconnect 1 time per 5 minutes\n}\n\n} //namespace\n\nRedisClient::~RedisClient()\n{\n    Disconnect();\n}\n\nvoid RedisClient::Connect(std::function<void (boost::system::error_code const& ec)> on,\n                          std::string const& host, unsigned short port)\n{\n    if (IsConnected() || IsConnectting())\n    {\n        return;\n    }\n\n    _host = host;\n    _port = port;\n\n    do_async_connect(on);\n}\n\nvoid RedisClient::Reconnect(std::function<void (boost::system::error_code const& ec)> on)\n{\n    if (IsConnectting())\n    {\n        if (on)\n        {\n            auto ec = boost::system::errc::make_error_code(boost::system::errc::operation_in_progress);\n            on(ec);\n        }\n\n        return;\n    }\n\n    if (!IsConnected())\n    {\n        boost::system::error_code ec;\n        _reconnect_timer.cancel(ec);\n        start_reconnect_timer(on);\n    }\n    else if (on)\n    {\n        auto ec = boost::system::errc::make_error_code(boost::system::errc::already_connected);\n        on(ec);\n    }\n}\n\nvoid RedisClient::do_async_connect(std::function<void (boost::system::error_code const& ec)> on)\n{\n    _connect_status = is_connectting;\n    boost::asio::ip::tcp::endpoint end_point(\n                boost::asio::ip::address::from_string(_host), _port);\n\n    auto cb = std::bind(&RedisClient::on_connect_finished, this, on, std::placeholders::_1);\n    _socket.async_connect(end_point, cb);\n}\n\nenum class AsyncHandlerAction\n{\n    on_async_connect, on_async_read, on_async_write, on_reply_parse\n};\n\nchar const* get_async_handler_action_name(AsyncHandlerAction aha)\n{\n    static char const* names[] = {\"connect\", \"read\", \"write\", \"parse\"};\n\n    switch (aha)\n    {\n        case AsyncHandlerAction::on_async_connect:\n            return names[0];\n\n        case AsyncHandlerAction::on_async_read:\n            return names[1];\n\n        case AsyncHandlerAction::on_async_write:\n            return names[2];\n\n        case AsyncHandlerAction::on_reply_parse:\n            return names[3];\n    }\n\n    return \"\";\n}\n\nvoid try_on_redis_handler(std::function<void (boost::system::error_code const& ec)> on\n                          , boost::system::error_code p, AsyncHandlerAction aha)\n{\n    if (!on)\n    {\n        return;\n    }\n\n    try\n    {\n        on(std::move(p));\n    }\n    catch (std::exception const& e)\n    {\n        log::Server()->error(\"Redis handle {} result exception. {}\", get_async_handler_action_name(aha), e.what());\n    }\n    catch (std::string const& s)\n    {\n        log::Server()->error(\"Redis handle {} result exception. {}\", get_async_handler_action_name(aha), s);\n    }\n    catch (char const* s)\n    {\n        log::Server()->error(\"Redis handle {} result exception. {}\", get_async_handler_action_name(aha), s);\n    }\n    catch (...)\n    {\n        log::Server()->error(\"Redis handle {} result unknown exception.\", get_async_handler_action_name(aha));\n    }\n}\n\nvoid try_on_redis_handler(std::function<void(RedisValue value)> on, RedisValue p, AsyncHandlerAction aha)\n{\n    if (!on)\n    {\n        return;\n    }\n\n    //debug:\n    RedisValue debug_dump;\n    if (aha == AsyncHandlerAction::on_reply_parse)\n    {\n        debug_dump = p;\n    }\n\n    try\n    {\n        on(std::move(p));\n    }\n    catch (std::exception const& e)\n    {\n        log::Server()->error(\"Redis handle {} result exception. {}\", get_async_handler_action_name(aha), e.what());\n\n        if (!debug_dump.IsNull())\n        {\n           log::Server()->debug(\"context read from redis: {}.\", debug_dump.ToString());\n        }\n    }\n    catch (std::string const& s)\n    {\n        log::Server()->error(\"Redis handle {} result exception. {}\", get_async_handler_action_name(aha), s);\n    }\n    catch (char const* s)\n    {\n        log::Server()->error(\"Redis handle {} result exception. {}\", get_async_handler_action_name(aha), s);\n    }\n    catch (...)\n    {\n        log::Server()->error(\"Redis handle {} result unknown exception.\", get_async_handler_action_name(aha));\n    }\n}\n\nvoid RedisClient::on_connect_finished(std::function<void (boost::system::error_code const& ec)> on\n                                      , boost::system::error_code const& ec)\n{\n    _connect_status = (!ec) ? is_connected : not_connect;\n\n    if (ec)\n    {\n        _connect_status = not_connect;\n        log::Server()->error(\"Connect to redis server fail. {}\", ec.message());\n    }\n    else\n    {\n        if (_reconnect_count > 0)\n        {\n            log::Server()->info(\"Reconnect to redis server success, after {} time(s).\", _reconnect_count);\n            _reconnect_count = 0;\n        }\n\n        _connect_status = is_connected;\n    }\n\n    try_on_redis_handler(on, std::move(ec), AsyncHandlerAction::on_async_connect);\n\n    if (ec && (_error_handle_policy == RedisClientErrorHandlePolicy::auto_reconnect))\n    {\n        start_reconnect_timer(on);\n    }\n}\n\nbool RedisClient::start_reconnect_timer(std::function<void (boost::system::error_code const& ec)> on)\n{\n    auto seconds = redis_server_reconnect_interval_seconds(++_reconnect_count);\n\n    boost::system::error_code timer_ec;\n    _reconnect_timer.expires_from_now(boost::posix_time::seconds(seconds), timer_ec);\n\n    if (timer_ec)\n    {\n        log::Server()->error(\"Set reconnect redis server timer expires time fail. {}\", timer_ec.message());\n        return false;\n    }\n\n    _reconnect_timer.async_wait([this, on](boost::system::error_code const & ec)\n    {\n        if (ec)\n        {\n            log::Server()->error(\"Start reconnect redis server timer fail. {}\", ec.message());\n            return;\n        }\n\n        do_async_connect(on);\n    });\n\n    return true;\n}\n\nvoid RedisClient::Disconnect()\n{\n    if (IsConnected())\n    {\n        do_disconnect();\n    }\n    else\n    {\n        boost::system::error_code ec;\n        _reconnect_timer.cancel(ec);\n    }\n}\n\nvoid RedisClient::do_disconnect()\n{\n    boost::system::error_code ec;\n    _socket.cancel(ec);\n    _socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec);\n    _socket.close(ec);\n    _connect_status = not_connect;\n}\n\n#ifdef _DEBUG_REDIS_NEED_SYNC_OPERATOR_\nbool RedisClient::do_sync_connect()\n{\n    _connect_status = is_connectting;\n\n    boost::system::error_code ec;\n\n    boost::asio::ip::tcp::endpoint end_point(boost::asio::ip::address::from_string(_host), _port);\n\n    _socket.connect(end_point, ec);\n\n    if (ec)\n    {\n        _connect_status = not_connect;\n        return false;\n    }\n\n    _connect_status = is_connected;\n    return true;\n}\n\nRedisValue RedisClient::CommandSync(std::string cmd, std::deque<RedisBuffer> args)\n{\n    assert(!cmd.empty());\n\n    args.emplace_front(std::move(cmd));\n    auto send_data = MakeCommand(args);\n\n    boost::system::error_code ec;\n    boost::asio::write(_socket, boost::asio::buffer(send_data), ec);\n\n    if (ec)\n    {\n        return RedisValue(ec.message(), RedisValue::ErrorTag());\n    }\n\n    RedisParser parser;\n\n    std::size_t beg = 0;\n    bool completed = false;\n\n    std::string read_data;\n    read_data.reserve(_read_buffer_size_ << 1);\n\n    while (!completed)\n    {\n        char tmp_buf[_read_buffer_size_];\n        std::size_t read_size = _socket.read_some(boost::asio::buffer(tmp_buf, _read_buffer_size_), ec);\n\n        if (ec)\n        {\n            return RedisValue(ec.message(), RedisValue::ErrorTag());\n        }\n\n        if (read_size > 0)\n        {\n            read_data.append(tmp_buf, read_size);\n            size_t end = read_data.size();\n\n            while (!completed && (beg < end))\n            {\n                auto result = parser.Parse(read_data.c_str() + beg, end - beg);\n\n                switch (result.second)\n                {\n                    case RedisParser::Completed:\n                        completed = true;\n                        break;\n\n                    case RedisParser::Incompleted:\n                        beg += result.first;\n                        break;\n\n                    default :\n                        return RedisValue(\"parse fail\", RedisValue::ErrorTag());\n                }\n            }\n        }\n    }\n\n    return (completed) ? parser.Result() : RedisValue(\"parse fail\", RedisValue::ErrorTag());\n}\n\nbool RedisClient::ConnectSync(std::string const& host, unsigned short port)\n{\n    if (IsConnected() || IsConnectting())\n    {\n        return true;\n    }\n\n    _host = host;\n    _port = port;\n\n    return do_sync_connect();\n}\n#endif //_DEBUG_REDIS_NEED_SYNC_OPERATOR_\n\nvoid RedisClient::Command(std::string cmd, std::deque<RedisBuffer> args,\n                          std::function<void(RedisValue value)> on)\n{\n    assert(!cmd.empty());\n\n    args.emplace_front(std::move(cmd));\n    auto command_data = MakeCommand(args);\n\n    bool is_stopped_because_empty = _command_queue.empty();\n    _command_queue.emplace(command_data, on);\n\n    if (is_stopped_because_empty)\n    {\n        start_async_write();\n    }\n}\n\nvoid RedisClient::start_async_write()\n{\n    if (_command_queue.empty())\n    {\n        return;\n    }\n\n    boost::asio::async_write(_socket, boost::asio::buffer(_command_queue.front().first)\n                             , [this](boost::system::error_code const & ec,  std::size_t /*bytes*/)\n    {\n        assert(!_command_queue.empty());\n\n        auto node(std::move(_command_queue.front()));\n        auto on = node.second;\n\n        if (ec)\n        {\n            RedisValue error_value(ec.message(), RedisValue::ErrorTag());\n            try_on_redis_handler(on, std::move(error_value), AsyncHandlerAction::on_async_write);\n            _command_queue.pop();\n\n            if (_error_handle_policy == RedisClientErrorHandlePolicy::auto_reconnect)\n            {\n                Reconnect();\n            }\n\n            return;\n        }\n\n        start_aysnc_read_and_parse(on);\n    });\n\n}\n\nvoid RedisClient::start_aysnc_read_and_parse(std::function<void(RedisValue value)> on)\n{\n    if (!_reply_buf.empty())\n    {\n        if (_reply_buf.size() <= _reply_parse_beg)\n        {\n            _reply_buf.clear();\n        }\n        else\n        {\n            _reply_buf = _reply_buf.substr(_reply_parse_beg);\n        }\n    }\n\n    _reply_parse_beg = 0;\n\n    std::shared_ptr<RedisParser> parser(new RedisParser);\n    do_async_read_and_parse(parser, on);\n}\n\nvoid RedisClient::do_async_read_and_parse(std::shared_ptr<RedisParser> parser,\n                                          std::function<void(RedisValue value)> on)\n{\n    _socket.async_read_some(boost::asio::buffer(_tmp_read_buf, _read_buffer_size_)\n                            , [this, parser, on](boost::system::error_code const & ec, size_t size)\n    {\n        if (ec)\n        {\n            RedisValue error_value(ec.message(), RedisValue::ErrorTag());\n            try_on_redis_handler(on, std::move(error_value), AsyncHandlerAction::on_async_read);\n            _command_queue.pop();\n\n            return;\n        }\n\n        if (size > 0)\n        {\n            _reply_buf.append(_tmp_read_buf, size);\n            size_t end = _reply_buf.size();\n\n            bool completed = false, error = false;\n\n            while (!completed && !error && (_reply_parse_beg < end))\n            {\n                auto result = parser->Parse(_reply_buf.c_str() + _reply_parse_beg, end - _reply_parse_beg);\n                _reply_parse_beg += result.first;\n\n                switch (result.second)\n                {\n                    case RedisParser::Completed:\n                        completed = true;\n                        break;\n\n                    case RedisParser::Incompleted:\n                        break;\n\n                    default :\n                        error = true;\n                        break;\n                }\n            }\n\n            if (completed)\n            {\n                RedisValue value = parser->Result();\n                try_on_redis_handler(on, std::move(value), AsyncHandlerAction::on_reply_parse);\n                _command_queue.pop();\n                start_async_write();\n                return;\n            }\n\n            if (error)\n            {\n                RedisValue error_value(\"parse error. \" + _reply_buf, RedisValue::ErrorTag());\n                try_on_redis_handler(on, std::move(error_value), AsyncHandlerAction::on_reply_parse);\n                _command_queue.pop();\n                start_async_write();\n                return;\n            }\n        } //read size (more than 0) byte.\n\n        do_async_read_and_parse(parser, on);\n    });\n}\n\n} // namespace da4qi4\n\n"
  },
  {
    "path": "src/redis-client/redis_command.cpp",
    "content": "#include \"daqi/redis-client/redis_command.hpp\"\n\n#include <cstring>\n#include <string>\n\n#include <boost/variant.hpp>\n\nnamespace da4qi4\n{\n\nnamespace\n{\n\nstatic const char crlf[] = {'\\r', '\\n'};\n\nvoid bufferAppend(std::vector<char>& vec, std::string const& s);\nvoid bufferAppend(std::vector<char>& vec, char c);\n\ntemplate<std::size_t size>\nvoid bufferAppend(std::vector<char>& vec, const char (&s)[size]);\n\nvoid bufferAppend(std::vector<char>& vec, RedisBuffer const& buf)\n{\n    bufferAppend(vec, buf.data);\n}\n\nvoid bufferAppend(std::vector<char>& vec, std::string const& s)\n{\n    vec.insert(vec.end(), s.begin(), s.end());\n}\n\nvoid bufferAppend(std::vector<char>& vec, char c)\n{\n    vec.resize(vec.size() + 1);\n    vec[vec.size() - 1] = c;\n}\n\ntemplate<size_t size>\nvoid bufferAppend(std::vector<char>& vec, const char (&s)[size])\n{\n    vec.insert(vec.end(), s, s + size);\n}\n\n} //namespace\n\n\nstd::vector<char> MakeCommand(const std::deque<RedisBuffer>& items)\n{\n    std::vector<char> result;\n    result.reserve(128);\n\n    bufferAppend(result, '*');\n    bufferAppend(result, std::to_string(items.size()));\n    bufferAppend<>(result, crlf);\n\n    for (const auto& item : items)\n    {\n        bufferAppend(result, '$');\n        bufferAppend(result, std::to_string(item.size()));\n        bufferAppend<>(result, crlf);\n        bufferAppend(result, item);\n        bufferAppend<>(result, crlf);\n    }\n\n    return result;\n}\n\n} // namespace da4qi4\n"
  },
  {
    "path": "src/redis-client/redis_parser.cpp",
    "content": "#include \"daqi/redis-client/redis_parser.hpp\"\n\n#include <cassert>\n#include <sstream>\n\nnamespace da4qi4\n{\n\nRedisParser::RedisParser()\n    : bulkSize(0)\n{\n    buf.reserve(64);\n}\n\nstd::pair<size_t, RedisParser::ParseResult> RedisParser::Parse(const char* ptr, size_t size)\n{\n    return RedisParser::parse_chunk(ptr, size);\n}\n\nstd::pair<size_t, RedisParser::ParseResult> RedisParser::parse_chunk(const char* ptr, size_t size)\n{\n    size_t position = 0;\n    State state = Start;\n\n    if (!states.empty())\n    {\n        state = states.top();\n        states.pop();\n    }\n\n    while (position < size)\n    {\n        char c = ptr[position++];\n\n        switch (static_cast<int>(state))\n        {\n            case StartArray:\n            case Start:\n                buf.clear();\n\n                switch (c)\n                {\n                    case stringReply:\n                        state = String;\n                        break;\n\n                    case errorReply:\n                        state = ErrorString;\n                        break;\n\n                    case integerReply:\n                        state = Integer;\n                        break;\n\n                    case bulkReply:\n                        state = BulkSize;\n                        bulkSize = 0;\n                        break;\n\n                    case arrayReply:\n                        state = ArraySize;\n                        break;\n\n                    default:\n                        return std::make_pair(position, Error);\n                }\n\n                break;\n\n            case String:\n                if (c == '\\r')\n                {\n                    state = StringLF;\n                }\n                else if (is_char(c) && !is_control(c))\n                {\n                    buf.push_back(c);\n                }\n                else\n                {\n                    std::stack<State>().swap(states);\n                    return std::make_pair(position, Error);\n                }\n\n                break;\n\n            case ErrorString:\n                if (c == '\\r')\n                {\n                    state = ErrorLF;\n                }\n                else if (is_char(c) && !is_control(c))\n                {\n                    buf.push_back(c);\n                }\n                else\n                {\n                    std::stack<State>().swap(states);\n                    return std::make_pair(position, Error);\n                }\n\n                break;\n\n            case BulkSize:\n                if (c == '\\r')\n                {\n                    if (buf.empty())\n                    {\n                        std::stack<State>().swap(states);\n                        return std::make_pair(position, Error);\n                    }\n                    else\n                    {\n                        state = BulkSizeLF;\n                    }\n                }\n                else if (isdigit(c) || c == '-')\n                {\n                    buf.push_back(c);\n                }\n                else\n                {\n                    std::stack<State>().swap(states);\n                    return std::make_pair(position, Error);\n                }\n\n                break;\n\n            case StringLF:\n                if (c == '\\n')\n                {\n                    state = Start;\n                    redisValue = RedisValue(buf);\n                }\n                else\n                {\n                    std::stack<State>().swap(states);\n                    return std::make_pair(position, Error);\n                }\n\n                break;\n\n            case ErrorLF:\n                if (c == '\\n')\n                {\n                    state = Start;\n                    RedisValue::ErrorTag tag;\n                    redisValue = RedisValue(buf, tag);\n                }\n                else\n                {\n                    std::stack<State>().swap(states);\n                    return std::make_pair(position, Error);\n                }\n\n                break;\n\n            case BulkSizeLF:\n                if (c == '\\n')\n                {\n                    bulkSize = buf_to_long(buf.data(), buf.size());\n                    buf.clear();\n\n                    if (bulkSize == -1)\n                    {\n                        state = Start;\n                        redisValue = RedisValue(); // Nil\n                    }\n                    else if (bulkSize == 0)\n                    {\n                        state = BulkCR;\n                    }\n                    else if (bulkSize < 0)\n                    {\n                        std::stack<State>().swap(states);\n                        return std::make_pair(position, Error);\n                    }\n                    else\n                    {\n                        buf.reserve(static_cast<std::size_t>(bulkSize));\n\n                        long int available = static_cast<long>(size - position);\n                        long int canRead = std::min(bulkSize, available);\n\n                        if (canRead > 0)\n                        {\n                            buf.assign(ptr + position, ptr + position + canRead);\n                            position += static_cast<unsigned long>(canRead);\n                            bulkSize -= canRead;\n                        }\n\n\n                        if (bulkSize > 0)\n                        {\n                            state = Bulk;\n                        }\n                        else\n                        {\n                            state = BulkCR;\n                        }\n                    }\n                }\n                else\n                {\n                    std::stack<State>().swap(states);\n                    return std::make_pair(position, Error);\n                }\n\n                break;\n\n            case Bulk:\n            {\n                assert(bulkSize > 0);\n\n                long int available = static_cast<long int>(size - position + 1);\n                long int canRead = std::min(available, bulkSize);\n\n                buf.insert(buf.end(), ptr + position - 1, ptr + position - 1 + canRead);\n                bulkSize -= canRead;\n                position += static_cast<unsigned long>(canRead - 1);\n\n                if (bulkSize == 0)\n                {\n                    state = BulkCR;\n                }\n\n                break;\n            }\n\n            case BulkCR:\n                if (c == '\\r')\n                {\n                    state = BulkLF;\n                }\n                else\n                {\n                    std::stack<State>().swap(states);\n                    return std::make_pair(position, Error);\n                }\n\n                break;\n\n            case BulkLF:\n                if (c == '\\n')\n                {\n                    state = Start;\n                    redisValue = RedisValue(buf);\n                }\n                else\n                {\n                    std::stack<State>().swap(states);\n                    return std::make_pair(position, Error);\n                }\n\n                break;\n\n            case ArraySize:\n                if (c == '\\r')\n                {\n                    if (buf.empty())\n                    {\n                        std::stack<State>().swap(states);\n                        return std::make_pair(position, Error);\n                    }\n                    else\n                    {\n                        state = ArraySizeLF;\n                    }\n                }\n                else if (isdigit(c) || c == '-')\n                {\n                    buf.push_back(c);\n                }\n                else\n                {\n                    std::stack<State>().swap(states);\n                    return std::make_pair(position, Error);\n                }\n\n                break;\n\n            case ArraySizeLF:\n                if (c == '\\n')\n                {\n                    int64_t arraySize = buf_to_long(buf.data(), buf.size());\n                    std::vector<RedisValue> array;\n\n                    if (arraySize == -1)\n                    {\n                        state = Start;\n                        redisValue = RedisValue();  // Nil value\n                    }\n                    else if (arraySize == 0)\n                    {\n                        state = Start;\n                        redisValue = RedisValue(std::move(array));  // Empty array\n                    }\n                    else if (arraySize < 0)\n                    {\n                        std::stack<State>().swap(states);\n                        return std::make_pair(position, Error);\n                    }\n                    else\n                    {\n                        array.reserve(static_cast<std::size_t>(arraySize));\n                        arraySizes.push(arraySize);\n                        arrayValues.push(std::move(array));\n\n                        state = StartArray;\n                    }\n                }\n                else\n                {\n                    std::stack<State>().swap(states);\n                    return std::make_pair(position, Error);\n                }\n\n                break;\n\n            case Integer:\n                if (c == '\\r')\n                {\n                    if (buf.empty())\n                    {\n                        std::stack<State>().swap(states);\n                        return std::make_pair(position, Error);\n                    }\n                    else\n                    {\n                        state = IntegerLF;\n                    }\n                }\n                else if (isdigit(c) || c == '-')\n                {\n                    buf.push_back(c);\n                }\n                else\n                {\n                    std::stack<State>().swap(states);\n                    return std::make_pair(position, Error);\n                }\n\n                break;\n\n            case IntegerLF:\n                if (c == '\\n')\n                {\n                    int64_t value = buf_to_long(buf.data(), buf.size());\n\n                    buf.clear();\n                    redisValue = RedisValue(value);\n                    state = Start;\n                }\n                else\n                {\n                    std::stack<State>().swap(states);\n                    return std::make_pair(position, Error);\n                }\n\n                break;\n\n            default:\n                std::stack<State>().swap(states);\n                return std::make_pair(position, Error);\n        }\n\n\n        if (state == Start)\n        {\n            if (!arraySizes.empty())\n            {\n                assert(arraySizes.size() > 0);\n                arrayValues.top().GetArray().push_back(redisValue);\n\n                while (!arraySizes.empty() && --arraySizes.top() == 0)\n                {\n                    arraySizes.pop();\n                    redisValue = std::move(arrayValues.top());\n                    arrayValues.pop();\n\n                    if (!arraySizes.empty())\n                    {\n                        arrayValues.top().GetArray().push_back(redisValue);\n                    }\n                }\n            }\n\n\n            if (arraySizes.empty())\n            {\n                // done\n                break;\n            }\n        }\n    }\n\n    if (arraySizes.empty() && state == Start)\n    {\n        return std::make_pair(position, Completed);\n    }\n    else\n    {\n        states.push(state);\n        return std::make_pair(position, Incompleted);\n    }\n}\n\nRedisValue RedisParser::Result()\n{\n    return std::move(redisValue);\n}\n\nlong int RedisParser::buf_to_long(const char* str, size_t size)\n{\n    long int value = 0;\n    bool sign = false;\n\n    if (str == nullptr || size == 0)\n    {\n        return 0;\n    }\n\n    if (*str == '-')\n    {\n        sign = true;\n        ++str;\n        --size;\n\n        if (size == 0)\n        {\n            return 0;\n        }\n    }\n\n    for (const char* end = str + size; str != end; ++str)\n    {\n        char c = *str;\n\n        // char must be valid, already checked in the parser\n        assert(c >= '0' && c <= '9');\n\n        value = value * 10;\n        value += c - '0';\n    }\n\n    return sign ? -value : value;\n}\n\n} // namespace da4qi4\n"
  },
  {
    "path": "src/redis-client/redis_value.cpp",
    "content": "#include \"daqi/redis-client/redis_value.hpp\"\n\n#include <string.h>\n\nnamespace da4qi4\n{\n\nRedisValue::RedisValue()\n    : _value(NullTag()), _error(false)\n{\n}\n\nRedisValue::RedisValue(RedisValue&& other)\n    : _value(std::move(other._value)), _error(other._error)\n{\n}\n\nRedisValue::RedisValue(int64_t i)\n    : _value(i), _error(false)\n{\n}\n\nRedisValue::RedisValue(const char* s)\n    : _value(std::vector<char>(s, s + strlen(s))), _error(false)\n{\n}\n\nRedisValue::RedisValue(std::string const& s)\n    : _value(std::vector<char>(s.begin(), s.end())), _error(false)\n{\n}\n\nRedisValue::RedisValue(std::vector<char> buf)\n    : _value(std::move(buf)), _error(false)\n{\n}\n\nRedisValue::RedisValue(std::vector<char> buf, struct ErrorTag)\n    : _value(std::move(buf)), _error(true)\n{\n}\n\nRedisValue::RedisValue(std::string const& custom_error, struct ErrorTag)\n    : _value(std::vector<char>(custom_error.cbegin(), custom_error.cend()))\n    , _error(true)\n{\n\n}\n\nRedisValue::RedisValue(std::vector<RedisValue> array)\n    : _value(std::move(array)), _error(false)\n{\n}\n\nstd::vector<RedisValue> RedisValue::ToArray() const\n{\n    return cast_to<std::vector<RedisValue>>();\n}\n\nstd::string RedisValue::ToString() const\n{\n    const std::vector<char>& buf = ToByteArray();\n    return std::string(buf.begin(), buf.end());\n}\n\nstd::vector<char> RedisValue::ToByteArray() const\n{\n    return cast_to<std::vector<char>>();\n}\n\nint64_t RedisValue::ToInt() const\n{\n    return cast_to<int64_t>();\n}\n\nstd::string RedisValue::Inspect() const\n{\n    if (IsError())\n    {\n        static std::string err = \"_error: \";\n        std::string result;\n\n        result = err;\n        result += ToString();\n\n        return result;\n    }\n    else if (IsNull())\n    {\n        static std::string null = \"(null)\";\n        return null;\n    }\n    else if (IsInt())\n    {\n        return std::to_string(ToInt());\n    }\n    else if (IsString())\n    {\n        return ToString();\n    }\n    else\n    {\n        std::vector<RedisValue> _values = ToArray();\n        std::string result = \"[\";\n\n        if (_values.empty() == false)\n        {\n            for (size_t i = 0; i < _values.size(); ++i)\n            {\n                result += _values[i].Inspect();\n                result += \", \";\n            }\n\n            result.resize(result.size() - 1);\n            result[result.size() - 1] = ']';\n        }\n        else\n        {\n            result += ']';\n        }\n\n        return result;\n    }\n}\n\nbool RedisValue::IsOk() const\n{\n    return !IsError();\n}\n\nbool RedisValue::IsError() const\n{\n    return _error;\n}\n\nbool RedisValue::IsNull() const\n{\n    return type_eq<NullTag>();\n}\n\nbool RedisValue::IsInt() const\n{\n    return type_eq<int64_t>();\n}\n\nbool RedisValue::IsString() const\n{\n    return type_eq<std::vector<char>>();\n}\n\nbool RedisValue::IsByteArray() const\n{\n    return type_eq<std::vector<char>>();\n}\n\nbool RedisValue::IsArray() const\n{\n    return type_eq< std::vector<RedisValue>>();\n}\n\nstd::vector<char>& RedisValue::GetByteArray()\n{\n    assert(IsByteArray());\n    return boost::get<std::vector<char>>(_value);\n}\n\nconst std::vector<char>& RedisValue::GetByteArray() const\n{\n    assert(IsByteArray());\n    return boost::get<std::vector<char>>(_value);\n}\n\nstd::vector<RedisValue>& RedisValue::GetArray()\n{\n    assert(IsArray());\n    return boost::get<std::vector<RedisValue>>(_value);\n}\n\nconst std::vector<RedisValue>& RedisValue::GetArray() const\n{\n    assert(IsArray());\n    return boost::get<std::vector<RedisValue>>(_value);\n}\n\nbool RedisValue::operator == (const RedisValue& rhs) const\n{\n    return _value == rhs._value;\n}\n\nbool RedisValue::operator != (const RedisValue& rhs) const\n{\n    return !(_value == rhs._value);\n}\n\n} // namespace da4qi4\n"
  },
  {
    "path": "src/rediscli_pool.cpp",
    "content": "#include \"daqi/rediscli_pool.hpp\"\n\n#include \"daqi/def/log_def.hpp\"\n#include \"daqi/utilities/asio_utilities.hpp\"\n\n#include \"daqi/server_engine.hpp\"\n\nnamespace da4qi4\n{\n\nvoid RedisClientPool::CreateClients(IOContextPool* ioc_pool\n                                    , const std::string& host, unsigned short port)\n{\n    for (std::size_t i = 0; i < ioc_pool->Size(); ++i)\n    {\n        auto client = RedisClientPtr(new RedisClient(ioc_pool->GetIOContextByIndex(i)\n                                                     , RedisClientErrorHandlePolicy::auto_reconnect));\n        _clients.push_back(client);\n        client->Connect(std::bind(&RedisClientPool::on_connect_finished\n                                  , this, i\n                                  , std::placeholders::_1), host, port);\n    }\n}\n\nvoid RedisClientPool::on_connect_finished(std::size_t index, boost::system::error_code const& ec)\n{\n    if (!ec)\n    {\n        log::Server()->info(\"Redis server connected. (client {}).\", index);\n    }\n    else\n    {\n        log::Server()->error(\"Redis server connect fail. (client {}).\", index);\n    }\n}\n\nRedisClientPool& RedisPool()\n{\n    static RedisClientPool _pool;\n    return _pool;\n}\n\nvoid RedisClientPool::Stop()\n{\n    for (auto p : _clients)\n    {\n        if (p->IsConnected())\n        {\n            p->Disconnect();\n        }\n    }\n}\n\nvoid RedisClientPool::clear()\n{\n    _clients.clear();\n}\n\n} //nampespace da4qi4\n"
  },
  {
    "path": "src/request.cpp",
    "content": "#include \"daqi/request.hpp\"\n\n#include <iomanip>\n#include <sstream>\n#include <fstream>\n#include <algorithm>\n\n#include <boost/uuid/uuid_generators.hpp>\n#include <boost/uuid/uuid_io.hpp>\n\n#include \"daqi/def/log_def.hpp\"\n\n#include \"daqi/utilities/string_utilities.hpp\"\n#include \"daqi/utilities/file_utilities.hpp\"\n#include \"daqi/utilities/html_utilities.hpp\"\n#include \"daqi/utilities/http_utilities.hpp\"\n\n#include \"daqi/application.hpp\"\n\nnamespace da4qi4\n{\n\nvoid RoutingPathParameters::InitParameters(std::vector<std::string> const& names\n                                           , std::vector<std::string> const& values)\n{\n    _parameters.clear();\n\n    for (size_t i = 0; i < names.size(); ++i)\n    {\n        std::string value = (i < values.size()) ? values[i] : Utilities::theEmptyString;\n        _parameters.insert(std::make_pair(names[i], value));\n    }\n}\n\nbool RoutingPathParameters::IsExists(std::string const& name) const\n{\n    return _parameters.find(name) != _parameters.cend();\n}\n\nstd::string const& RoutingPathParameters::Get(std::string const& name) const\n{\n    auto it = _parameters.find(name);\n    return (it != _parameters.cend() ? it->second : Utilities::theEmptyString);\n}\n\nOptionalStringRefConst RoutingPathParameters::TryGet(std::string const& name) const\n{\n    auto it = _parameters.find(name);\n    return (it != _parameters.cend() ? OptionalStringRefConst(it->second)\n            : OptionalStringRefConst(NoneObject));\n}\n\nMultiPart::MultiPart(MultiPart const& o)\n    : _headers(o._headers), _data(o._data)\n{\n}\n\nMultiPart::MultiPart(MultiPart&& o)\n    : _headers(std::move(o._headers)), _data(std::move(o._data))\n{\n}\n\nbool MultiPart::IsExistsHeader(std::string const& field) const\n{\n    return Utilities::IsExistsHeader(_headers, field);\n}\n\nstd::string const& MultiPart::GetHeader(std::string const& field) const\n{\n    return Utilities::GetHeader(_headers, field);\n}\n\nOptionalStringRefConst MultiPart::TryGetHeader(std::string const& field) const\n{\n    return Utilities::TryGetHeader(_headers, field);\n}\n\nvoid MultiPart::AppendHeader(std::string&& field, std::string&& value)\n{\n    auto it = _headers.find(field);\n\n    if (it != _headers.end())\n    {\n        it->second = std::move(value);\n    }\n    else\n    {\n        _headers.insert(std::make_pair(std::move(field), std::move(value)));\n    }\n}\n\nbool Request::IsExistsHeader(std::string const& field) const\n{\n    return Utilities::IsExistsHeader(_headers, field);\n}\n\nstd::string const& Request::GetHeader(std::string const& field) const\n{\n    return Utilities::GetHeader(_headers, field);\n}\n\nOptionalStringRefConst Request::TryGetHeader(std::string const& field) const\n{\n    return Utilities::TryGetHeader(_headers, field);\n}\n\nbool Request::IsExistsUrlParameter(std::string const& name) const\n{\n    return Utilities::IsExistsHeader(_url.parameters, name);\n}\n\nstd::string const& Request::GetUrlParameter(std::string const& name) const\n{\n    return Utilities::GetHeader(_url.parameters, name);\n}\n\nOptionalStringRefConst Request::TryGetUrlParameter(std::string const& name) const\n{\n    return Utilities::TryGetHeader(_url.parameters, name);\n}\n\nbool UploadFile::SaveTo(std::string const& dst_filename)\n{\n    if (_status == no_found)\n    {\n        return false;\n    }\n\n    std::ofstream ofs(dst_filename);\n\n    if (!ofs)\n    {\n        return false;\n    }\n\n    if (_status == in_stream)\n    {\n        if (!_stream)\n        {\n            return false;\n        }\n\n        size_t const tmp_buf_size = 2048;\n        char buf[tmp_buf_size];\n\n        while (_stream)\n        {\n            _stream.read(buf, tmp_buf_size);\n            std::size_t rd = static_cast<std::size_t>(_stream.gcount());\n\n            if (rd > 0)\n            {\n                ofs.write(buf, static_cast<std::streamsize>(rd));\n            }\n        }\n\n        _stream.close();\n    }\n    else // in_memory\n    {\n        ofs.write(_memory.c_str(), static_cast<std::streamsize>(_memory.size()));\n        _memory.clear();\n    }\n\n    ofs.close();\n    return true;\n}\n\nbool UploadFile::ToMemory()\n{\n    if ((_status == in_stream && !_stream) || (_status == no_found))\n    {\n        return false;\n    }\n\n    if (_status == in_memory)\n    {\n        return true;\n    }\n\n    size_t const tmp_buf_size = 2048;\n    char buf[tmp_buf_size];\n    _memory.clear();\n    _memory.reserve(tmp_buf_size << 1);\n\n    while (_stream)\n    {\n        _stream.read(buf, tmp_buf_size);\n        std::size_t rd = static_cast<std::size_t>(_stream.gcount());\n\n        if (rd > 0)\n        {\n            _memory.append(buf, rd);\n        }\n    }\n\n    _stream.close();\n    _status = in_memory;\n\n    return true;\n}\n\nbool UploadFile::ToStream(std::string const& temp_filename)\n{\n    if (_status == no_found)\n    {\n        return false;\n    }\n\n    if (_status == in_stream)\n    {\n        return true;\n    }\n\n    std::string err;\n\n    if (!Utilities::SaveDataToFile(this->_memory, temp_filename, err))\n    {\n        log::Server()->error(\"Try create temp file for upload fail. {}. {}. {}.\"\n                             , temp_filename, _src_filename, err);\n        return false;\n    }\n\n    std::ofstream ofs(temp_filename.c_str(), std::ios_base::out | std::ios_base::binary);\n\n    if (_stream.is_open())\n    {\n        _stream.close();\n    }\n\n    _stream.open(temp_filename.c_str(), std::ios_base::in | std::ios_base::binary);\n\n    if (!_stream)\n    {\n        log::Server()->error(\"Try open temp file for upload fail. {}. {}.\"\n                             , temp_filename, _src_filename);\n        return false;\n    }\n\n    _saved_filename = temp_filename;\n    return  true;\n}\n\nextern fs::path MakeUploadFileTemporaryName(std::string const& ext, std::string const& dir);\n\nbool UploadFile::ToStream(const Application& app, std::string const& ext)\n{\n    if (_status == no_found)\n    {\n        return false;\n    }\n\n    if (_status == in_stream)\n    {\n        return true;\n    }\n\n    auto upload_root = app.GetUploadRoot().string();\n\n    if (upload_root.empty())\n    {\n        errorcode ec;\n        upload_root = fs::temp_directory_path(ec).native();\n\n        if (ec)\n        {\n            log::Server()->error(\"Get system temp file path fail. {}.\", ec.message());\n            return false;\n        }\n    }\n\n    auto templ_file_path = MakeUploadFileTemporaryName(ext, upload_root);\n\n    if (templ_file_path.empty())\n    {\n        return false;\n    }\n\n    return ToStream(templ_file_path.native());\n}\n\nbool Request::IsExistsFile(std::string const& field_name) const\n{\n    for (auto const& item : _formdata)\n    {\n        if (item.IsFile() && Utilities::iEquals(item.name, field_name))\n        {\n            return true;\n        }\n    }\n\n    return false;\n}\n\nbool UploadFile::FromFormDataItem(FormDataItem const& item)\n{\n    _field_name = item.name;\n    _content_type = item.content_type;\n\n    if (item.IsSavedFile())\n    {\n        _status = UploadFile::in_stream;\n        _stream.open(item.GetSavedFileTemporaryName(), std::ios_base::in | std::ios_base::binary);\n        _src_filename = item.filename;\n        _saved_filename = item.GetSavedFileTemporaryName();\n        return true;\n    }\n\n    if (item.IsFile()) //but no saved still\n    {\n        _status = UploadFile::in_memory;\n        _memory = item.data;\n        _src_filename = item.filename;\n        return true;\n    }\n\n    _status = no_found;\n    return false;\n}\n\nUploadFile Request::GetFile(std::string const& field_name) const\n{\n    UploadFile uf;\n\n    for (auto const& item : _formdata)\n    {\n        if (Utilities::iEquals(item.name, field_name) && uf.FromFormDataItem(item))\n        {\n            return uf;\n        }\n    }\n\n    return uf;\n}\n\nbool Request::IsExistsCookie(std::string const& name) const\n{\n    return Utilities::IsExistsHeader(_cookies, name);\n}\n\nstd::string const& Request::GetCookie(std::string const& name) const\n{\n    return Utilities::GetHeader(_cookies, name);\n}\n\nOptionalStringRefConst Request::TryGetCookie(std::string const& name) const\n{\n    return Utilities::TryGetHeader(_cookies, name);\n}\n\nbool Request::IsExistsFormData(std::string const& name) const\n{\n    for (auto const& fd : _formdata)\n    {\n        if (Utilities::iEquals(fd.name, name))\n        {\n            return true;\n        }\n    }\n\n    return false;\n}\n\nstd::string const& Request::GetFormData(std::string const& name) const\n{\n    for (auto const& fd : _formdata)\n    {\n        if (Utilities::iEquals(fd.name, name))\n        {\n            return fd.data;\n        }\n    }\n\n    return Utilities::theEmptyString;\n}\n\nOptionalStringRefConst Request::TryGetFormData(std::string const& name) const\n{\n    for (auto const& fd : _formdata)\n    {\n        if (Utilities::iEquals(fd.name, name))\n        {\n            return OptionalStringRefConst(fd.data);\n        }\n    }\n\n    return OptionalStringRefConst(NoneObject);\n}\n\nstd::string const& Request::GetParameter(std::string const& name) const\n{\n    ParameterSrc src = IsExistsParameter(name);\n\n    switch (src)\n    {\n        case fromUrl:\n            return GetUrlParameter(name);\n\n        case fromPath:\n            return GetPathParameter(name);\n\n        case fromForm:\n            return GetFormData(name);\n\n        case fromHeader:\n            return GetHeader(name);\n\n        case fromCookie:\n            return GetCookie(name);\n\n        case fromUnknown:\n            break;\n    }\n\n    return Utilities::theEmptyString;\n}\n\nOptionalStringRefConst Request::TryGetParameter(std::string const& name) const\n{\n    ParameterSrc src = IsExistsParameter(name);\n\n    switch (src)\n    {\n        case fromUrl:\n            return TryGetUrlParameter(name);\n\n        case fromPath:\n            return TryGetPathParameter(name);\n\n        case fromForm:\n            return TryGetFormData(name);\n\n        case fromHeader:\n            return TryGetHeader(name);\n\n        case fromCookie:\n            return TryGetCookie(name);\n\n        case fromUnknown:\n            break;\n    }\n\n    return OptionalStringRefConst(NoneObject);\n}\n\n\nbool Request::ParseUrl(std::string&& url)\n{\n    return _url.Parse(std::move(url));\n}\n\nvoid Request::AppendHeader(std::string&& field, std::string&& value)\n{\n    auto it = _headers.find(field);\n\n    if (it != _headers.end())\n    {\n        it->second = std::move(value);\n    }\n    else\n    {\n        _headers.insert(std::make_pair(std::move(field), std::move(value)));\n    }\n}\n\nvoid Request::Reset()\n{\n    _url.Clear();\n    _method = HTTP_GET;\n    _headers.clear();\n    _version_major = _version_minor = 0;\n    _content_length = 0;\n    _flags = 0;\n    _addition_flags.reset();\n\n    if (_body.length() < 1024 * 10)\n    {\n        _body.clear();\n    }\n    else\n    {\n        std::string tmp;\n        _body.swap(tmp);\n        _body.reserve(1024 * 2);\n    }\n\n    _boundary.clear();\n    _multiparts.clear();\n    _cookies.clear();\n    _formdata.clear();\n    _path_parameters.Clear();\n}\n\nvoid Request::ParseContentType()\n{\n    auto content_type = this->TryGetHeader(\"Content-Type\");\n\n    if (content_type)\n    {\n        auto beg = content_type->find(\"multipart/\");\n\n        if (beg != std::string::npos)\n        {\n            constexpr int len_of_multipart_flag = 10; // length of \"multipart/\"\n            constexpr int len_of_boundary_flag = 9;   // length of \"boundary=\"\n            this->MarkMultiPart(true);\n\n            if (content_type->find(\"form-data\", beg + len_of_multipart_flag) != std::string::npos)\n            {\n                this->MarkFormData(true);\n            }\n\n            auto pos = content_type->find(\"boundary=\", beg + len_of_multipart_flag);\n\n            if (pos != std::string::npos)\n            {\n                _boundary = content_type->substr(pos + len_of_boundary_flag);\n            }\n        }\n        else if (content_type->find(\"application/x-www-form-urlencoded\") != std::string::npos)\n        {\n            this->MarkFormUrlEncoded(true);\n        }\n        else if (content_type->find(\"application/octet-stream\") != std::string::npos)\n        {\n            this->MarkOctetStream(true);\n        }\n    }\n}\n\nvoid Request::ApplyApplication(std::string const& app_url_root)\n{\n    _url.UnderApplication(app_url_root);\n}\n\nvoid Request::SetMultiPartBoundary(char const* at, size_t length)\n{\n    _boundary = std::string(at, length);\n}\n\nvoid MultiPartSplitSubHeadersFromValue(std::string const& value, MultiPart::SubHeaders& sub_headers)\n{\n    std::vector<std::string> parts = Utilities::Split(value, ';');\n    sub_headers.value.clear();\n\n    for (auto p : parts)\n    {\n        auto pos = p.find('=');\n\n        if (pos == std::string::npos)\n        {\n            if (sub_headers.value.empty())\n            {\n                sub_headers.value = p;\n            }\n        }\n        else\n        {\n            std::string f = p.substr(0, pos);\n            Utilities::Trim(f);\n            std::string v = p.substr(pos + 1);\n            Utilities::Trim(v);\n            size_t vl = v.size();\n\n            if (vl >= 2)\n            {\n                if (v[0] == '\\\"' && v[vl - 1] == '\\\"')\n                {\n                    v = v.substr(1, vl - 2);\n                }\n            }\n\n            if (!f.empty())\n            {\n                sub_headers.headers.insert(std::make_pair(std::move(f), std::move(v)));\n            }\n        }\n    }\n}\n\nMultiPart::SubHeaders MultiPart::GetSubHeaders(std::string const& field)\n{\n    SubHeaders h;\n    std::string const& value = this->GetHeader(field);\n\n    if (!value.empty())\n    {\n        MultiPartSplitSubHeadersFromValue(value, h);\n    }\n\n    return h;\n}\n\nvoid Request::TransferHeadersToCookies()\n{\n    auto value = GetHeader(\"Cookie\");\n\n    if (!value.empty())\n    {\n        std::vector<std::string> parts = Utilities::Split(value, ';',\n                                                          Utilities::TrimOptions::keep_space);\n\n        for (auto part : parts)\n        {\n            std::vector<std::string> kv = Utilities::Split(part, '=',\n                                                           Utilities::TrimOptions::trim_all);\n\n            if (!kv.empty())\n            {\n                std::string const& k = kv[0];\n                std::string const& v = (kv.size() > 1) ? kv[1] : Utilities::theEmptyString;\n                _cookies.insert(std::make_pair(std::move(k), std::move(v)));\n            }\n        }\n    }\n}\n\nfs::path MakeUploadFileTemporaryName(std::string const& ext, std::string const& dir)\n{\n    fs::path disk_fn(dir);\n\n    do\n    {\n        std::stringstream ss;\n        ss << Utilities::GetUUID() << ext;\n\n        disk_fn /= ss.str();\n        size_t retry_count = 0;\n\n        try\n        {\n            if (fs::exists(disk_fn))\n            {\n                if (++retry_count > 9)\n                {\n                    log::Server()->error(\"Too many files in upload directory: {}.\", dir);\n                    return Utilities::theEmptyString;\n                }\n\n                continue;\n            }\n        }\n        catch (std::exception const& e)\n        {\n            log::Server()->error(\"Test file {} exists exception. {}\", disk_fn.string(), e.what());\n            return Utilities::theEmptyString;\n        }\n    }\n    while (false);\n\n    return disk_fn;\n}\n\nvoid Request::ParseFormUrlEncodedData()\n{\n    if (!this->_body.empty())\n    {\n        auto parameters = Utilities::ParseQueryParameters(_body);\n\n        for (auto& p : parameters)\n        {\n            FormDataItem fdi(p.first, std::move(p.second));\n            _formdata.push_back(std::move(fdi));\n        }\n    }\n}\n\nbool TransferMultiPartToFormDataItem(MultiPart& mp, FormDataItem& fdi)\n{\n    MultiPart::SubHeaders sub_headers = mp.GetSubHeaders(\"Content-Disposition\");\n\n    if (sub_headers.IsEmpty() || !Utilities::iEquals(sub_headers.value, \"form-data\"))\n    {\n        return false;\n    }\n\n    std::string name = Utilities::GetHeader(sub_headers.headers, \"name\");\n\n    if (name.empty())\n    {\n        mp.SetTransferResult(MultiPart::transfer_none);\n        return false;\n    }\n\n    fdi.name = std::move(name);\n    auto filename = Utilities::TryGetHeader(sub_headers.headers, \"filename\");\n\n    if (filename)\n    {\n        fdi.data_flag = FormDataItem::is_file_data;\n        fdi.filename = std::move(*filename);\n\n        mp.SetTransferResult(MultiPart::transfer_file_memory);\n    }\n    else\n    {\n        fdi.data_flag = FormDataItem::is_data;\n        mp.SetTransferResult(MultiPart::tranfer_formdata);\n    }\n\n    auto content_type = mp.TryGetHeader(\"Content-Type\");\n\n    if (content_type)\n    {\n        fdi.content_type = std::move(*content_type);\n    }\n\n    fdi.data = std::move(mp.GetData());\n    return true;\n}\n\nvoid Request::TransferMultiPartsToFormData(UploadFileSaveOptions const& options, std::string const& dir)\n{\n    for (size_t i = 0; i < _multiparts.size(); ++i)\n    {\n        MultiPart& part = _multiparts[i];\n        FormDataItem fd_item;\n\n        if (TransferMultiPartToFormDataItem(part, fd_item))\n        {\n            if (fd_item.data_flag == FormDataItem::is_file_data\n                && !fd_item.filename.empty() && !fd_item.data.empty()\n                && !dir.empty())\n            {\n                std::string ext = fs::extension(fd_item.filename);\n                size_t filesize_kb = fd_item.data.size() / 1024;\n\n                if (options.IsNeedSave(ext, filesize_kb))\n                {\n                    fs::path temporary_file_name = MakeUploadFileTemporaryName(ext, dir);\n\n                    if (!temporary_file_name.empty())\n                    {\n                        std::string err;\n\n                        if (Utilities::SaveDataToFile(fd_item.data, temporary_file_name, err))\n                        {\n                            fd_item.data = temporary_file_name.string();\n                            fd_item.data_flag = FormDataItem::is_file_temporary_name;\n                            part.SetTransferResult(MultiPart::transfer_file_saved);\n                        }\n                        else\n                        {\n                            log::Server()->error(\"Save form-item to template file fail. {}. {}. {}.\"\n                                                 , fd_item.filename, temporary_file_name.native(), err);\n                        }\n                    }\n                }\n            }\n        }\n\n        _formdata.push_back(std::move(fd_item));\n    }\n}\n\nstd::string Request::Dump() const\n{\n    std::stringstream ss;\n\n    ss << \"url : \" << _url.full <<  \"\\r\\n\";\n    ss << \"host : \" << _url.host <<  \"\\r\\n\";\n    ss << \"port : \" << _url.port <<  \"\\r\\n\";\n    ss << \"path : \" << _url.path <<  \"\\r\\n\";\n    ss << \"query : \" << _url.query <<  \"\\r\\n\";\n    ss << \"fragment : \" << _url.fragment <<  \"\\r\\n\";\n    ss << \"userinfo : \" << _url.userinfo <<  \"\\r\\n\";\n\n    ss << \"url-parameters : \\r\\n\";\n\n    for (auto const& p : _url.parameters)\n    {\n        ss << p.first << \" : \" << p.second <<  \"\\r\\n\";\n    }\n\n    ss << \"method : \" << this->GetMethodName() <<  \"\\r\\n\";\n\n    ss << \"headers : \\r\\n\";\n\n    for (auto const& p : _headers)\n    {\n        ss << p.first << \" : \" << p.second << \"\\r\\n\";\n    }\n\n    ss << \"upgrade : \" << std::boolalpha << this->IsUpgrade() << \"\\r\\n\";\n    ss << \"has content-length : \" << std::boolalpha << this->IsContentLengthProvided() << \"\\r\\n\";\n    ss << \"chunked : \" << std::boolalpha << this->IsChunked() << \"\\r\\n\";\n    ss << \"multipart : \" << std::boolalpha << this->IsMultiPart() << \"\\r\\n\";\n    ss << \"formdata : \" << std::boolalpha << this->IsFormData() << \"\\r\\n\";\n    ss << \"keepalive : \" << std::boolalpha << this->IsKeepAlive() << \"\\r\\n\";\n\n    if (this->IsMultiPart())\n    {\n        ss << \"boundary : \" << GetMultiPartBoundary() << \"\\r\\n\";\n    }\n\n    ss << \"body : \\r\\n\";\n    ss << _body <<  \"\\r\\n\";\n\n    ss << \"multi-parts : \\r\\n\";\n\n    for (auto const& mp : this->_multiparts)\n    {\n        for (auto const& h : mp.GetHeaders())\n        {\n            ss << h.first << \" = \" << h.second << \"\\r\\n\";\n        }\n\n        ss << \"part data : \\r\\n\";\n        ss << mp.GetData() <<  \"\\r\\n\";\n    }\n\n    ss << \"form-data : \\r\\n\";\n\n    for (auto const& fd : this->_formdata)\n    {\n        ss << \"name : \" << fd.name << \"\\r\\n\"\n           << \"is-file : \" << fd.IsFile() << \"\\r\\n\"\n           << \"data : \\r\\n\" << fd.data << \"\\r\\n\";\n    }\n\n    ss << \"path-parameters : \\r\\n\";\n\n    for (auto const& pp : this->_path_parameters.Items())\n    {\n        ss << pp.first << \" : \" << pp.second << \"\\r\\n\";\n    }\n\n    ss << \"cookies : \\r\\n\";\n\n    for (auto const& c : this->_cookies)\n    {\n        ss << c.first << \" : \" << c.second << \"\\r\\n\";\n    }\n\n    return ss.str();\n}\n\n}//namespace da4qi4\n"
  },
  {
    "path": "src/response.cpp",
    "content": "#include \"daqi/response.hpp\"\n\n#include <cstring>\n#include <map>\n#include <sstream>\n\n#include \"daqi/utilities/string_utilities.hpp\"\n#include \"daqi/utilities/container_utilities.hpp\"\n#include \"daqi/utilities/html_utilities.hpp\"\n\nnamespace da4qi4\n{\n\nstd::string const& EmptyBody()\n{\n    return Utilities::theEmptyString;\n}\n\nstruct HttpStatusSummaryHelper\n{\n    friend char const* HttpStatusSummaryGetter(int);\nprivate:\n    HttpStatusSummaryHelper()\n    {\n        init();\n    }\n\n    void init();\n    std::map<int, char const*> _map;\n};\n\n#define ADD_SUMMARY(CODE, SUMMARY) _map[CODE] = #SUMMARY\n\nvoid HttpStatusSummaryHelper::init()\n{\n    ADD_SUMMARY(HTTP_STATUS_CONTINUE,                        Continue)                        ;\n    ADD_SUMMARY(HTTP_STATUS_SWITCHING_PROTOCOLS,             Switching Protocols)             ;\n    ADD_SUMMARY(HTTP_STATUS_PROCESSING,                      Processing)                      ;\n    ADD_SUMMARY(HTTP_STATUS_OK,                              OK)                              ;\n    ADD_SUMMARY(HTTP_STATUS_CREATED,                         Created)                         ;\n    ADD_SUMMARY(HTTP_STATUS_ACCEPTED,                        Accepted)                        ;\n    ADD_SUMMARY(HTTP_STATUS_NON_AUTHORITATIVE_INFORMATION,   Non - Authoritative Information)   ;\n    ADD_SUMMARY(HTTP_STATUS_NO_CONTENT,                      No Content)                      ;\n    ADD_SUMMARY(HTTP_STATUS_RESET_CONTENT,                   Reset Content)                   ;\n    ADD_SUMMARY(HTTP_STATUS_PARTIAL_CONTENT,                 Partial Content)                 ;\n    ADD_SUMMARY(HTTP_STATUS_MULTI_STATUS,                    Multi - Status)                    ;\n    ADD_SUMMARY(HTTP_STATUS_ALREADY_REPORTED,                Already Reported)                ;\n    ADD_SUMMARY(HTTP_STATUS_IM_USED,                         IM Used)                         ;\n    ADD_SUMMARY(HTTP_STATUS_MULTIPLE_CHOICES,                Multiple Choices)                ;\n    ADD_SUMMARY(HTTP_STATUS_MOVED_PERMANENTLY,               Moved Permanently)               ;\n    ADD_SUMMARY(HTTP_STATUS_FOUND,                           Found)                           ;\n    ADD_SUMMARY(HTTP_STATUS_SEE_OTHER,                       See Other)                       ;\n    ADD_SUMMARY(HTTP_STATUS_NOT_MODIFIED,                    Not Modified)                    ;\n    ADD_SUMMARY(HTTP_STATUS_USE_PROXY,                       Use Proxy)                       ;\n    ADD_SUMMARY(HTTP_STATUS_TEMPORARY_REDIRECT,              Temporary Redirect)              ;\n    ADD_SUMMARY(HTTP_STATUS_PERMANENT_REDIRECT,              Permanent Redirect)              ;\n    ADD_SUMMARY(HTTP_STATUS_BAD_REQUEST,                     Bad Request)                     ;\n    ADD_SUMMARY(HTTP_STATUS_UNAUTHORIZED,                    Unauthorized)                    ;\n    ADD_SUMMARY(HTTP_STATUS_PAYMENT_REQUIRED,                Payment Required)                ;\n    ADD_SUMMARY(HTTP_STATUS_FORBIDDEN,                       Forbidden)                       ;\n    ADD_SUMMARY(HTTP_STATUS_NOT_FOUND,                       Not Found)                       ;\n    ADD_SUMMARY(HTTP_STATUS_METHOD_NOT_ALLOWED,              Method Not Allowed)              ;\n    ADD_SUMMARY(HTTP_STATUS_NOT_ACCEPTABLE,                  Not Acceptable)                  ;\n    ADD_SUMMARY(HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED,   Proxy Authentication Required)   ;\n    ADD_SUMMARY(HTTP_STATUS_REQUEST_TIMEOUT,                 Request Timeout)                 ;\n    ADD_SUMMARY(HTTP_STATUS_CONFLICT,                        Conflict)                        ;\n    ADD_SUMMARY(HTTP_STATUS_GONE,                            Gone)                            ;\n    ADD_SUMMARY(HTTP_STATUS_LENGTH_REQUIRED,                 Length Required)                 ;\n    ADD_SUMMARY(HTTP_STATUS_PRECONDITION_FAILED,             Precondition Failed)             ;\n    ADD_SUMMARY(HTTP_STATUS_PAYLOAD_TOO_LARGE,               Payload Too Large)               ;\n    ADD_SUMMARY(HTTP_STATUS_URI_TOO_LONG,                    URI Too Long)                    ;\n    ADD_SUMMARY(HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE,          Unsupported Media Type)          ;\n    ADD_SUMMARY(HTTP_STATUS_RANGE_NOT_SATISFIABLE,           Range Not Satisfiable)           ;\n    ADD_SUMMARY(HTTP_STATUS_EXPECTATION_FAILED,              Expectation Failed)              ;\n    ADD_SUMMARY(HTTP_STATUS_MISDIRECTED_REQUEST,             Misdirected Request)             ;\n    ADD_SUMMARY(HTTP_STATUS_UNPROCESSABLE_ENTITY,            Unprocessable Entity)            ;\n    ADD_SUMMARY(HTTP_STATUS_LOCKED,                          Locked)                          ;\n    ADD_SUMMARY(HTTP_STATUS_FAILED_DEPENDENCY,               Failed Dependency)               ;\n    ADD_SUMMARY(HTTP_STATUS_UPGRADE_REQUIRED,                Upgrade Required)                ;\n    ADD_SUMMARY(HTTP_STATUS_PRECONDITION_REQUIRED,           Precondition Required)           ;\n    ADD_SUMMARY(HTTP_STATUS_TOO_MANY_REQUESTS,               Too Many Requests)               ;\n    ADD_SUMMARY(HTTP_STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE, Request Header Fields Too Large) ;\n    ADD_SUMMARY(HTTP_STATUS_UNAVAILABLE_FOR_LEGAL_REASONS,   Unavailable For Legal Reasons)   ;\n    ADD_SUMMARY(HTTP_STATUS_INTERNAL_SERVER_ERROR,           Internal Server Error)           ;\n    ADD_SUMMARY(HTTP_STATUS_NOT_IMPLEMENTED,                 Not Implemented)                 ;\n    ADD_SUMMARY(HTTP_STATUS_BAD_GATEWAY,                     Bad Gateway)                     ;\n    ADD_SUMMARY(HTTP_STATUS_SERVICE_UNAVAILABLE,             Service Unavailable)             ;\n    ADD_SUMMARY(HTTP_STATUS_GATEWAY_TIMEOUT,                 Gateway Timeout)                 ;\n    ADD_SUMMARY(HTTP_STATUS_HTTP_VERSION_NOT_SUPPORTED,      HTTP Version Not Supported)      ;\n    ADD_SUMMARY(HTTP_STATUS_VARIANT_ALSO_NEGOTIATES,         Variant Also Negotiates)         ;\n    ADD_SUMMARY(HTTP_STATUS_INSUFFICIENT_STORAGE,            Insufficient Storage)            ;\n    ADD_SUMMARY(HTTP_STATUS_LOOP_DETECTED,                   Loop Detected)                   ;\n    ADD_SUMMARY(HTTP_STATUS_NOT_EXTENDED,                    Not Extended)                    ;\n    ADD_SUMMARY(HTTP_STATUS_NETWORK_AUTHENTICATION_REQUIRED, Network Authentication Required) ;\n}\n\nchar const* HttpStatusSummaryGetter(int code)\n{\n    static HttpStatusSummaryHelper rsm;\n    std::map<int, char const*>::const_iterator cit  = rsm._map.find(code);\n    return (cit == rsm._map.cend()) ? \"\" : cit->second;\n}\n\nvoid ChunkedBodies::PushBack(std::string const& body, bool is_last)\n{\n    std::string data;\n    data.reserve(body.size() + 5);\n\n    if (is_last)\n    {\n        data = \"0\\r\\n\\r\\n\";\n    }\n    else\n    {\n        std::stringstream ss;\n        ss << Utilities::DecIntToHexStr(body.size()) << \"\\r\\n\";\n        ss << body << \"\\r\\n\";\n        data = ss.str();\n    }\n\n    std::lock_guard<std::mutex> lock(_m);\n    _chunked_bodies.push_back(std::make_pair(std::move(data), false));\n\n    if (is_last)\n    {\n        _chunked_bodies.push_back(std::make_pair(\"\", true));\n    }\n}\n\nstd::string ChunkedBodies::PopFront(bool& is_last)\n{\n    is_last = false;\n    std::lock_guard<std::mutex> lock(_m);\n\n    if (_chunked_bodies.empty())\n    {\n        return Utilities::theEmptyString;\n    }\n\n    std::pair<std::string, bool> front(std::move(*_chunked_bodies.begin()));\n    _chunked_bodies.erase(_chunked_bodies.begin());\n\n    is_last = front.second;\n    return front.first;\n}\n\nvoid ChunkedBodies::Clear()\n{\n    std::lock_guard<std::mutex> lock(_m);\n    _chunked_bodies.clear();\n}\n\nResponse::Response()\n{\n    add_server_header();\n}\n\nvoid Response::add_server_header()\n{\n    std::stringstream ss;\n    ss << the_daqi_name << '/' << the_daqi_version;\n    _headers[\"Server\"] = ss.str();\n}\n\nvoid Response::Reset()\n{\n    _status_code = HTTP_STATUS_OK;\n    _headers.clear();\n    _body.clear();\n    _charset = \"UTF-8\";\n    _version_major  = _version_minor = 1;\n    _cookies.clear();\n    _chunked_bodies.Clear();\n\n    add_server_header();\n}\n\nvoid Response::AppendHeader(std::string const& field, std::string const& value)\n{\n    auto it = _headers.find(field);\n\n    if (it != _headers.end())\n    {\n        it->second = std::move(value);\n    }\n    else\n    {\n        _headers.insert(std::make_pair(std::move(field), std::move(value)));\n    }\n}\nbool Response::IsExistsHeader(std::string const& field) const\n{\n    return Utilities::IsExistsHeader(_headers, field);\n}\nstd::string const& Response::GetHeader(std::string const& field) const\n{\n    return Utilities::GetHeader(_headers, field);\n}\nOptionalStringRefConst Response::TryGetHeader(std::string const& field) const\n{\n    return Utilities::TryGetHeader(_headers, field);\n}\nstd::pair<std::string, std::string> split_content_type_value(std::string const& value)\n{\n    auto pair = std::make_pair(value, std::string());\n\n    if (!value.empty())\n    {\n        auto pos = value.find(\" ;\");\n\n        if (pos != std::string::npos)\n        {\n            pair.first = value.substr(0, pos);\n            pair.second = value.substr(pos + 2);\n        }\n    }\n\n    return pair;\n}\nstd::string Response::GetContentType(ContentTypePart part) const\n{\n    std::string value = GetHeader(\"Content-Type\");\n\n    if (part == with_chartset)\n    {\n        return value;\n    }\n\n    if (!value.empty())\n    {\n        auto pos = value.find(\";\");\n\n        if (pos != std::string::npos)\n        {\n            return value.substr(0, pos);\n        }\n    }\n\n    return value;\n}\nbool is_content_type_need_charset(std::string const& content_type)\n{\n    return Utilities::iStartsWith(content_type, \"text/\");\n}\nvoid Response::SetCharset(std::string const& charset)\n{\n    _charset = charset;\n    auto it = _headers.find(\"Content-Type\");\n\n    if (it != _headers.end())\n    {\n        auto pair = split_content_type_value(it->second);\n\n        if (charset != pair.second\n            && is_content_type_need_charset(pair.first))\n        {\n            SetContentType(pair.first, charset);\n        }\n    }\n}\nvoid Response::SetContentType(std::string const& content_type)\n{\n    std::string field_value;\n    field_value.reserve(content_type.size() + _charset.size() + 2);\n    field_value = content_type;\n\n    if (is_content_type_need_charset(content_type) && !_charset.empty())\n    {\n        field_value += (\"; charset=\" + _charset);\n    }\n\n    AppendHeader(\"Content-Type\", field_value);\n}\nvoid Response::SetContentType(std::string const& content_type\n                              , std::string const& content_charset)\n{\n    std::string field_value;\n    field_value = content_type + \"; charset=\" + content_charset;\n    AppendHeader(\"Content-Type\", field_value);\n}\nbool Response::IsChunked() const\n{\n    auto item = TryGetHeader(\"Transfer-Encoding\");\n    return (item && Utilities::iEquals(*item, \"chunked\"));\n}\nvoid Response::MarkKeepAlive()\n{\n    AppendHeader(\"Connection\", \"keep-alive\");\n}\nvoid Response::MarkClose()\n{\n    AppendHeader(\"Connection\", \"close\");\n}\nbool Response::IsKeepAlive() const\n{\n    auto value = TryGetHeader(\"Connection\");\n\n    if ((_version_major < 1) || (_version_major == 1 && _version_minor == 0))\n    {\n        return (value && Utilities::iEquals(*value, \"keep-alive\"));\n    }\n    else\n    {\n        return (!value || !Utilities::iEquals(*value, \"close\"));\n    }\n}\nbool Response::IsClose() const\n{\n    return !IsKeepAlive();\n}\n\nvoid Response::set_or_default_body(std::string body, bool provide_default_if_body_is_empty)\n{\n    if (!body.empty())\n    {\n        SetBody(std::move(body));\n        return;\n    }\n\n    if (provide_default_if_body_is_empty)\n    {\n        SetContentType(\"text/plain\");\n        SetBody(HttpStatusSummaryGetter(_status_code));\n    }\n}\nvoid Response::ReplyStatus(int code, std::string body)\n{\n    _status_code = code;\n    set_or_default_body(std::move(body));\n}\n\nvoid Response::ReplyOk()\n{\n    return ReplyOk(nullptr);\n}\n\nvoid Response::ReplyOk(const char* body)\n{\n    _status_code = HTTP_STATUS_OK;\n    std::string s = (body ? std::string(body) : EmptyBody());\n    set_or_default_body(std::move(s));\n}\n\nvoid Response::ReplyOk(std::string body)\n{\n    _status_code = HTTP_STATUS_OK;\n    set_or_default_body(std::move(body));\n}\n\nvoid Response::ReplyOk(Json const& result)\n{\n    try\n    {\n        std::string body = result.dump(2);\n        ReplyOkJSON(body);\n    }\n    catch (...)\n    {\n        ReplyInternalServerError();\n    }\n}\n\n\nvoid Response::ReplyNofound(std::string body)\n{\n    _status_code = HTTP_STATUS_NOT_FOUND;\n    set_or_default_body(std::move(body));\n}\n\nvoid Response::ReplyGone(std::string body)\n{\n    _status_code = HTTP_STATUS_GONE;\n    set_or_default_body(std::move(body));\n}\n\nvoid Response::ReplyUnauthorized(std::string body)\n{\n    _status_code = HTTP_STATUS_UNAUTHORIZED;\n    set_or_default_body(std::move(body));\n}\n\nvoid Response::ReplyNoAuthoritativeInfo(std::string body)\n{\n    _status_code = HTTP_STATUS_NON_AUTHORITATIVE_INFORMATION;\n    set_or_default_body(std::move(body));\n}\n\nvoid Response::ReplyBadRequest(std::string body)\n{\n    _status_code = HTTP_STATUS_BAD_REQUEST;\n    set_or_default_body(std::move(body));\n}\n\nvoid Response::ReplyRangeNotSatisfiable(std::string body)\n{\n    _status_code = HTTP_STATUS_RANGE_NOT_SATISFIABLE;\n    set_or_default_body(std::move(body));\n}\n\nvoid Response::ReplyForbidden(std::string body)\n{\n    _status_code = HTTP_STATUS_FORBIDDEN;\n    set_or_default_body(std::move(body));\n}\n\nvoid Response::ReplyMethodNotAllowed(std::string body)\n{\n    _status_code = HTTP_STATUS_METHOD_NOT_ALLOWED;\n    set_or_default_body(std::move(body));\n}\n\nvoid Response::ReplyHttpVersionNotSupported(std::string body)\n{\n    _status_code = HTTP_STATUS_HTTP_VERSION_NOT_SUPPORTED;\n    set_or_default_body(std::move(body));\n}\n\nvoid Response::ReplyPayloadTooLarge(std::string body)\n{\n    _status_code = HTTP_STATUS_PAYLOAD_TOO_LARGE;\n    set_or_default_body(std::move(body));\n}\n\nvoid Response::ReplyUriTooLong(std::string body)\n{\n    _status_code = HTTP_STATUS_URI_TOO_LONG;\n    set_or_default_body(std::move(body));\n}\n\nvoid Response::ReplyTooManyRequests(std::string body)\n{\n    _status_code = HTTP_STATUS_TOO_MANY_REQUESTS;\n    set_or_default_body(std::move(body));\n}\n\nvoid Response::ReplyNotImplemented(std::string body)\n{\n    _status_code = HTTP_STATUS_NOT_IMPLEMENTED;\n    set_or_default_body(std::move(body));\n}\n\nvoid Response::ReplyUnsupportedMediaType(std::string body)\n{\n    _status_code = HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE;\n    set_or_default_body(std::move(body));\n}\n\nvoid Response::ReplyServiceUnavailable(std::string body)\n{\n    _status_code = HTTP_STATUS_SERVICE_UNAVAILABLE;\n    set_or_default_body(std::move(body));\n}\n\nvoid Response::ReplyInternalServerError(std::string body)\n{\n    _status_code = HTTP_STATUS_INTERNAL_SERVER_ERROR;\n    set_or_default_body(std::move(body));\n}\n\nvoid Response::ReplyMovedPermanently(std::string const& dst_location, std::string body)\n{\n    _status_code = HTTP_STATUS_MOVED_PERMANENTLY;\n    SetLocation(dst_location);\n    set_or_default_body(std::move(body));\n}\n\nvoid Response::ReplyRedirect(std::string const& dst_location\n                             , RedirectType type\n                             , std::string body)\n{\n    _status_code = (type == RedirectType::permanent)\n                   ? HTTP_STATUS_PERMANENT_REDIRECT\n                   : HTTP_STATUS_TEMPORARY_REDIRECT;\n    SetLocation(dst_location);\n    set_or_default_body(std::move(body), false);\n}\n\nvoid Response::SetCookie(Cookie const& cookie)\n{\n    for (auto& c : _cookies)\n    {\n        if (Utilities::iEquals(c.GetName(), cookie.GetName())\n            && Utilities::iEquals(c.GetDomain(), cookie.GetDomain())\n            && Utilities::iEquals(c.GetPath(), cookie.GetPath()))\n        {\n            c = cookie;\n            return;\n        }\n    }\n\n    _cookies.push_back(cookie);\n}\n\nvoid Response::SetCookieExpiredImmediately(std::string const& name,\n                                           std::string const& domain, std::string const& path)\n{\n    bool found = false;\n\n    for (auto& c : _cookies)\n    {\n        if (Utilities::iEquals(c.GetName(), name)\n            && Utilities::iEquals(c.GetDomain(), domain)\n            && Utilities::iEquals(c.GetPath(), path))\n        {\n            c.SetValue(\"\").SetExpiredImmediately();\n            found = true;\n            break;\n        }\n    }\n\n    if (!found)\n    {\n        Cookie cookie(name, \"\", domain, path);\n        cookie.SetExpiredImmediately();\n        _cookies.push_back(cookie);\n    }\n}\n\nstd::ostream& operator << (std::ostream& os, Response const& res)\n{\n    int code = res.GetStatusCode();\n    char const* summary = HttpStatusSummaryGetter(code);\n    auto v = res.GetVersion();\n    os << \"HTTP/\" << v.first << \".\" << v.second << ' ' << code << ' ' << summary << \"\\r\\n\";\n\n    for (auto const& h : res.GetHeaders())\n    {\n        os << h.first << \":\" << h.second << \"\\r\\n\";\n    }\n\n    for (auto const& cookie : res.GetCookies())\n    {\n        os << \"Set-Cookie:\" << cookie << \"\\r\\n\";\n    }\n\n    if (!res.IsChunked())\n    {\n        os << \"Content-Length:\" << res.GetBody().size() << \"\\r\\n\\r\\n\";\n        os << res.GetBody();\n    }\n    else\n    {\n        os << \"\\r\\n\";\n    }\n\n    return os;\n}\n\n} //namespace da4qi4\n"
  },
  {
    "path": "src/router.cpp",
    "content": "#include \"daqi/router.hpp\"\n\nnamespace da4qi4\n{\n\nrouter_equals operator \"\" _router_equals(char const* str, std::size_t n)\n{\n    return router_equals(std::string(str, n));\n}\n\nrouter_starts operator \"\" _router_starts(char const* str, std::size_t n)\n{\n    return router_starts(std::string(str, n));\n}\n\nrouter_regex operator \"\" _router_regex(char const* str, std::size_t n)\n{\n    return router_regex(std::string(str, n));\n}\n\nstd::size_t to_uniform_items(std::string const& url_matcher\n                             , RouterItem const& ri, std::vector<UniformItem>& uitems)\n{\n    for (auto const& h : ri.handlers)\n    {\n        UniformItem ui(url_matcher);\n        ui.method = HandlerMethodName(h.first);\n        ui.template_name = ri.template_name;\n        uitems.push_back(ui);\n    }\n\n    return ri.handlers.size();\n}\n\nstd::size_t to_uniform_items(RegexRouterItem const& ri, std::vector<UniformRegexItem>& uitems)\n{\n    for (auto const& h : ri.handlers)\n    {\n        UniformRegexItem ui(ri.url_matcher);\n\n        ui.method = HandlerMethodName(h.first);\n        ui.template_name = ri.template_name;\n\n        ui.regex_matcher = ri.regex_matcher;\n\n        uitems.push_back(ui);\n    }\n\n    return ri.handlers.size();\n}\n\nstd::vector<UniformItem> EqualsRoutingTable::Uniforms() const\n{\n    std::vector<UniformItem> items;\n\n    for (auto const& p : _map)\n    {\n        to_uniform_items(p.first, p.second, items);\n    }\n\n    return items;\n}\n\nStartsWithRoutingTable::Result StartsWithRoutingTable::Match(std::string const& url\n                                                             , HandlerMethod method\n                                                             , bool& url_exists)\n{\n    auto it = _map.begin();\n\n    for (; it != _map.end(); ++it)\n    {\n        if (Utilities::iStartsWith(url, it->first))\n        {\n            url_exists = true;\n            return Result(&(it->second), method, it->first);\n        }\n    }\n\n    return Result();\n}\n\nstd::vector<UniformItem> StartsWithRoutingTable::Uniforms() const\n{\n    std::vector<UniformItem> items;\n\n    for (auto const& p : _map)\n    {\n        to_uniform_items(p.first, p.second, items);\n    }\n\n    return items;\n}\n\nstd::string to_parameter_pattern(std::string simple_pattern\n                                 , std::vector<std::string>& names)\n{\n    std::regex pattern(\"\\\\{\\\\{\\\\w*\\\\}\\\\}\");\n\n    std::string::const_iterator itb = simple_pattern.begin(), ite = simple_pattern.end();\n\n    using PairItem = std::pair<std::string::const_iterator, std::string::const_iterator>;\n    std::vector<PairItem> pos;\n    std::smatch result;\n\n    while (std::regex_search(itb, ite, result, pattern))\n    {\n        int const parameter_name_flag = 2;\n        std::string name(result[0].first + parameter_name_flag\n                         , result[0].second - parameter_name_flag);\n        names.push_back(name);\n\n        PairItem it = std::make_pair(result[0].first, result[0].second);\n        pos.push_back(it);\n\n        itb = result[0].second;\n    }\n\n    for (size_t i = pos.size(); i > 0; --i)\n    {\n        auto item = pos[i - 1];\n        simple_pattern.replace(item.first, item.second, \"(\\\\w*)\");\n    }\n\n    return simple_pattern;\n}\n\nbool RegexMatchRoutingTable::Insert(std::string const&  url_matcher,\n                                    RouterItem const& item, std::string& error)\n{\n    error.clear();\n\n    Item ri(item);\n    ri.url_matcher = url_matcher;\n\n    try\n    {\n        ri.regex_matcher = to_parameter_pattern(url_matcher, ri.parameters);\n        ri.regex_pattern.assign(ri.regex_matcher);\n        _lst.push_back(ri);\n        return true;\n    }\n    catch (std::regex_error const& e)\n    {\n        error = e.what();\n        return false;\n    }\n    catch (std::exception const& e)\n    {\n        error = e.what();\n        return false;\n    }\n}\n\nRegexMatchRoutingTable::Item* RegexMatchRoutingTable::Exists(std::string const& url_matcher)\n{\n    for (auto& item : _lst)\n    {\n        if (url_matcher == item.url_matcher)\n        {\n            return &(item);\n        }\n    }\n\n    return nullptr;\n}\n\nRegexMatchRoutingTable::Result RegexMatchRoutingTable::Match(std::string const& url\n                                                             , HandlerMethod method\n                                                             , bool& url_exists)\n{\n    Result r;\n\n    try\n    {\n        for (auto& item : _lst)\n        {\n            std::smatch result;\n\n            if (std::regex_match(url, result, item.regex_pattern))\n            {\n                url_exists = true;\n                Result rr(&item, method);\n\n                if (!rr.handler)\n                {\n                    return Result();\n                }\n\n                int const skip_first_one = 1;\n\n                for (size_t i = skip_first_one ; i < result.size(); ++i)\n                {\n                    std::string value = result[i].str();\n                    rr.values.push_back(value);\n                }\n\n                rr.parameters = item.parameters;\n                return rr;\n            }\n        }\n    }\n    catch (std::regex_error const& e)\n    {\n        r.error = e.what();\n        return r;\n    }\n    catch (std::exception const& e)\n    {\n        r.error = e.what();\n    }\n\n    return r;\n}\n\nstd::vector<UniformRegexItem> RegexMatchRoutingTable::Uniforms() const\n{\n    std::vector<UniformRegexItem> items;\n\n    for (auto const& l : _lst)\n    {\n        to_uniform_items(l, items);\n    }\n\n    return items;\n}\n\n} //namespace da4qi4\n\nda4qi4::router_equals operator \"\" _da4qi4_router_equals(char const* str, std::size_t n)\n{\n    return da4qi4::operator \"\" _router_equals(str, n);\n}\n\nda4qi4::router_starts operator \"\" _da4qi4_router_starts(char const* str, std::size_t n)\n{\n    return da4qi4::operator \"\" _router_starts(str, n);\n}\n\nda4qi4::router_regex operator \"\" _da4qi4_router_regex(char const*  str, std::size_t n)\n{\n    return da4qi4::operator \"\" _router_regex(str, n);\n}\n\n"
  },
  {
    "path": "src/server.cpp",
    "content": "#include  \"daqi/server.hpp\"\n\n#include <functional>\n#include <boost/date_time/posix_time/ptime.hpp>\n\n#include \"daqi/def/log_def.hpp\"\n#include \"daqi/def/boost_def.hpp\"\n#include \"daqi/utilities/asio_utilities.hpp\"\n\n#include \"daqi/connection.hpp\"\n\nnamespace da4qi4\n{\n\n#ifdef NDEBUG\n    int const _detect_templates_interval_seconds_ =  15 * 60; //15 minutes\n#else\n    int const _detect_templates_interval_seconds_ =  15;  //15 seconds\n#endif\n\nnamespace\n{\n\nint const _first_idle_interval_seconds_ = 10;            //10 seconds\n\nvoid init_server_ssl_context(boost::asio::ssl::context* ssl_ctx, Server::SSLOptions const* ssl_opts)\n{\n    assert(ssl_ctx && ssl_opts);\n\n    ssl_ctx->set_options(ssl_opts->options);\n\n    if (ssl_opts->on_need_password)\n    {\n        ssl_ctx->set_password_callback(ssl_opts->on_need_password);\n    }\n\n    if (!ssl_opts->certificate_chain_file.empty())\n    {\n        ssl_ctx->use_certificate_chain_file(ssl_opts->certificate_chain_file);\n    }\n\n    if (!ssl_opts->private_key_file.empty())\n    {\n        if (ssl_opts->private_key_type == Server::SSLOptions::PrivateKeyType::RSA)\n        {\n            ssl_ctx->use_rsa_private_key_file(ssl_opts->private_key_file, ssl_opts->private_key_file_format);\n        }\n        else\n        {\n            ssl_ctx->use_private_key_file(ssl_opts->private_key_file, ssl_opts->private_key_file_format);\n        }\n    }\n\n    if (!ssl_opts->tmp_DiffieHellman_file.empty())\n    {\n        ssl_ctx->use_tmp_dh_file(ssl_opts->tmp_DiffieHellman_file);\n    }\n\n    auto verify_mode = (!ssl_opts->will_verify_client)\n                       ? SSLContextBase::verify_none\n                       : (SSLContextBase::verify_peer | SSLContextBase::verify_fail_if_no_peer_cert);\n\n    ssl_ctx->set_verify_mode(verify_mode);\n}\n\n}\n\nServer::Server(Tcp::endpoint endpoint, size_t thread_count, SSLOptions const* ssl_opts)\n    : _withssl(ssl_opts != nullptr ? WithSSL::yes : WithSSL::no)\n    , _idle_interval_seconds(_first_idle_interval_seconds_)\n    , _running(false), _stopping(false)\n    , _ioc_pool(thread_count)\n    , _acceptor(_ioc_pool.GetIOContext())\n    , _signals(_ioc_pool.GetIOContext())\n    , _ssl_ctx(!ssl_opts ? nullptr : new boost::asio::ssl::context(boost::asio::ssl::context::tls_server))\n    , _idle_running(false)\n    , _detect_templates(false)\n    , _idle_timer(_ioc_pool.GetIOContext())\n{\n    _signals.add(SIGINT);\n    _signals.add(SIGTERM);\n\n#if defined(SIGQUIT)\n    _signals.add(SIGQUIT);\n#endif\n    _signals.async_wait(std::bind(&Server::do_stop, this));\n\n    if (_ssl_ctx)\n    {\n        assert(_withssl == WithSSL::yes);\n        init_server_ssl_context(_ssl_ctx.get(), ssl_opts);\n    }\n\n    _acceptor.open(endpoint.protocol());\n    _acceptor.set_option(Tcp::acceptor::reuse_address(true));\n    _acceptor.bind(endpoint);\n    _acceptor.listen();\n\n    log::Server()->info(\"Supping on {}:{}, {} thread(s).\",\n                        endpoint.address().to_string()\n                        , endpoint.port()\n                        , _ioc_pool.Size());\n}\n\nServer::Ptr Server::Supply(unsigned short port, size_t thread_count)\n{\n    return Ptr(new Server({Tcp::v4(), port}, thread_count));\n}\n\nServer::Ptr Server::Supply(std::string const& host, unsigned short port, size_t thread_count)\n{\n    return Ptr(new Server(Utilities::make_endpoint(host, port), thread_count));\n}\n\nServer::Ptr Server::Supply(std::string const& host, unsigned short port)\n{\n    return Ptr(new Server(Utilities::make_endpoint(host, port), 0));\n}\n\nServer::Ptr Server::Supply(unsigned short port)\n{\n    return Ptr(new Server({Tcp::v4(), port}, 0));\n}\n\nServer::Ptr Server::SupplyWithSSL(Server::SSLOptions const& ssl_opt, unsigned short port, size_t thread_count)\n{\n    return Ptr(new Server({Tcp::v4(), port}, thread_count, &ssl_opt));\n}\n\nServer::Ptr Server::SupplyWithSSL(Server::SSLOptions const& ssl_opt\n                                  , std::string const& host, unsigned short port, size_t thread_count)\n{\n    return Ptr(new Server(Utilities::make_endpoint(host, port), thread_count, &ssl_opt));\n}\n\nServer::Ptr Server::SupplyWithSSL(Server::SSLOptions const& ssl_opt, std::string const& host, unsigned short port)\n{\n    return Ptr(new Server(Utilities::make_endpoint(host, port), 0, &ssl_opt));\n}\n\nServer::Ptr Server::SupplyWithSSL(Server::SSLOptions const& ssl_opt, unsigned short port)\n{\n    return Ptr(new Server({Tcp::v4(), port}, 0, &ssl_opt));\n}\n\nServer::~Server()\n{\n    log::Server()->info(\"Destroied.\");\n}\n\nbool Server::Mount(ApplicationPtr app)\n{\n    if (AppMgr().MountApplication(app))\n    {\n        log::Server()->info(\"Application {} mounted.\", app->GetName());\n        return true;\n    }\n\n    log::Server()->error(\"Application {} mount fail.\", app->GetName());\n    return false;\n}\n\nvoid Server::Run()\n{\n    assert(!_running);\n\n    if (_running)\n    {\n        log::Server()->critical(\"Server is running already.\");\n        return;\n    }\n\n    _running = true;\n\n    AppMgr().Mount();\n\n    _idle_running = true;\n    start_idle_timer();\n\n    start_accept();\n\n    _ioc_pool.Run();\n\n    log::Server()->info(\"Stopped.\");\n}\n\nvoid Server::Stop()\n{\n    do_stop();\n}\n\nstd::string extract_app_path(std::string const& app_root, std::string const& path)\n{\n    assert((Utilities::iStartsWith(path, app_root)) && \"URL MUST STARTSWITH APPLICATION ROOT\");\n\n    return path.substr(app_root.size());\n}\n\ntemplate<typename R, typename M>\nApplicationPtr ServerAddHandler(Server* s, M m, R r, Handler h)\n{\n    ApplicationPtr app = s->PrepareApp(r.s);\n\n    if (app)\n    {\n        r.s = extract_app_path(app->GetUrlRoot(), r.s);\n\n        if (app->AddHandler(m, r, h))\n        {\n            return app;\n        }\n    }\n\n    return nullptr;\n}\n\nApplicationPtr Server::AddHandler(HandlerMethod m, router_equals r, Handler h)\n{\n    return ServerAddHandler(this, m, r, h);\n}\n\nApplicationPtr Server::AddHandler(HandlerMethod m, router_starts r, Handler h)\n{\n    return ServerAddHandler(this, m, r, h);\n}\n\nApplicationPtr Server::AddHandler(HandlerMethod m, router_regex r, Handler h)\n{\n    return ServerAddHandler(this, m, r, h);\n}\n\nApplicationPtr Server::AddHandler(HandlerMethods ms, router_equals r, Handler h)\n{\n    return ServerAddHandler(this, ms, r, h);\n}\n\nApplicationPtr Server::AddHandler(HandlerMethods ms, router_starts r, Handler h)\n{\n    return ServerAddHandler(this, ms, r, h);\n}\n\nApplicationPtr Server::AddHandler(HandlerMethods ms, router_regex r, Handler h)\n{\n    return ServerAddHandler(this, ms, r, h);\n}\n\nbool Server::AddEqualsRouter(HandlerMethod m, std::vector<std::string> const& urls, Handler h)\n{\n    for (auto a : urls)\n    {\n        if (!AddHandler(m, router_equals(a), h))\n        {\n            return false;\n        }\n    }\n\n    return true;\n}\n\nbool Server::AddStartsRouter(HandlerMethod m, std::vector<std::string> const& urls, Handler h)\n{\n    for (auto a : urls)\n    {\n        if (!AddHandler(m, router_starts(a), h))\n        {\n            return false;\n        }\n    }\n\n    return true;\n}\n\nbool Server::AddRegexRouter(HandlerMethod m, std::vector<std::string> const& urls, Handler h)\n{\n    for (auto a : urls)\n    {\n        if (!AddHandler(m, router_regex(a), h))\n        {\n            return false;\n        }\n    }\n\n    return true;\n}\n\nvoid Server::AppendIdleFunction(int interval_seconds, IdleFunction func)\n{\n    assert(!_idle_running && \"Idle-function is running.\");\n    assert(interval_seconds > 0);\n\n    _idle_functions.emplace_back(interval_seconds, func);\n}\n\nApplicationPtr Server::PrepareApp(std::string const& url)\n{\n    make_default_app_if_empty();\n\n    auto app = AppMgr().FindByURL(url);\n\n    if (!app)\n    {\n        log::Server()->warn(\"Application on url \\\"{}\\\" no found.\", url);\n        return nullptr;\n    }\n\n    return app;\n}\n\nApplicationPtr Server::DefaultApp(const std::string& name)\n{\n    auto app = AppMgr().FindByURL(\"/\");\n\n    if (!app)\n    {\n        make_default_app(name);\n        app = AppMgr().FindByURL(\"/\");\n    }\n\n    assert(app != nullptr);\n\n    return app;\n}\n\nvoid Server::make_default_app_if_empty()\n{\n    if (AppMgr().IsEmpty())\n    {\n        AppMgr().CreateDefault();\n    }\n}\n\nvoid Server::make_default_app(std::string const& name)\n{\n    AppMgr().CreateDefault(name);\n}\n\nvoid Server::start_accept()\n{\n    make_default_app_if_empty();\n    do_accept();\n}\n\nvoid Server::do_accept()\n{\n    auto ioc_ctx = _ioc_pool.GetIOContextAndIndex();\n\n    ConnectionPtr cnt =\n                _withssl == WithSSL::no\n                ? Connection::Create(ioc_ctx.first, ioc_ctx.second)\n                : Connection::Create(ioc_ctx.first, ioc_ctx.second, *_ssl_ctx);\n\n    _acceptor.async_accept(cnt->GetSocket()\n                           , [this, cnt](errorcode ec)\n    {\n        if (ec)\n        {\n            log::Server()->error(\"Acceptor error: {}\", ec.message());\n\n            if (_stopping)\n            {\n                return;\n            }\n        }\n        else\n        {\n            cnt->Start();\n        }\n\n        do_accept();\n    });\n}\n\nvoid Server::do_stop()\n{\n    _stopping = true;\n\n    log::Server()->info(\"Stopping...\");\n\n    stop_idle_timer();\n    _ioc_pool.Stop();\n}\n\nvoid Server::start_idle_timer()\n{\n    if (!_idle_running)\n    {\n        return;\n    }\n\n    errorcode ec;\n    _idle_timer.expires_from_now(boost::posix_time::seconds(_idle_interval_seconds), ec);\n\n    if (ec)\n    {\n        log::Server()->error(\"Idle timer set expires fail.\");\n        return;\n    }\n\n    _idle_timer.async_wait(std::bind(&Server::on_idle_timer, this, std::placeholders::_1));\n}\n\nvoid appmgr_check_templates_update()\n{\n    AppMgr().CheckTemplatesUpdate();\n}\n\nint Server::call_idle_function_if_timeout(std::time_t now, IdleFunctionStatus& status)\n{\n    int distance_seconds = static_cast<int>(status.next_timepoint - now);\n\n    if (distance_seconds <= 0)\n    {\n        status.func();\n\n        now = std::time(nullptr);\n        status.next_timepoint = now + status.interval_seconds;\n        return status.interval_seconds;\n    }\n\n    return distance_seconds;\n}\n\nvoid update_min_distance_seconds(int& min_distance_seconds, int a_distance_seconds)\n{\n    if (min_distance_seconds <= 0 || min_distance_seconds > a_distance_seconds)\n    {\n        min_distance_seconds = a_distance_seconds;\n    }\n}\n\nvoid Server::on_idle_timer(errorcode const& ec)\n{\n    if (ec)\n    {\n        if (ec != boost::system::errc::operation_canceled)\n        {\n            log::Server()->error(\"Idle timer exception. {}\", ec.message());\n        }\n\n        _idle_running = false;\n        return;\n    }\n\n    std::time_t now = std::time(nullptr);\n    int min_distance_seconds = -1;\n\n    if (_detect_templates)\n    {\n        if (!_detect_templates_status.func)\n        {\n            _detect_templates_status.func = appmgr_check_templates_update;\n        }\n\n        if (_detect_templates_status.interval_seconds <= 0)\n        {\n            _detect_templates_status.interval_seconds = _detect_templates_interval_seconds_;\n        }\n\n        update_min_distance_seconds(min_distance_seconds,\n                                    call_idle_function_if_timeout(now, _detect_templates_status));\n    }\n\n    for (auto& ss : _idle_functions)\n    {\n        update_min_distance_seconds(min_distance_seconds,\n                                    call_idle_function_if_timeout(now, ss));\n    }\n\n    if (min_distance_seconds <= 0)\n    {\n        _idle_running = false;\n    }\n    else\n    {\n        if (_idle_interval_seconds != min_distance_seconds)\n        {\n            _idle_interval_seconds = min_distance_seconds;\n        }\n\n        start_idle_timer();\n    }\n}\n\nvoid Server::stop_idle_timer()\n{\n    errorcode ec;\n\n    _idle_timer.cancel(ec);\n\n    if (ec)\n    {\n        log::Server()->error(\"Cancel idle timer exception. {}\", ec.message());\n    }\n}\n\nvoid Server::PauseIdleTimer()\n{\n    if (_idle_running)\n    {\n        _idle_running = false;\n    }\n}\n\nvoid Server::ResumeIdleTimer()\n{\n    if (_idle_running)\n    {\n        return;\n    }\n\n    _idle_running = true;\n    start_idle_timer();\n}\n\n}//namespace da4qi4\n"
  },
  {
    "path": "src/server_engine.cpp",
    "content": "#include \"daqi/server_engine.hpp\"\n\n#include \"daqi/def/log_def.hpp\"\n#include \"daqi/def/boost_def.hpp\"\n#include \"daqi/def/asio_def.hpp\"\n\nnamespace da4qi4\n{\n\nIOContextPool::IOContextPool(std::size_t pool_size)\n    : _stopping(false), _next_index(0)\n{\n    if (pool_size == 0)\n    {\n        size_t count = std::thread::hardware_concurrency();\n        pool_size = (count > 0) ? count : 1;\n    }\n\n    for (std::size_t i = 0; i < pool_size; ++i)\n    {\n        IOContextPtr ioc(new IOC);\n        _io_contexts.push_back(ioc);\n\n#ifdef HAS_IO_CONTEXT\n        _work.push_back(boost::asio::make_work_guard(*ioc));\n#else\n        _work.push_back(std::make_unique<IOC::work>(*ioc));\n#endif\n    }\n}\n\nvoid init_srand_seed(int thread_index)\n{\n    unsigned int rand_seed = static_cast<unsigned int>(std::time(nullptr) + thread_index * 13);\n    std::srand(rand_seed);\n}\n\nvoid IOContextPool::Run()\n{\n    for (std::size_t i = 0; i < _io_contexts.size(); ++i)\n    {\n        std::shared_ptr<std::thread> thread(new std::thread([i, this]()\n        {\n            init_srand_seed(static_cast<int>(i));\n\n            while (!_stopping)\n            {\n                try\n                {\n                    errorcode ec;\n                    _io_contexts[i]->run(ec);\n\n                    if (ec)\n                    {\n                        log::Server()->error(\"Engine running exception. {0}.\", ec.message());\n                    }\n                }\n                catch (std::exception const& e)\n                {\n                    log::Server()->error(\"Engine running exception. {0}.\", e.what());\n                }\n                catch (std::string const& s)\n                {\n                    log::Server()->error(\"Engine running exception. {0}.\", s);\n                }\n                catch (char const* s)\n                {\n                    log::Server()->error(\"Engine running exception. {0}.\", s);\n                }\n                catch (int const i)\n                {\n                    log::Server()->error(\"Engine running exception. {0}.\", i);\n                }\n                catch (...)\n                {\n                    log::Server()->error(\"Engine running exception. unknown.\");\n                }\n            }\n        }));\n\n        _threads.push_back(thread);\n    }\n\n    for (auto thread_ptr : _threads)\n    {\n        thread_ptr->join();\n    }\n}\n\nvoid IOContextPool::Stop()\n{\n    if (_stopping)\n    {\n        return;\n    }\n\n    _stopping = true;\n\n    for (auto ioc_ptr : _io_contexts)\n    {\n        ioc_ptr->stop();\n    }\n}\n\nIOC& IOContextPool::GetIOContext()\n{\n    return GetIOContextAndIndex().first;\n}\n\nstd::pair<IOC&, size_t> IOContextPool::GetIOContextAndIndex()\n{\n    size_t index = _next_index;\n    IOC& io_context = *_io_contexts[index];\n\n    ++_next_index;\n\n    if (_next_index >= _io_contexts.size())\n    {\n        _next_index = 0;\n    }\n\n    return {io_context, index};\n}\n\nIOC& IOContextPool::GetIOContextByIndex(size_t index)\n{\n    assert(index < _io_contexts.size());\n    return *(_io_contexts[index]);\n}\n\n}\n"
  },
  {
    "path": "src/session.cpp",
    "content": "#include \"daqi/session.hpp\"\n\nnamespace da4qi4\n{\n\nstd::string const session_cookie_name = \"_cookie_\";\n\nJson MakeNewSession(Cookie const& cookie)\n{\n    Json session {{session_cookie_name, cookie}};\n    return session;\n}\n\nCookie GetSessionCookie(Json const& session)\n{\n    Cookie cookie;\n\n    Json::const_iterator it = session.find(session_cookie_name);\n\n    if (it != session.cend())\n    {\n        it->get_to(cookie);\n    }\n\n    return cookie;\n}\n\n} //namespace da4qi4\n"
  },
  {
    "path": "src/templates.cpp",
    "content": "#include \"daqi/templates.hpp\"\n\n#include \"inja/inja.hpp\"\n\n#include \"daqi/def/log_def.hpp\"\n#include \"daqi/def/boost_def.hpp\"\n#include \"daqi/utilities/string_utilities.hpp\"\n#include \"daqi/utilities/file_utilities.hpp\"\n\nnamespace da4qi4\n{\n\nstd::string const daqi_HTML_template_ext = \".daqi.HTML\";\nstd::string const daqi_JSON_template_ext = \".daqi.JSON\";\nstd::string const daqi_XML_template_ext = \".daqi.XML\";\n\nstd::string const& get_daqi_HTML_template_ext()\n{\n    return daqi_HTML_template_ext;\n}\n\nstd::string const& get_daqi_JSON_template_ext()\n{\n    return daqi_JSON_template_ext;\n}\n\nstd::string const& get_daqi_XML_template_ext()\n{\n    return daqi_XML_template_ext;\n}\n\nstd::string make_daqi_template_ext(std::string const& ext)\n{\n    return std::string(\".daqi\") + (ext.empty() ? \"\" : (ext[0] == '.' ? ext : (\".\" + ext)));\n}\n\nvoid init_template_env(inja::Environment& env)\n{\n    env.set_expression(\"{=\", \"=}\");\n\n    env.set_comment(\"{#\", \"#}\");\n    env.set_statement(\"{%\", \"%}\");\n    env.set_line_statement(\"##\");\n\n    env.set_element_notation(inja::ElementNotation::Dot);\n\n    env.set_trim_blocks(true);\n    env.set_lstrip_blocks(true);\n}\n\nstd::string remove_template_ext(std::string const& fn, std::string const& ext)\n{\n    return (Utilities::EndsWith(fn, ext)) ?\n           fn.substr(0, fn.length() - ext.length()) : fn;\n}\n\nbool is_include_dir(fs::path const& path)\n{\n    return (path.native().find(\"/i/\") != std::string::npos\n            || path.native().find(\"\\\\i\\\\\") != std::string::npos);\n}\n\nbool Templates::try_load_template(TemplatesEnv& env\n                                  , std::string const& key\n                                  , std::string const& template_filename\n                                  , std::string const& full_template_filename\n                                  , bool is_include_dir) noexcept\n{\n    try\n    {\n        std::string tmpl_src = env.load_file(template_filename);\n\n        if (tmpl_src.empty())\n        {\n            _app_logger->error(\"Template read fail. \\\"{}\\\".\", full_template_filename);\n            return false;\n        }\n\n        TemplatePtr templ = TemplatePtr(new Template(env.parse(tmpl_src)));\n        Item item {templ, full_template_filename};\n\n        if (is_include_dir)\n        {\n            env.include_template(key, *templ);\n            _includes_templates.insert(std::make_pair(key, std::move(item)));\n        }\n        else\n        {\n            _templates.insert(std::make_pair(key, std::move(item)));\n        }\n\n        _app_logger->info(\"Template load success. \\\"{}\\\". {}.\",\n                          remove_template_ext(template_filename, _template_ext), key);\n        return true;\n    }\n    catch (std::exception const& e)\n    {\n        _app_logger->error(\"Template load exception. {}. \\\"{}\\\". {}.\", e.what()\n                           , full_template_filename, key);\n        return false;\n    }\n    catch (...)\n    {\n        _app_logger->error(\"Template load exception. \\\"{}\\\". {}.\", full_template_filename, key);\n        return false;\n    }\n}\n\nbool is_ignored(fs::path const& path)\n{\n    std::string const& path_s = path.string();\n\n    return (path.empty()\n            || path_s.find(\"/_alternate/\") != std::string::npos\n            || path_s.find(\"/_deprecated/\") != std::string::npos\n            || path_s.find(\".deprecated.\") != std::string::npos);\n}\n\nstd::pair<size_t, size_t> Templates::load_templates(std::string const& template_ext\n                                                    , std::string const& key_ext)\n{\n    TemplatesEnv env(_root);\n    init_template_env(env);\n\n    std::pair<size_t, size_t> counts_i = load_templates(env, template_ext, key_ext\n                                                        , TemplateFlag::for_include);\n\n    std::pair<size_t, size_t> counts = load_templates(env, template_ext, key_ext\n                                                      , TemplateFlag::for_normal);\n\n    return { counts_i.first + counts.first, counts_i.second + counts.second };\n}\n\nstd::string make_template_key(std::string const& app_prefix, std::string const& mpath\n                              , std::string const& key_ext)\n{\n    std::string key;\n    key.reserve(app_prefix.size() + mpath.size() + key_ext.size() + 1);\n\n    key = app_prefix;\n\n    if (app_prefix.empty() || mpath.empty()\n        || *(--app_prefix.end()) != '/' || *(mpath.begin()) != '/')\n    {\n        key += mpath;\n    }\n    else\n    {\n        key += mpath.substr(1);\n    }\n\n    key += key_ext;\n\n    return key;\n}\n\nstd::pair<size_t, size_t> Templates::load_templates(TemplatesEnv& env,\n                                                    std::string const& template_ext,\n                                                    std::string const& key_ext,\n                                                    TemplateFlag flag)\n{\n    fs::path root(_root);\n\n    if (!fs::is_directory((root)) || !fs::exists(root))\n    {\n        return {0, 0};\n    }\n\n    size_t ok = 0, fail = 0;\n\n    fs::recursive_directory_iterator iter(root);\n    fs::recursive_directory_iterator end_iter;\n\n    for (; iter != end_iter; ++iter)\n    {\n        if (fs::is_regular_file(*iter))\n        {\n            fs::path const& path = *iter;\n\n            if (Utilities::EndsWith(path.filename().native(), template_ext))\n            {\n                if (is_ignored(path))\n                {\n                    continue;\n                }\n\n                bool is_include = is_include_dir(path.string());\n\n                if ((flag == TemplateFlag::for_normal && is_include)\n                    || (flag == TemplateFlag::for_include && !is_include))\n                {\n                    continue;\n                }\n\n                std::string::size_type len = path.size();\n                std::string::size_type root_len = root.size();\n                std::string mpath = path.string()./*native().*/\n                                    substr(root_len, len - root_len - template_ext.size());\n\n                if (!mpath.empty())\n                {\n                    std::string template_filename = mpath + template_ext;\n                    std::string key = make_template_key(_app_prefix, mpath, key_ext);\n\n                    if (try_load_template(env, key, template_filename, path.string(), is_include))\n                    {\n                        ++ok;\n                    }\n                    else\n                    {\n                        ++fail;\n                    }\n                }\n            }\n        }\n    }\n\n    return {ok, fail};\n}\n\nbool Templates::reload()\n{\n    return (!_app_logger) ? false : Preload(_app_logger);\n}\n\nvoid Templates::CopyIncludeTemplateTo(TemplatesEnv& env)\n{\n    for (auto pair : _includes_templates)\n    {\n        env.include_template(pair.first, *(pair.second.templ));\n    }\n}\n\nbool Templates::Preload(log::LoggerPtr app_logger)\n{\n    if (_app_logger != app_logger)\n    {\n        _app_logger = app_logger;\n    }\n\n    if (this->_disabled || this->_root.empty() || this->_template_ext.empty())\n    {\n        _app_logger->info(\"Templates is undesired.\");\n        return true;\n    }\n\n    std::lock_guard<std::mutex> _guard_(_m);\n\n    _templates.clear();\n    _includes_templates.clear();\n\n    try\n    {\n        auto counts = load_templates(_template_ext, Utilities::theEmptyString);\n        _loaded_time = std::time(nullptr);\n        app_logger->info(\"Templates loaded. {} success, {} fail.\", counts.first, counts.second);\n\n        return true;\n    }\n    catch (fs::filesystem_error const& ec)\n    {\n        _app_logger->error(\"Template file \\\"{}\\\" load exception.\", ec.what());\n    }\n    catch (std::exception const& ec)\n    {\n        _app_logger->error(\"Template file \\\"{}\\\" load exception.\", ec.what());\n    }\n    catch (...)\n    {\n        _app_logger->error(\"Template file load unknown exception.\");\n    }\n\n    return false;\n}\n\nTemplatePtr const Templates::Get(std::string const& name)\n{\n    std::lock_guard<std::mutex> _guard_(_m);\n\n    auto it = _templates.find(name);\n\n    if (it == _templates.end())\n    {\n        return nullptr;\n    }\n\n    return it->second.templ;\n}\n\nvoid Templates::hint_template_updated_found(TemplateUpdateAction action)\n{\n    switch (action)\n    {\n        case TemplateUpdateAction::appended:\n            _app_logger->info(\"Detects template appended.\");\n            break;\n\n        case TemplateUpdateAction::modified:\n            _app_logger->info(\"Detects template modified.\");\n            break;\n\n        case TemplateUpdateAction::removed:\n            _app_logger->info(\"Detects template removed.\");\n            break;\n\n        default:\n            break;\n    }\n}\n\nvoid Templates::hint_template_reload_fail()\n{\n    _app_logger->error(\"Templates reload fail.\");\n}\n\nbool Templates::ReloadIfFindUpdate()\n{\n    if (this->_disabled)\n    {\n        return true;\n    }\n\n    auto r = check_exists_template();\n\n    if (r == TemplateUpdateAction::none)\n    {\n        return false;\n    }\n\n    hint_template_updated_found(r);\n\n    if (reload())\n    {\n        return true;\n    }\n\n    hint_template_reload_fail();\n    return false;\n}\n\nTemplates::TemplateUpdateAction\nTemplates::check_exists_template(std::unordered_map<std::string, Item> const& templates)\n{\n    TemplateUpdateAction action = TemplateUpdateAction::none;\n\n    for (auto item : templates)\n    {\n        auto fp = fs::path(item.second.filename);\n\n        if (!Utilities::IsFileExists(fp))\n        {\n            action = TemplateUpdateAction::removed;\n            break;\n        }\n\n        errorcode ec;\n        std::time_t t = fs::last_write_time(fp, ec);\n\n        if (ec)\n        {\n            _app_logger->warn(\"Check templates file \\\"{}\\\" last-write-time exception. {}\",\n                              item.second.filename, ec.message());\n        }\n        else if (t > _loaded_time)\n        {\n            action = TemplateUpdateAction::modified;\n            break;\n        }\n    }\n\n    return action;\n}\n\nTemplates::TemplateUpdateAction Templates::check_exists_template()\n{\n    TemplateUpdateAction action = check_exists_template(_templates);\n\n    if (action != TemplateUpdateAction::none)\n    {\n        return action;\n    }\n\n    return check_exists_template(_includes_templates);\n}\n\nbool Templates::ReloadIfFindNew()\n{\n    if (this->_disabled)\n    {\n        return true;\n    }\n\n    auto r = check_new_template(_template_ext, Utilities::theEmptyString);\n\n    if (r == TemplateUpdateAction::none)\n    {\n        return false;\n    }\n\n    hint_template_updated_found(r);\n\n    if (reload())\n    {\n        return true;\n    }\n\n    hint_template_reload_fail();\n    return false;\n}\n\nTemplates::TemplateUpdateAction Templates::check_new_template(std::string const& template_ext,\n                                                              std::string const& key_ext)\n{\n    fs::path root(_root);\n\n    if (!fs::is_directory((root)) || !fs::exists(root))\n    {\n        return TemplateUpdateAction::none;\n    }\n\n    fs::recursive_directory_iterator iter(root);\n    fs::recursive_directory_iterator end_iter;\n\n    for (; iter != end_iter; ++iter)\n    {\n        if (fs::is_regular_file(*iter))\n        {\n            fs::path const& path = *iter;\n\n            if (Utilities::EndsWith(path.filename().native(), template_ext))\n            {\n                if (is_ignored(path))\n                {\n                    continue;\n                }\n\n                std::string::size_type len = path.size();\n                std::string::size_type root_len = root.size();\n                std::string mpath = path.native().substr(root_len\n                                                         , len - root_len - template_ext.size());\n\n                if (!mpath.empty())\n                {\n                    bool is_include = is_include_dir(path);\n                    std::string key = make_template_key(_app_prefix, mpath, key_ext);\n\n                    std::lock_guard<std::mutex> _guard_(_m);\n\n                    if ((!is_include && (_templates.find(key) == _templates.cend()))\n                        || (is_include && (_includes_templates.find(key)\n                                           == _includes_templates.cend())))\n                    {\n                        return TemplateUpdateAction::appended;\n                    }\n                }\n            }\n        }\n    }\n\n    return TemplateUpdateAction::none;\n}\n\n\n} //namespace da4qi4\n"
  },
  {
    "path": "src/url.cpp",
    "content": "#include \"daqi/url.hpp\"\n\n#include <cassert>\n\n#include \"daqi/utilities/http_utilities.hpp\"\n\n#include \"llhttp/helper/http_url_def.h\"\n\nnamespace da4qi4\n{\n\nnamespace\n{\nbool get_url_part_value(unsigned int url_part_flag,  UrlBase& url, std::string&& value)\n{\n    switch (url_part_flag)\n    {\n        case UF_SCHEMA :\n            url.schema = std::move(value);\n            break;\n\n        case UF_HOST :\n            url.host = std::move(value);\n            break;\n\n        case UF_PORT:\n            break; //skip, but return true;\n\n        case UF_PATH :\n            url.path = std::move(value);\n            break;\n\n        case UF_QUERY :\n            url.query = std::move(value);\n            break;\n\n        case UF_FRAGMENT :\n            url.fragment = std::move(value);\n            break;\n\n        case UF_USERINFO :\n            url.userinfo = std::move(value);\n            break;\n\n        default:\n            return false;\n    }\n\n    return true;\n}\n}\n\nbool UrlBase::Parse(std::string&& url_value)\n{\n    http_parser_url r;\n    http_parser_url_init(&r);\n    int err = http_parser_parse_url(url_value.c_str(), url_value.length(), 0, &r);\n\n    if (0 == err)\n    {\n        port = r.port;\n\n        for (unsigned int i = 0; i < UF_MAX; ++i)\n        {\n            if ((r.field_set & (1 << i)) == 0)\n            {\n                continue;\n            }\n\n            std::string part(url_value.c_str() + r.field_data[i].off, r.field_data[i].len);\n            get_url_part_value(i, *this, std::move(part));\n        }\n\n        if (!query.empty())\n        {\n            parameters = Utilities::ParseQueryParameters(query);\n        }\n    }\n\n    full = std::move(url_value);\n\n    return !err;\n}\n\nvoid UrlUnderApp::UnderApplication(std::string const& app_url_root)\n{\n    assert(Utilities::iStartsWith(full, app_url_root));\n    assert(Utilities::iStartsWith(path, app_url_root));\n\n    full_under_app = full.substr(app_url_root.size());\n    path_under_app = path.substr(app_url_root.size());\n}\n\nUrlBase FromUrlUnderApp(UrlUnderApp&& src)\n{\n    UrlBase dst;\n    dst.port = src.port;\n\n#define MOVE_FROM_APP_URL(D, I, S) D.I = std::move(S.I)\n\n    MOVE_FROM_APP_URL(dst, full, src);\n    MOVE_FROM_APP_URL(dst, schema, src);\n    MOVE_FROM_APP_URL(dst, host, src);\n    MOVE_FROM_APP_URL(dst, path, src);\n    MOVE_FROM_APP_URL(dst, query, src);\n    MOVE_FROM_APP_URL(dst, fragment, src);\n    MOVE_FROM_APP_URL(dst, userinfo, src);\n    MOVE_FROM_APP_URL(dst, parameters, src);\n\n#undef MOVE_FROM_APP_URL\n\n    return dst;\n}\n\n\nstd::string JoinUrlPath(std::string const& app_root, std::string const& path)\n{\n    if (!path.empty() && !app_root.empty())\n    {\n        if (*app_root.rbegin() == '/' && *path.begin() == '/')\n        {\n            return app_root + path.substr(1, path.size() - 1);\n        }\n\n        if (*app_root.rbegin() != '/' && *path.begin() != '/')\n        {\n            return app_root + \"/\" + path;\n        }\n    }\n\n    return app_root + path;\n}\n\nstd::string MakesureFullUrlPath(std::string const& path, UrlFlag flag, const std::string& app_root)\n{\n    return (flag == UrlFlag::url_full_path) ? path : JoinUrlPath(app_root, path);\n}\n\n\n} // namespace da4qi4\n"
  },
  {
    "path": "src/utilities/asio_utilities.cpp",
    "content": "#include \"daqi/utilities/asio_utilities.hpp\"\n\nnamespace da4qi4\n{\nnamespace Utilities\n{\n\nTcp::endpoint make_endpoint(char const* host, unsigned short port)\n{\n    boost::asio::ip::address adr = boost::asio::ip::address::from_string(host);\n    return Tcp::endpoint(adr, port);\n}\n\nTcp::endpoint make_endpoint(std::string const& host, unsigned short port)\n{\n    return make_endpoint(host.c_str(), port);\n}\n\nstd::vector<Tcp::endpoint> from_http_host_sync(std::string const& host\n                                               , std::string const& service\n                                               , IOC& ioc, std::string& exception)\n{\n    Tcp::resolver resolver(ioc);\n    Tcp::resolver::query query(host, service);\n\n    std::vector<Tcp::endpoint> result;\n\n    try\n    {\n        auto it = resolver.resolve(query);\n\n        if (it == Tcp::resolver::iterator())\n        {\n            return result;\n        }\n\n        for (; it != Tcp::resolver::iterator(); ++it)\n        {\n            result.emplace_back(*it);\n        }\n    }\n    catch (std::exception const& e)\n    {\n        exception = e.what();\n    }\n\n    return result;\n}\n//\nvoid from_host(std::string const& host,  std::string const& service,\n               Tcp::resolver& resolver,\n               HostResolveHandler handler)\n{\n    Tcp::resolver::query query(host, service);\n    resolver.async_resolve(query, handler);\n}\n\nResolverResultT from_host(std::string const& host\n                          , std::string const& service\n                          , Tcp::resolver& resolver\n                          , errorcode& ec)\n{\n    Tcp::resolver::query query(host, service);\n    return resolver.resolve(query, ec);\n}\n\n} //namespace Utilities\n} //namespace da4qi4\n"
  },
  {
    "path": "src/utilities/base64_utilities.cpp",
    "content": "//\n// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)\n//\n// Distributed under the Boost Software License, Version 1.0. (See accompanying\n// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)\n//\n// Official repository: https://github.com/boostorg/beast\n//\n\n/*\n   Portions from http://www.adp-gmbh.ch/cpp/common/base64.html\n   Copyright notice:\n\n   base64.cpp and base64.h\n\n   Copyright (C) 2004-2008 Rene Nyffenegger\n\n   This source code is provided 'as-is', without any express or implied\n   warranty. In no event will the author be held liable for any damages\n   arising from the use of this software.\n\n   Permission is granted to anyone to use this software for any purpose,\n   including commercial applications, and to alter it and redistribute it\n   freely, subject to the following restrictions:\n\n   1. The origin of this source code must not be misrepresented; you must not\n      claim that you wrote the original source code. If you use this source code\n      in a product, an acknowledgment in the product documentation would be\n      appreciated but is not required.\n\n   2. Altered source versions must be plainly marked as such, and must not be\n      misrepresented as being the original source code.\n\n   3. This notice may not be removed or altered from any source distribution.\n\n   Rene Nyffenegger rene.nyffenegger@adp-gmbh.ch\n\n*/\n\n#include \"daqi/utilities/base64_utilities.hpp\"\n\n#include <utility>\n\nnamespace da4qi4\n{\nnamespace Utilities\n{\n\nnamespace base64\n{\n\nchar const* get_alphabet()\n{\n    static char constexpr tab[] =\n    {\n        \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\"\n    };\n    return &tab[0];\n}\n\nsigned char const* get_inverse()\n{\n    static signed char constexpr tab[] =\n    {\n        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //   0-15\n            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //  16-31\n            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, //  32-47\n            52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, //  48-63\n            -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, //  64-79\n            15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, //  80-95\n            -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, //  96-111\n            41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, // 112-127\n            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 128-143\n            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 144-159\n            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 160-175\n            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 176-191\n            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 192-207\n            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 208-223\n            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 224-239\n            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1  // 240-255\n        };\n    return &tab[0];\n}\n\n\n/// Returns max chars needed to encode a base64 string\nstd::size_t constexpr encoded_size(std::size_t n)\n{\n    return 4 * ((n + 2) / 3);\n}\n\n/// Returns max bytes needed to decode a base64 string\nstd::size_t constexpr decoded_size(std::size_t n)\n{\n    return n / 4 * 3; // requires n&3==0, smaller\n    //return 3 * n / 4;\n}\n\n/** Encode a series of octets as a padded, base64 string.\n\n    The resulting string will not be null terminated.\n\n    @par Requires\n\n    The memory pointed to by `out` points to valid memory\n    of at least `encoded_size(len)` bytes.\n\n    @return The number of characters written to `out`. This\n    will exclude any null termination.\n*/\nstd::size_t encode(void* dest, void const* src, std::size_t len)\n{\n    char*      out = static_cast<char*>(dest);\n    char const* in = static_cast<char const*>(src);\n    auto const tab = base64::get_alphabet();\n\n    for (auto n = len / 3; n--;)\n    {\n        *out++ = tab[(in[0] & 0xfc) >> 2];\n        *out++ = tab[((in[0] & 0x03) << 4) + ((in[1] & 0xf0) >> 4)];\n        *out++ = tab[((in[2] & 0xc0) >> 6) + ((in[1] & 0x0f) << 2)];\n        *out++ = tab[  in[2] & 0x3f];\n        in += 3;\n    }\n\n    switch (len % 3)\n    {\n        case 2:\n            *out++ = tab[(in[0] & 0xfc) >> 2];\n            *out++ = tab[((in[0] & 0x03) << 4) + ((in[1] & 0xf0) >> 4)];\n            *out++ = tab[(in[1] & 0x0f) << 2];\n            *out++ = '=';\n            break;\n\n        case 1:\n            *out++ = tab[(in[0] & 0xfc) >> 2];\n            *out++ = tab[((in[0] & 0x03) << 4)];\n            *out++ = '=';\n            *out++ = '=';\n            break;\n\n        case 0:\n            break;\n    }\n\n    return static_cast<std::size_t>(out - static_cast<char*>(dest));\n}\n\n/** Decode a padded base64 string into a series of octets.\n\n    @par Requires\n\n    The memory pointed to by `out` points to valid memory\n    of at least `decoded_size(len)` bytes.\n\n    @return The number of octets written to `out`, and\n    the number of characters read from the input string,\n    expressed as a pair.\n*/\nstd::pair<std::size_t, std::size_t> decode(void* dest, char const* src, std::size_t len)\n{\n    char* out = static_cast<char*>(dest);\n    auto in = reinterpret_cast<unsigned char const*>(src);\n    unsigned char c3[3], c4[4];\n    int i = 0;\n    int j = 0;\n\n    auto const inverse = base64::get_inverse();\n\n    while (len-- && *in != '=')\n    {\n        auto const v = inverse[*in];\n\n        if (v == -1)\n        {\n            break;\n        }\n\n        ++in;\n        c4[i] = static_cast<unsigned char>(v);\n\n        if (++i == 4)\n        {\n            c3[0] = static_cast<unsigned char>((c4[0] << 2) + ((c4[1] & 0x30) >> 4));\n            c3[1] = static_cast<unsigned char>(((c4[1] & 0xf) << 4) + ((c4[2] & 0x3c) >> 2));\n            c3[2] = static_cast<unsigned char>(((c4[2] & 0x3) << 6) +   c4[3]);\n\n            for (i = 0; i < 3; i++)\n            {\n                *out++ = static_cast<char>(c3[i]);\n            }\n\n            i = 0;\n        }\n    }\n\n    if (i)\n    {\n        c3[0] = static_cast<unsigned char>((c4[0] << 2) + ((c4[1] & 0x30) >> 4));\n        c3[1] = static_cast<unsigned char>(((c4[1] & 0xf) << 4) + ((c4[2] & 0x3c) >> 2));\n        c3[2] = static_cast<unsigned char>(((c4[2] & 0x3) << 6) +   c4[3]);\n\n        for (j = 0; j < i - 1; j++)\n        {\n            *out++ = static_cast<char>(c3[j]);\n        }\n    }\n\n    return {out - static_cast<char*>(dest),\n            in - reinterpret_cast<unsigned char const*>(src)};\n}\n\n}//namespace base64\n\nstatic std::string base64_encode(std::uint8_t const* data, std::size_t len)\n{\n    std::string dest;\n    dest.resize(base64::encoded_size(len));\n    dest.resize(base64::encode(&dest[0], data, len));\n    return dest;\n}\n\nstatic std::string base64_encode(std::string const& s)\n{\n    return base64_encode(reinterpret_cast <\n                         std::uint8_t const* >(s.data()), s.size());\n}\n\nstatic std::string base64_decode(std::string const& data)\n{\n    std::string dest;\n    dest.resize(base64::decoded_size(data.size()));\n    auto const result = base64::decode(\n                                    &dest[0], data.data(), data.size());\n    dest.resize(result.first);\n    return dest;\n}\n\nstd::string Base64Encode(std::uint8_t const* value, std::size_t len)\n{\n    return base64_encode(value, len);\n}\n\nstd::string Base64Encode(std::string const& value)\n{\n    return base64_encode(value);\n}\n\nstd::string Base64Decode(std::string const& base64)\n{\n    return base64_decode(base64);\n}\n\n} // namespace Utilities\n} // namespace da4qi4\n"
  },
  {
    "path": "src/utilities/des3_utilities.cpp",
    "content": "#include \"daqi/utilities/des3_utilities.hpp\"\n\n#include <cstdlib>\n#include <cstring>\n#include <vector>\n\n#include \"openssl/des.h\"\n\nnamespace da4qi4\n{\nnamespace Utilities\n{\n\nstd::string DESEncrypt(std::string const& clearText, std::string const& key)\n{\n    DES_cblock keyEncrypt;\n    std::memset(keyEncrypt, 0, 8);\n\n    if (key.length() <= 8)\n    {\n        std::memcpy(keyEncrypt, key.c_str(), key.length());\n    }\n    else\n    {\n        std::memcpy(keyEncrypt, key.c_str(), 8);\n    }\n\n    DES_key_schedule keySchedule;\n    DES_set_key_unchecked(&keyEncrypt, &keySchedule);\n\n    const_DES_cblock inputText;\n    DES_cblock outputText;\n    std::vector<unsigned char> vecCiphertext;\n    unsigned char tmp[8];\n\n    for (std::size_t i = 0; i < clearText.length() / 8; i++)\n    {\n        std::memcpy(inputText, clearText.c_str() + i * 8, 8);\n        DES_ecb_encrypt(&inputText, &outputText, &keySchedule, DES_ENCRYPT);\n        std::memcpy(tmp, outputText, 8);\n\n        for (int j = 0; j < 8; j++)\n        {\n            vecCiphertext.push_back(tmp[j]);\n        }\n    }\n\n    if (clearText.length() % 8 != 0)\n    {\n        std::size_t tmp1 = clearText.length() / 8 * 8;\n        std::size_t tmp2 = clearText.length() - tmp1;\n        std::memset(inputText, 0, 8);\n        std::memcpy(inputText, clearText.c_str() + tmp1, tmp2);\n\n        DES_ecb_encrypt(&inputText, &outputText, &keySchedule, DES_ENCRYPT);\n        std::memcpy(tmp, outputText, 8);\n\n        for (int j = 0; j < 8; j++)\n        {\n            vecCiphertext.push_back(tmp[j]);\n        }\n    }\n\n    std::string cipherText;\n    cipherText.reserve(vecCiphertext.size());\n    cipherText.assign(vecCiphertext.begin(), vecCiphertext.end());\n\n    return cipherText;\n}\n\nstd::string DESDecrypt(std::string const& cipherText, std::string const& key)\n{\n    DES_cblock keyEncrypt;\n    std::memset(keyEncrypt, 0, 8);\n\n    if (key.length() <= 8)\n    {\n        std::memcpy(keyEncrypt, key.c_str(), key.length());\n    }\n    else\n    {\n        std::memcpy(keyEncrypt, key.c_str(), 8);\n    }\n\n    DES_key_schedule keySchedule;\n    DES_set_key_unchecked(&keyEncrypt, &keySchedule);\n\n    const_DES_cblock inputText;\n    DES_cblock outputText;\n    std::vector<unsigned char> vecCleartext;\n    unsigned char tmp[8];\n\n    for (std::size_t i = 0; i < cipherText.length() / 8; i++)\n    {\n        std::memcpy(inputText, cipherText.c_str() + i * 8, 8);\n        DES_ecb_encrypt(&inputText, &outputText, &keySchedule, DES_DECRYPT);\n        std::memcpy(tmp, outputText, 8);\n\n        for (std::size_t j = 0; j < 8 && tmp[j]; j++)\n        {\n            vecCleartext.push_back(tmp[j]);\n        }\n    }\n\n    if (cipherText.length() % 8 != 0)\n    {\n        std::size_t tmp1 = cipherText.length() / 8 * 8;\n        std::size_t tmp2 = cipherText.length() - tmp1;\n\n        std::memset(inputText, 0, 8);\n        std::memcpy(inputText, cipherText.c_str() + tmp1, tmp2);\n        DES_ecb_encrypt(&inputText, &outputText, &keySchedule, DES_DECRYPT);\n        std::memcpy(tmp, outputText, 8);\n\n        for (int j = 0; j < 8 && tmp[j]; j++)\n        {\n            vecCleartext.push_back(tmp[j]);\n        }\n    }\n\n    std::string clearText;\n    clearText.reserve(vecCleartext.size());\n    clearText.assign(vecCleartext.begin(), vecCleartext.end());\n\n    return clearText;\n}\n\n} // namespace Utilities\n} // namespace da4qi4\n"
  },
  {
    "path": "src/utilities/encoding_utilities.cpp",
    "content": "#include \"daqi/utilities/encoding_utilities.hpp\"\n\n#include <vector>\n\nnamespace da4qi4\n{\nnamespace Utilities\n{\n\nnamespace iconvpp\n{\n\nConverter::Converter(char const* in_encode, char const* out_encode,\n                     bool _ignore_error, std::size_t const& buf_size)\n    : _iconv(nullptr), _ignore_error(_ignore_error), _buf_size(buf_size), _ignore_count(0)\n{\n    if (buf_size < 4 || buf_size >= 10 * 1024 * 1024)\n    {\n        _err = \"bad convert buffer size : \" + std::to_string(buf_size) + \".\";\n        return;\n    }\n\n    iconv_t h = ::iconv_open(out_encode, in_encode);\n\n    if (h == reinterpret_cast<iconv_t>(-1))\n    {\n        if (errno == EINVAL)\n        {\n            _err = std::string(\"not supported from \") + in_encode + \" to \" + out_encode;\n        }\n        else\n        {\n            _err = \"unknown error on iconv_open.\";\n        }\n\n        return;\n    }\n\n    _iconv = h;\n}\n\nConverter::~Converter()\n{\n    if (_iconv && (_iconv != reinterpret_cast<iconv_t>(-1)))\n    {\n        iconv_close(_iconv);\n    }\n}\n\nbool Converter::Convert(std::string const& input, std::string& output)\n{\n    if (!*this)\n    {\n        return false;\n    }\n\n    _ignore_count = 0;\n    std::vector<char> in_buf(input.begin(), input.end());\n\n    char* src_ptr = &in_buf[0];\n    size_t src_size = input.size();\n\n    std::vector<char> buf(_buf_size);\n    std::string dst;\n\n    while (src_size > 0)\n    {\n        char* dst_ptr = &buf[0];\n        size_t dst_size = buf.size();\n        size_t res = ::iconv(_iconv, &src_ptr, &src_size, &dst_ptr, &dst_size);\n\n        if (res == static_cast<size_t>(-1))\n        {\n            if (errno == E2BIG)\n            {\n                ;// ignore this error\n            }\n            else if (_ignore_error)\n            {\n                ++src_ptr;\n                --src_size;\n                ++_ignore_count;\n            }\n            else if (errno == EILSEQ)\n            {\n                _err = \"invalid multibyte chars : EILSEQ.\";\n                break;\n            }\n            else if (errno == EINVAL)\n            {\n                _err = \"invalid multibyte chars : EINVAL.\";\n                break;\n            }\n        }\n\n        dst.append(&buf[0], _buf_size - dst_size);\n    }\n\n    if (!(*this))\n    {\n        return false;\n    }\n\n    dst.swap(output);\n    return true;\n}\n\n} //namesapce iconvpp\n\nconstexpr bool WCHAR_HAS_4_BYTES()\n{\n    return sizeof(wchar_t) == 4;\n}\n\nconstexpr bool WCHAR_HAS_2_BYTES()\n{\n    return sizeof(wchar_t) == 2;\n}\n\n//bool IS_LITTER_ENDIAN()\n//{\n//    union UN\n//    {\n//        char c;\n//        int i;\n//    } un;\n//    un.i = 1;\n\n//    return un.c == 1;\n//}\n\nstd::wstring FromUTF8(std::string const& utf8str, std::string& err)\n{\n    if (!WCHAR_HAS_4_BYTES() && !WCHAR_HAS_2_BYTES())\n    {\n        err = \"only support wchat_t with 2 or 4 bytes.\";\n        return std::wstring();\n    }\n\n    iconvpp::Converter cvter(\"UTF-8\"\n                             , ((WCHAR_HAS_4_BYTES()) ? \"UCS-4\" : \"UCS-2\")\n                             , true);\n\n    if (!cvter)\n    {\n        err = cvter.Error();\n        return std::wstring();\n    }\n\n    std::string output;\n\n    if (!cvter.Convert(utf8str, output))\n    {\n        err = cvter.Error();\n        return std::wstring();\n    }\n\n    std::wstring ws;\n    ws.reserve(output.size() / sizeof(wchar_t));\n\n    for (std::size_t i = 0; i < output.size(); i += sizeof(wchar_t))\n    {\n        wchar_t wc = static_cast<wchar_t>(0);\n\n        if (WCHAR_HAS_4_BYTES())\n        {\n            wchar_t b4 = output[i];\n            wchar_t b3 = output[i + 1];\n            wchar_t b2 = output[i + 2];\n            wchar_t b1 = output[i + 3];\n            wc = static_cast<wchar_t>((static_cast<unsigned int>(b4 << 24) & 0xFF000000)\n                                      | ((b3 << 16) & 0x00FF0000)\n                                      | ((b2 << 8) & 0x0000FF00)\n                                      | (b1 & 0x000000FF)); //TODO : how about BIG-ENDIAN?\n        }\n        else\n        {\n            wchar_t b2 = output[i];\n            wchar_t b1 = output[i + 1];\n            wc = (b2 << 8) | b1;\n        }\n\n        ws.push_back(wc);\n    }\n\n    return ws;\n}\n\nstd::string ToUTF8(std::wstring const& wstr, std::string& err)\n{\n    if (!WCHAR_HAS_4_BYTES() && !WCHAR_HAS_2_BYTES())\n    {\n        err = \"only support wchat_t with 2 or 4 bytes.\";\n        return std::string();\n    }\n\n    iconvpp::Converter cvter(((WCHAR_HAS_4_BYTES()) ? \"UCS-4\" : \"UCS-2\"), \"UTF-8\", true);\n\n    if (!cvter)\n    {\n        err = cvter.Error();\n        return std::string();\n    }\n\n    std::string input;\n    input.reserve(wstr.size() * sizeof(wchar_t));\n\n    for (std::size_t i = 0; i < wstr.size(); ++i)\n    {\n        wchar_t wc = wstr[i];\n\n        if (WCHAR_HAS_4_BYTES())\n        {\n            char b4 = static_cast<char>((static_cast<unsigned int>(wc) & 0xFF000000) >> 24);\n            char b3 = static_cast<char>((wc & 0x00FF0000) >> 16);\n            char b2 = static_cast<char>((wc & 0x0000FF00) >> 8);\n            char b1 = static_cast<char>((wc & 0x000000FF));\n            input.push_back(b4);\n            input.push_back(b3);\n            input.push_back(b2);\n            input.push_back(b1);\n        }\n        else\n        {\n            char b2 = static_cast<char>((static_cast<unsigned int>(wc) & 0xFF00) >> 8);\n            char b1 = static_cast<char>((wc & 0x00FF));\n            input.push_back(b2);\n            input.push_back(b1);\n        }\n    }\n\n    std::string output;\n\n    if (!cvter.Convert(input, output))\n    {\n        err = cvter.Error();\n        return std::string();\n    }\n\n    return output;\n}\n\nstd::wstring FromUTF8(std::string const& utf8str)\n{\n    std::string err;\n    return FromUTF8(utf8str, err);\n}\n\nstd::string ToUTF8(std::wstring const& wstr)\n{\n    std::string err;\n    return ToUTF8(wstr, err);\n}\n\nstd::string ToGBK(std::string const& utf8str, std::string& err)\n{\n    iconvpp::Converter cvter(\"UTF-8\", \"GBK\", true);\n\n    if (!cvter)\n    {\n        err = cvter.Error();\n        return std::string();\n    }\n\n    std::string output;\n\n    if (!cvter.Convert(utf8str, output))\n    {\n        err = cvter.Error();\n        return std::string();\n    }\n\n    return output;\n}\n\nstd::string ToGBK(std::string const& utf8str)\n{\n    std::string err;\n    return ToGBK(utf8str, err);\n}\n\nstd::string FromGBK(std::string const& gbkstr, std::string& err)\n{\n    iconvpp::Converter cvter(\"GBK\", \"UTF-8\", true);\n\n    if (!cvter)\n    {\n        err = cvter.Error();\n        return std::string();\n    }\n\n    std::string output;\n\n    if (!cvter.Convert(gbkstr, output))\n    {\n        err = cvter.Error();\n        return std::string();\n    }\n\n    return output;\n}\n\nstd::string FromGBK(std::string const& gbkstr)\n{\n    std::string err;\n    return FromGBK(gbkstr, err);\n}\n\n} //namespace Utilities\n} //namespace da4qi4\n"
  },
  {
    "path": "src/utilities/file_utilities.cpp",
    "content": "#include \"daqi/utilities/file_utilities.hpp\"\n\n#include <fstream>\n\n#include \"daqi/def/debug_def.hpp\"\n#include \"daqi/def/boost_def.hpp\"\n\nnamespace da4qi4\n{\nnamespace Utilities\n{\n\nbool SaveDataToFile(std::string const& data, std::string const& filename_with_path, std::string& err)\n{\n    fs::path f(filename_with_path);\n    return SaveDataToFile(data, f, err);\n}\n\nbool SaveDataToFile(std::string const& data, fs::path const& filename_with_path, std::string& err)\n{\n    bool dir_exists = false;\n\n    try\n    {\n        fs::path dir_path = filename_with_path.parent_path();\n        dir_exists = (fs::exists(dir_path)) || fs::create_directories(dir_path);\n    }\n    catch (std::exception const& e)\n    {\n        err = e.what();\n        return false;\n    }\n\n    if (!dir_exists)\n    {\n        err = \"dir no exists\";\n        return false;\n    }\n\n    std::ofstream ofs(filename_with_path.native().c_str(), std::ios_base::out | std::ios_base::binary);\n\n    if (!ofs)\n    {\n        return false;\n    }\n\n    ofs.write(data.data(), static_cast<std::streamsize>(data.size()));\n    ofs.close();\n\n    return true;\n}\n\nbool IsFileExists(fs::path const& fullpath)\n{\n    errorcode ec;\n    bool exists_still = fs::exists(fs::status(fullpath, ec));\n    return (!ec && exists_still);\n}\n\nbool IsFileExists(std::string const& fullpath)\n{\n    auto fp = fs::path(fullpath);\n    return IsFileExists(fp);\n}\n\nstd::pair<bool, std::string /*msg*/>\nCopyFile(fs::path const& src, fs::path const& dst, FileOverwriteOptions overwrite)\n{\n    if (!IsFileExists(src))\n    {\n        return std::make_pair(false, \"Source file is not exists.\");\n    }\n\n    bool dst_exists = IsFileExists(dst);\n\n    if (dst_exists && overwrite != FileOverwriteOptions::overwrite)\n    {\n        return std::make_pair(overwrite == FileOverwriteOptions::ignore_success\n                              , \"Destination was exists.\");\n    }\n\n    errorcode ec;\n    fs::copy_file(src, dst, fs::copy_option::overwrite_if_exists, ec);\n\n    if (ec)\n    {\n        return std::make_pair(false, ec.message());\n    }\n\n    return std::make_pair(true, \"\");\n}\n\nstd::pair<bool, std::string /*msg*/>\nMoveFile(fs::path const& src, fs::path const& dst, FileOverwriteOptions overwrite)\n{\n    if (!IsFileExists(src))\n    {\n        return std::make_pair(false, \"Sourse is not exists.\");\n    }\n\n    bool dst_exists = IsFileExists(dst);\n\n    if (dst_exists && overwrite != FileOverwriteOptions::overwrite)\n    {\n        return std::make_pair(overwrite == FileOverwriteOptions::ignore_success\n                              , \"Destination is exists.\");\n    }\n\n    errorcode ec;\n    fs::rename(src, dst, ec);\n\n    if (ec)\n    {\n        return std::make_pair(false, ec.message());\n    }\n\n    return std::make_pair(true, \"\");\n}\n\n} //namesapce Utilities\n}//namespace da4qi4\n"
  },
  {
    "path": "src/utilities/hmac_sha1_utilities.cpp",
    "content": "#include \"daqi/utilities/hmac_sha1_utilities.hpp\"\n\n#include <openssl/sha.h>\n#include <openssl/hmac.h>\n\n#include <cassert>\n#include <algorithm>\n\nnamespace da4qi4\n{\nnamespace Utilities\n{\n\nstd::vector<std::uint8_t> HMA_SHA1(std::string const& key, std::string const& src)\n{\n    return HMA_SHA1(key.c_str(), static_cast<int>(key.size()), src.c_str(), src.size());\n}\n\nstd::vector<std::uint8_t> HMA_SHA1(char const* key, int key_size, std::string const& src)\n{\n    return HMA_SHA1(key, key_size, src.c_str(), src.size());\n}\n\nstd::vector<std::uint8_t> HMA_SHA1(char const* key, int key_size,\n                                   char const* src,  std::size_t src_size)\n{\n    unsigned int dst_size = 0;\n    unsigned char dst_buf[20 * sizeof(std::uint8_t)]; //20 byte = 160bit\n\n    HMAC(EVP_sha1(),\n         key, key_size,\n         reinterpret_cast<unsigned char const*>(src), src_size,\n         dst_buf, &dst_size);\n\n    std::vector<std::uint8_t> result;\n    result.resize(dst_size);\n\n    assert(dst_size <= 20);\n\n    std::copy(dst_buf, dst_buf + dst_size, result.begin());\n\n    return result;\n}\n\nstd::vector<std::uint8_t> SHA1(std::string const& src)\n{\n    std::vector<std::uint8_t> dst;\n    dst.resize(20);\n\n    for (auto& c : dst)\n    {\n        c = '\\0';\n    }\n\n    ::SHA1(reinterpret_cast<unsigned char const*>(src.data()), src.size(), dst.data());\n\n    return dst;\n}\n\nstd::vector<std::uint8_t> SHA1(unsigned char const*& src, std::size_t src_size)\n{\n    std::vector<std::uint8_t> dst;\n    dst.resize(20);\n\n    for (auto& c : dst)\n    {\n        c = '\\0';\n    }\n\n    ::SHA1(src, src_size, dst.data());\n\n    return dst;\n}\n\nstd::vector<std::uint8_t> SHA1(std::vector<unsigned char> const& src)\n{\n    std::vector<std::uint8_t> dst;\n    dst.resize(20);\n\n    for (auto& c : dst)\n    {\n        c = '\\0';\n    }\n\n    ::SHA1(&src[0], src.size(), dst.data());\n\n    return dst;\n}\n\n\n} // namespace Utilities\n} // namespace da4qi4\n"
  },
  {
    "path": "src/utilities/html_utilities.cpp",
    "content": "#include \"daqi/utilities/html_utilities.hpp\"\n\n#include \"daqi/utilities/string_utilities.hpp\"\n\nnamespace da4qi4\n{\nnamespace Utilities\n{\n\nnamespace\n{\n\nstd::string theOctetStreamMIMEType = \"application/octet-stream\";\n\nstd::unordered_map<std::string, std::string> _mime_map_ =\n{\n    { \".323\", \"text/h323\" },\n    { \".3gp\", \"video/3gpp\" },\n    { \".aab\", \"application/x-authoware-bin\" },\n    { \".aam\", \"application/x-authoware-map\" },\n    { \".aas\", \"application/x-authoware-seg\" },\n    { \".acx\", \"application/internet-property-stream\" },\n    { \".ai\", \"application/postscript\" },\n    { \".aif\", \"audio/x-aiff\" },\n    { \".aifc\", \"audio/x-aiff\" },\n    { \".aiff\", \"audio/x-aiff\" },\n    { \".als\", \"audio/X-Alpha5\" },\n    { \".amc\", \"application/x-mpeg\" },\n    { \".ani\", \"application/octet-stream\" },\n    { \".apk\", \"application/vnd.android.package-archive\" },\n    { \".asc\", \"text/plain\" },\n    { \".asd\", \"application/astound\" },\n    { \".asf\", \"video/x-ms-asf\" },\n    { \".asn\", \"application/astound\" },\n    { \".asp\", \"application/x-asap\" },\n    { \".asr\", \"video/x-ms-asf\" },\n    { \".asx\", \"video/x-ms-asf\" },\n    { \".au\", \"audio/basic\" },\n    { \".avb\", \"application/octet-stream\" },\n    { \".avi\", \"video/x-msvideo\" },\n    { \".awb\", \"audio/amr-wb\" },\n    { \".axs\", \"application/olescript\" },\n    { \".bas\", \"text/plain\" },\n    { \".bcpio\", \"application/x-bcpio\" },\n    { \".bin \", \"application/octet-stream\" },\n    { \".bld\", \"application/bld\" },\n    { \".bld2\", \"application/bld2\" },\n    { \".bmp\", \"image/bmp\" },\n    { \".bpk\", \"application/octet-stream\" },\n    { \".bz2\", \"application/x-bzip2\" },\n    { \".c\", \"text/plain\" },\n    { \".cal\", \"image/x-cals\" },\n    { \".cat\", \"application/vnd.ms-pkiseccat\" },\n    { \".ccn\", \"application/x-cnc\" },\n    { \".cco\", \"application/x-cocoa\" },\n    { \".cdf\", \"application/x-cdf\" },\n    { \".cer\", \"application/x-x509-ca-cert\" },\n    { \".cgi\", \"magnus-internal/cgi\" },\n    { \".chat\", \"application/x-chat\" },\n    { \".class\", \"application/octet-stream\" },\n    { \".clp\", \"application/x-msclip\" },\n    { \".cmx\", \"image/x-cmx\" },\n    { \".co\", \"application/x-cult3d-object\" },\n    { \".cod\", \"image/cis-cod\" },\n    { \".conf\", \"text/plain\" },\n    { \".cpio\", \"application/x-cpio\" },\n    { \".cpp\", \"text/plain\" },\n    { \".cpt\", \"application/mac-compactpro\" },\n    { \".crd\", \"application/x-mscardfile\" },\n    { \".crl\", \"application/pkix-crl\" },\n    { \".crt\", \"application/x-x509-ca-cert\" },\n    { \".csh\", \"application/x-csh\" },\n    { \".csm\", \"chemical/x-csml\" },\n    { \".csml\", \"chemical/x-csml\" },\n    { \".css\", \"text/css\" },\n    { \".cur\", \"application/octet-stream\" },\n    { \".dcm\", \"x-lml/x-evm\" },\n    { \".dcr\", \"application/x-director\" },\n    { \".dcx\", \"image/x-dcx\" },\n    { \".der\", \"application/x-x509-ca-cert\" },\n    { \".dhtml\", \"text/html\" },\n    { \".dir\", \"application/x-director\" },\n    { \".dll\", \"application/x-msdownload\" },\n    { \".dmg\", \"application/octet-stream\" },\n    { \".dms\", \"application/octet-stream\" },\n    { \".doc\", \"application/msword\" },\n    { \".docx\", \"application/vnd.openxmlformats-officedocument.wordprocessingml.document\" },\n    { \".dot\", \"application/msword\" },\n    { \".dvi\", \"application/x-dvi\" },\n    { \".dwf\", \"drawing/x-dwf\" },\n    { \".dwg\", \"application/x-autocad\" },\n    { \".dxf\", \"application/x-autocad\" },\n    { \".dxr\", \"application/x-director\" },\n    { \".ebk\", \"application/x-expandedbook\" },\n    { \".emb\", \"chemical/x-embl-dl-nucleotide\" },\n    { \".embl\", \"chemical/x-embl-dl-nucleotide\" },\n    { \".eps\", \"application/postscript\" },\n    { \".epub\", \"application/epub+zip\" },\n    { \".eri\", \"image/x-eri\" },\n    { \".es\", \"audio/echospeech\" },\n    { \".esl\", \"audio/echospeech\" },\n    { \".etc\", \"application/x-earthtime\" },\n    { \".etx\", \"text/x-setext\" },\n    { \".evm\", \"x-lml/x-evm\" },\n    { \".evy\", \"application/envoy\" },\n    { \".exe\", \"application/octet-stream\" },\n    { \".fh4\", \"image/x-freehand\" },\n    { \".fh5\", \"image/x-freehand\" },\n    { \".fhc\", \"image/x-freehand\" },\n    { \".fif\", \"application/fractals\" },\n    { \".flr\", \"x-world/x-vrml\" },\n    { \".flv\", \"flv-application/octet-stream\" },\n    { \".fm\", \"application/x-maker\" },\n    { \".fpx\", \"image/x-fpx\" },\n    { \".fvi\", \"video/isivideo\" },\n    { \".gau\", \"chemical/x-gaussian-input\" },\n    { \".gca\", \"application/x-gca-compressed\" },\n    { \".gdb\", \"x-lml/x-gdb\" },\n    { \".gif\", \"image/gif\" },\n    { \".gps\", \"application/x-gps\" },\n    { \".gtar\", \"application/x-gtar\" },\n    { \".gz\", \"application/x-gzip\" },\n    { \".h\", \"text/plain\" },\n    { \".hdf\", \"application/x-hdf\" },\n    { \".hdm\", \"text/x-hdml\" },\n    { \".hdml\", \"text/x-hdml\" },\n    { \".hlp\", \"application/winhlp\" },\n    { \".hqx\", \"application/mac-binhex40\" },\n    { \".hta\", \"application/hta\" },\n    { \".htc\", \"text/x-component\" },\n    { \".htm\", \"text/html\" },\n    { \".html\", \"text/html\" },\n    { \".hts\", \"text/html\" },\n    { \".htt\", \"text/webviewhtml\" },\n    { \".ice\", \"x-conference/x-cooltalk\" },\n    { \".ico\", \"image/x-icon\" },\n    { \".ief\", \"image/ief\" },\n    { \".ifm\", \"image/gif\" },\n    { \".ifs\", \"image/ifs\" },\n    { \".iii\", \"application/x-iphone\" },\n    { \".imy\", \"audio/melody\" },\n    { \".ins\", \"application/x-internet-signup\" },\n    { \".ips\", \"application/x-ipscript\" },\n    { \".ipx\", \"application/x-ipix\" },\n    { \".isp\", \"application/x-internet-signup\" },\n    { \".it\", \"audio/x-mod\" },\n    { \".itz\", \"audio/x-mod\" },\n    { \".ivr\", \"i-world/i-vrml\" },\n    { \".j2k\", \"image/j2k\" },\n    { \".jad\", \"text/vnd.sun.j2me.app-descriptor\" },\n    { \".jam\", \"application/x-jam\" },\n    { \".jar\", \"application/java-archive\" },\n    { \".java\", \"text/plain\" },\n    { \".jfif\", \"image/pipeg\" },\n    { \".jnlp\", \"application/x-java-jnlp-file\" },\n    { \".jpe\", \"image/jpeg\" },\n    { \".jpeg\", \"image/jpeg\" },\n    { \".jpg\", \"image/jpeg\" },\n    { \".jpz\", \"image/jpeg\" },\n    { \".js\", \"application/x-javascript\" },\n    { \".jwc\", \"application/jwc\" },\n    { \".kjx\", \"application/x-kjx\" },\n    { \".lak\", \"x-lml/x-lak\" },\n    { \".latex\", \"application/x-latex\" },\n    { \".lcc\", \"application/fastman\" },\n    { \".lcl\", \"application/x-digitalloca\" },\n    { \".lcr\", \"application/x-digitalloca\" },\n    { \".lgh\", \"application/lgh\" },\n    { \".lha\", \"application/octet-stream\" },\n    { \".lml\", \"x-lml/x-lml\" },\n    { \".lmlpack\", \"x-lml/x-lmlpack\" },\n    { \".log\", \"text/plain\" },\n    { \".lsf\", \"video/x-la-asf\" },\n    { \".lsx\", \"video/x-la-asf\" },\n    { \".lzh\", \"application/octet-stream\" },\n    { \".m13\", \"application/x-msmediaview\" },\n    { \".m14\", \"application/x-msmediaview\" },\n    { \".m15\", \"audio/x-mod\" },\n    { \".m3u\", \"audio/x-mpegurl\" },\n    { \".m3url\", \"audio/x-mpegurl\" },\n    { \".m4a\", \"audio/mp4a-latm\" },\n    { \".m4b\", \"audio/mp4a-latm\" },\n    { \".m4p\", \"audio/mp4a-latm\" },\n    { \".m4u\", \"video/vnd.mpegurl\" },\n    { \".m4v\", \"video/x-m4v\" },\n    { \".ma1\", \"audio/ma1\" },\n    { \".ma2\", \"audio/ma2\" },\n    { \".ma3\", \"audio/ma3\" },\n    { \".ma5\", \"audio/ma5\" },\n    { \".man\", \"application/x-troff-man\" },\n    { \".map\", \"magnus-internal/imagemap\" },\n    { \".mbd\", \"application/mbedlet\" },\n    { \".mct\", \"application/x-mascot\" },\n    { \".mdb\", \"application/x-msaccess\" },\n    { \".mdz\", \"audio/x-mod\" },\n    { \".me\", \"application/x-troff-me\" },\n    { \".mel\", \"text/x-vmel\" },\n    { \".mht\", \"message/rfc822\" },\n    { \".mhtml\", \"message/rfc822\" },\n    { \".mi\", \"application/x-mif\" },\n    { \".mid\", \"audio/mid\" },\n    { \".midi\", \"audio/midi\" },\n    { \".mif\", \"application/x-mif\" },\n    { \".mil\", \"image/x-cals\" },\n    { \".mio\", \"audio/x-mio\" },\n    { \".mmf\", \"application/x-skt-lbs\" },\n    { \".mng\", \"video/x-mng\" },\n    { \".mny\", \"application/x-msmoney\" },\n    { \".moc\", \"application/x-mocha\" },\n    { \".mocha\", \"application/x-mocha\" },\n    { \".mod\", \"audio/x-mod\" },\n    { \".mof\", \"application/x-yumekara\" },\n    { \".mol\", \"chemical/x-mdl-molfile\" },\n    { \".mop\", \"chemical/x-mopac-input\" },\n    { \".mov\", \"video/quicktime\" },\n    { \".movie\", \"video/x-sgi-movie\" },\n    { \".mp2\", \"video/mpeg\" },\n    { \".mp3\", \"audio/mpeg\" },\n    { \".mp4\", \"video/mp4\" },\n    { \".mpa\", \"video/mpeg\" },\n    { \".mpc\", \"application/vnd.mpohun.certificate\" },\n    { \".mpe\", \"video/mpeg\" },\n    { \".mpeg\", \"video/mpeg\" },\n    { \".mpg\", \"video/mpeg\" },\n    { \".mpg4\", \"video/mp4\" },\n    { \".mpga\", \"audio/mpeg\" },\n    { \".mpn\", \"application/vnd.mophun.application\" },\n    { \".mpp\", \"application/vnd.ms-project\" },\n    { \".mps\", \"application/x-mapserver\" },\n    { \".mpv2\", \"video/mpeg\" },\n    { \".mrl\", \"text/x-mrml\" },\n    { \".mrm\", \"application/x-mrm\" },\n    { \".ms\", \"application/x-troff-ms\" },\n    { \".msg\", \"application/vnd.ms-outlook\" },\n    { \".mts\", \"application/metastream\" },\n    { \".mtx\", \"application/metastream\" },\n    { \".mtz\", \"application/metastream\" },\n    { \".mvb\", \"application/x-msmediaview\" },\n    { \".mzv\", \"application/metastream\" },\n    { \".nar\", \"application/zip\" },\n    { \".nbmp\", \"image/nbmp\" },\n    { \".nc\", \"application/x-netcdf\" },\n    { \".ndb\", \"x-lml/x-ndb\" },\n    { \".ndwn\", \"application/ndwn\" },\n    { \".nif\", \"application/x-nif\" },\n    { \".nmz\", \"application/x-scream\" },\n    { \".nokia-op-logo\", \"image/vnd.nok-oplogo-color\" },\n    { \".npx\", \"application/x-netfpx\" },\n    { \".nsnd\", \"audio/nsnd\" },\n    { \".nva\", \"application/x-neva1\" },\n    { \".nws\", \"message/rfc822\" },\n    { \".oda\", \"application/oda\" },\n    { \".ogg\", \"audio/ogg\" },\n    { \".oom\", \"application/x-AtlasMate-Plugin\" },\n    { \".p10\", \"application/pkcs10\" },\n    { \".p12\", \"application/x-pkcs12\" },\n    { \".p7b\", \"application/x-pkcs7-certificates\" },\n    { \".p7c\", \"application/x-pkcs7-mime\" },\n    { \".p7m\", \"application/x-pkcs7-mime\" },\n    { \".p7r\", \"application/x-pkcs7-certreqresp\" },\n    { \".p7s\", \"application/x-pkcs7-signature\" },\n    { \".pac\", \"audio/x-pac\" },\n    { \".pae\", \"audio/x-epac\" },\n    { \".pan\", \"application/x-pan\" },\n    { \".pbm\", \"image/x-portable-bitmap\" },\n    { \".pcx\", \"image/x-pcx\" },\n    { \".pda\", \"image/x-pda\" },\n    { \".pdb\", \"chemical/x-pdb\" },\n    { \".pdf\", \"application/pdf\" },\n    { \".pfr\", \"application/font-tdpfr\" },\n    { \".pfx\", \"application/x-pkcs12\" },\n    { \".pgm\", \"image/x-portable-graymap\" },\n    { \".pict\", \"image/x-pict\" },\n    { \".pko\", \"application/ynd.ms-pkipko\" },\n    { \".pm\", \"application/x-perl\" },\n    { \".pma\", \"application/x-perfmon\" },\n    { \".pmc\", \"application/x-perfmon\" },\n    { \".pmd\", \"application/x-pmd\" },\n    { \".pml\", \"application/x-perfmon\" },\n    { \".pmr\", \"application/x-perfmon\" },\n    { \".pmw\", \"application/x-perfmon\" },\n    { \".png\", \"image/png\" },\n    { \".pnm\", \"image/x-portable-anymap\" },\n    { \".pnz\", \"image/png\" },\n    { \".pot,\", \"application/vnd.ms-powerpoint\" },\n    { \".ppm\", \"image/x-portable-pixmap\" },\n    { \".pps\", \"application/vnd.ms-powerpoint\" },\n    { \".ppt\", \"application/vnd.ms-powerpoint\" },\n    { \".pptx\", \"application/vnd.openxmlformats-officedocument.presentationml.presentation\" },\n    { \".pqf\", \"application/x-cprplayer\" },\n    { \".pqi\", \"application/cprplayer\" },\n    { \".prc\", \"application/x-prc\" },\n    { \".prf\", \"application/pics-rules\" },\n    { \".prop\", \"text/plain\" },\n    { \".proxy\", \"application/x-ns-proxy-autoconfig\" },\n    { \".ps\", \"application/postscript\" },\n    { \".ptlk\", \"application/listenup\" },\n    { \".pub\", \"application/x-mspublisher\" },\n    { \".pvx\", \"video/x-pv-pvx\" },\n    { \".qcp\", \"audio/vnd.qcelp\" },\n    { \".qt\", \"video/quicktime\" },\n    { \".qti\", \"image/x-quicktime\" },\n    { \".qtif\", \"image/x-quicktime\" },\n    { \".r3t\", \"text/vnd.rn-realtext3d\" },\n    { \".ra\", \"audio/x-pn-realaudio\" },\n    { \".ram\", \"audio/x-pn-realaudio\" },\n    { \".rar\", \"application/octet-stream\" },\n    { \".ras\", \"image/x-cmu-raster\" },\n    { \".rc\", \"text/plain\" },\n    { \".rdf\", \"application/rdf+xml\" },\n    { \".rf\", \"image/vnd.rn-realflash\" },\n    { \".rgb\", \"image/x-rgb\" },\n    { \".rlf\", \"application/x-richlink\" },\n    { \".rm\", \"audio/x-pn-realaudio\" },\n    { \".rmf\", \"audio/x-rmf\" },\n    { \".rmi\", \"audio/mid\" },\n    { \".rmm\", \"audio/x-pn-realaudio\" },\n    { \".rmvb\", \"audio/x-pn-realaudio\" },\n    { \".rnx\", \"application/vnd.rn-realplayer\" },\n    { \".roff\", \"application/x-troff\" },\n    { \".rp\", \"image/vnd.rn-realpix\" },\n    { \".rpm\", \"audio/x-pn-realaudio-plugin\" },\n    { \".rt\", \"text/vnd.rn-realtext\" },\n    { \".rte\", \"x-lml/x-gps\" },\n    { \".rtf\", \"application/rtf\" },\n    { \".rtg\", \"application/metastream\" },\n    { \".rtx\", \"text/richtext\" },\n    { \".rv\", \"video/vnd.rn-realvideo\" },\n    { \".rwc\", \"application/x-rogerwilco\" },\n    { \".s3m\", \"audio/x-mod\" },\n    { \".s3z\", \"audio/x-mod\" },\n    { \".sca\", \"application/x-supercard\" },\n    { \".scd\", \"application/x-msschedule\" },\n    { \".sct\", \"text/scriptlet\" },\n    { \".sdf\", \"application/e-score\" },\n    { \".sea\", \"application/x-stuffit\" },\n    { \".setpay\", \"application/set-payment-initiation\" },\n    { \".setreg\", \"application/set-registration-initiation\" },\n    { \".sgm\", \"text/x-sgml\" },\n    { \".sgml\", \"text/x-sgml\" },\n    { \".sh\", \"application/x-sh\" },\n    { \".shar\", \"application/x-shar\" },\n    { \".shtml\", \"magnus-internal/parsed-html\" },\n    { \".shw\", \"application/presentations\" },\n    { \".si6\", \"image/si6\" },\n    { \".si7\", \"image/vnd.stiwap.sis\" },\n    { \".si9\", \"image/vnd.lgtwap.sis\" },\n    { \".sis\", \"application/vnd.symbian.install\" },\n    { \".sit\", \"application/x-stuffit\" },\n    { \".skd\", \"application/x-Koan\" },\n    { \".skm\", \"application/x-Koan\" },\n    { \".skp\", \"application/x-Koan\" },\n    { \".skt\", \"application/x-Koan\" },\n    { \".slc\", \"application/x-salsa\" },\n    { \".smd\", \"audio/x-smd\" },\n    { \".smi\", \"application/smil\" },\n    { \".smil\", \"application/smil\" },\n    { \".smp\", \"application/studiom\" },\n    { \".smz\", \"audio/x-smd\" },\n    { \".snd\", \"audio/basic\" },\n    { \".spc\", \"application/x-pkcs7-certificates\" },\n    { \".spl\", \"application/futuresplash\" },\n    { \".spr\", \"application/x-sprite\" },\n    { \".sprite\", \"application/x-sprite\" },\n    { \".sdp\", \"application/sdp\" },\n    { \".spt\", \"application/x-spt\" },\n    { \".src\", \"application/x-wais-source\" },\n    { \".sst\", \"application/vnd.ms-pkicertstore\" },\n    { \".stk\", \"application/hyperstudio\" },\n    { \".stl\", \"application/vnd.ms-pkistl\" },\n    { \".stm\", \"text/html\" },\n    { \".svg\", \"image/svg+xml\" },\n    { \".sv4cpio\", \"application/x-sv4cpio\" },\n    { \".sv4crc\", \"application/x-sv4crc\" },\n    { \".svf\", \"image/vnd\" },\n    { \".eot\", \"application/vnd.ms-fontobject\" },\n    { \".woff\", \"application/font-woff\" },\n    { \".svh\", \"image/svh\" },\n    { \".svr\", \"x-world/x-svr\" },\n    { \".swf\", \"application/x-shockwave-flash\" },\n    { \".swfl\", \"application/x-shockwave-flash\" },\n    { \".t\", \"application/x-troff\" },\n    { \".tad\", \"application/octet-stream\" },\n    { \".talk\", \"text/x-speech\" },\n    { \".tar\", \"application/x-tar\" },\n    { \".taz\", \"application/x-tar\" },\n    { \".tbp\", \"application/x-timbuktu\" },\n    { \".tbt\", \"application/x-timbuktu\" },\n    { \".tcl\", \"application/x-tcl\" },\n    { \".tex\", \"application/x-tex\" },\n    { \".texi\", \"application/x-texinfo\" },\n    { \".texinfo\", \"application/x-texinfo\" },\n    { \".tgz\", \"application/x-compressed\" },\n    { \".thm\", \"application/vnd.eri.thm\" },\n    { \".tif\", \"image/tiff\" },\n    { \".tiff\", \"image/tiff\" },\n    { \".tki\", \"application/x-tkined\" },\n    { \".tkined\", \"application/x-tkined\" },\n    { \".toc\", \"application/toc\" },\n    { \".toy\", \"image/toy\" },\n    { \".tr\", \"application/x-troff\" },\n    { \".trk\", \"x-lml/x-gps\" },\n    { \".trm\", \"application/x-msterminal\" },\n    { \".tsi\", \"audio/tsplayer\" },\n    { \".tsp\", \"application/dsptype\" },\n    { \".tsv\", \"text/tab-separated-values\" },\n    { \".ttf\", \"application/octet-stream\" },\n    { \".ttz\", \"application/t-time\" },\n    { \".txt\", \"text/plain\" },\n    { \".uls\", \"text/iuls\" },\n    { \".ult\", \"audio/x-mod\" },\n    { \".ustar\", \"application/x-ustar\" },\n    { \".uu\", \"application/x-uuencode\" },\n    { \".uue\", \"application/x-uuencode\" },\n    { \".vcd\", \"application/x-cdlink\" },\n    { \".vcf\", \"text/x-vcard\" },\n    { \".vdo\", \"video/vdo\" },\n    { \".vib\", \"audio/vib\" },\n    { \".viv\", \"video/vivo\" },\n    { \".vivo\", \"video/vivo\" },\n    { \".vmd\", \"application/vocaltec-media-desc\" },\n    { \".vmf\", \"application/vocaltec-media-file\" },\n    { \".vmi\", \"application/x-dreamcast-vms-info\" },\n    { \".vms\", \"application/x-dreamcast-vms\" },\n    { \".vox\", \"audio/voxware\" },\n    { \".vqe\", \"audio/x-twinvq-plugin\" },\n    { \".vqf\", \"audio/x-twinvq\" },\n    { \".vql\", \"audio/x-twinvq\" },\n    { \".vre\", \"x-world/x-vream\" },\n    { \".vrml\", \"x-world/x-vrml\" },\n    { \".vrt\", \"x-world/x-vrt\" },\n    { \".vrw\", \"x-world/x-vream\" },\n    { \".vts\", \"workbook/formulaone\" },\n    { \".wav\", \"audio/x-wav\" },\n    { \".wax\", \"audio/x-ms-wax\" },\n    { \".wbmp\", \"image/vnd.wap.wbmp\" },\n    { \".wcm\", \"application/vnd.ms-works\" },\n    { \".wdb\", \"application/vnd.ms-works\" },\n    { \".web\", \"application/vnd.xara\" },\n    { \".wi\", \"image/wavelet\" },\n    { \".wis\", \"application/x-InstallShield\" },\n    { \".wks\", \"application/vnd.ms-works\" },\n    { \".wm\", \"video/x-ms-wm\" },\n    { \".wma\", \"audio/x-ms-wma\" },\n    { \".wmd\", \"application/x-ms-wmd\" },\n    { \".wmf\", \"application/x-msmetafile\" },\n    { \".wml\", \"text/vnd.wap.wml\" },\n    { \".wmlc\", \"application/vnd.wap.wmlc\" },\n    { \".wmls\", \"text/vnd.wap.wmlscript\" },\n    { \".wmlsc\", \"application/vnd.wap.wmlscriptc\" },\n    { \".wmlscript\", \"text/vnd.wap.wmlscript\" },\n    { \".wmv\", \"audio/x-ms-wmv\" },\n    { \".wmx\", \"video/x-ms-wmx\" },\n    { \".wmz\", \"application/x-ms-wmz\" },\n    { \".wpng\", \"image/x-up-wpng\" },\n    { \".wps\", \"application/vnd.ms-works\" },\n    { \".wpt\", \"x-lml/x-gps\" },\n    { \".wri\", \"application/x-mswrite\" },\n    { \".wrl\", \"x-world/x-vrml\" },\n    { \".wrz\", \"x-world/x-vrml\" },\n    { \".ws\", \"text/vnd.wap.wmlscript\" },\n    { \".wsc\", \"application/vnd.wap.wmlscriptc\" },\n    { \".wv\", \"video/wavelet\" },\n    { \".wvx\", \"video/x-ms-wvx\" },\n    { \".wxl\", \"application/x-wxl\" },\n    { \".x-gzip\", \"application/x-gzip\" },\n    { \".xaf\", \"x-world/x-vrml\" },\n    { \".xar\", \"application/vnd.xara\" },\n    { \".xbm\", \"image/x-xbitmap\" },\n    { \".xdm\", \"application/x-xdma\" },\n    { \".xdma\", \"application/x-xdma\" },\n    { \".xdw\", \"application/vnd.fujixerox.docuworks\" },\n    { \".xht\", \"application/xhtml+xml\" },\n    { \".xhtm\", \"application/xhtml+xml\" },\n    { \".xhtml\", \"application/xhtml+xml\" },\n    { \".xla\", \"application/vnd.ms-excel\" },\n    { \".xlc\", \"application/vnd.ms-excel\" },\n    { \".xll\", \"application/x-excel\" },\n    { \".xlm\", \"application/vnd.ms-excel\" },\n    { \".xls\", \"application/vnd.ms-excel\" },\n    { \".xlsx\", \"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\" },\n    { \".xlt\", \"application/vnd.ms-excel\" },\n    { \".xlw\", \"application/vnd.ms-excel\" },\n    { \".xm\", \"audio/x-mod\" },\n    { \".xml\", \"text/plain\" },\n    { \".xml\", \"application/xml\" },\n    { \".xmz\", \"audio/x-mod\" },\n    { \".xof\", \"x-world/x-vrml\" },\n    { \".xpi\", \"application/x-xpinstall\" },\n    { \".xpm\", \"image/x-xpixmap\" },\n    { \".xsit\", \"text/xml\" },\n    { \".xsl\", \"text/xml\" },\n    { \".xul\", \"text/xul\" },\n    { \".xwd\", \"image/x-xwindowdump\" },\n    { \".xyz\", \"chemical/x-pdb\" },\n    { \".yz1\", \"application/x-yz1\" },\n    { \".z\", \"application/x-compress\" },\n    { \".zac\", \"application/x-zaurus-zac\" },\n    { \".zip\", \"application/zip\" },\n    { \".json\", \"application/json\" },\n};\n\n}\n\nstd::string const& GetMIMEType(std::string const&  extension)\n{\n    std::string key = extension;\n\n    for (auto& c : key)\n    {\n        if (c >= 'A' && c <= 'Z')\n        {\n            c += 'a' - 'A';\n        }\n    }\n\n    auto it = _mime_map_.find(key);\n    return (it != _mime_map_.cend() ? it->second : theOctetStreamMIMEType);\n}\n\nstd::string HTMLEscape(std::string const& s)\n{\n    // & > <  white_space , ' \"\n    std::string r = ReplaceAll(s, \"&\", \"&amp;\");\n    r = ReplaceAll(r, \">\", \"&gt;\");\n    r = ReplaceAll(r, \"<\", \"&lt;\");\n    r = ReplaceAll(r, \" \", \"&nbsp;\");\n    r = ReplaceAll(r, \"\\\"\", \"&quot;\");\n    r = ReplaceAll(r, \"'\", \"&apos;\");\n\n    return r;\n}\n\n} //Utilities\n} //da4qi4\n\n"
  },
  {
    "path": "src/utilities/http_utilities.cpp",
    "content": "#include \"daqi/utilities/http_utilities.hpp\"\n\n#include \"daqi/utilities/string_utilities.hpp\"\n\nnamespace da4qi4\n{\nnamespace Utilities\n{\n\n\nbool IsUrlEncoded(const std::string& value)\n{\n    for (auto c : value)\n    {\n        if (c == '%' || c == '+')\n        {\n            return true;\n        }\n    }\n    \n    return false;\n}\n\nstd::string UrlDecodeIfEncoded(std::string const& value)\n{\n    return IsUrlEncoded(value) ? UrlDecode(value) : value;\n}\n\n\nstd::string UrlEncode(const std::string& value)\n{\n    static auto hex_digt = \"0123456789ABCDEF\";\n    \n    std::string result;\n    result.reserve(value.size() << 1);\n    \n    for (auto ch : value)\n    {\n        if ((ch >= '0' && ch <= '9')\n            || (ch >= 'A' && ch <= 'Z')\n            || (ch >= 'a' && ch <= 'z')\n            || ch == '-' || ch == '_' || ch == '!'\n            || ch == '\\'' || ch == '(' || ch == ')'\n            || ch == '*' || ch == '~' || ch == '.')  // !'()*-._~\n        {\n            result.push_back(ch);\n        }\n        else\n        {\n            result += std::string(\"%\") +\n                      hex_digt[static_cast<unsigned char>(ch) >> 4]\n                      +  hex_digt[static_cast<unsigned char>(ch) & 15];\n        }\n    }\n    \n    return result;\n}\n\nstd::string UrlDecode(const std::string& value)\n{\n    std::string result;\n    result.reserve(value.size());\n    \n    for (std::size_t i = 0; i < value.size(); ++i)\n    {\n        auto ch = value[i];\n        \n        if (ch == '%' && (i + 2) < value.size())\n        {\n            auto hex = value.substr(i + 1, 2);\n            auto dec = static_cast<char>(std::strtol(hex.c_str(), nullptr, 16));\n            result.push_back(dec);\n            i += 2;\n        }\n        else if (ch == '+')\n        {\n            result.push_back(' ');\n        }\n        else\n        {\n            result.push_back(ch);\n        }\n    }\n    \n    return result;\n}\n\nstd::map<std::string, std::string> ParseQueryParameters(std::string const& query)\n{\n    std::map<std::string, std::string> result;\n    std::vector<std::string> kvparts = Utilities::Split(query, '&', Utilities::TrimOptions::keep_space);\n    \n    for (auto kvpart : kvparts)\n    {\n        std::vector<std::string> kv = Utilities::Split(kvpart, '=', Utilities::TrimOptions::keep_space);\n        size_t  c = kv.size();\n        std::string k, v;\n        \n        switch (c)\n        {\n        case 2 :\n            v = UrlDecodeIfEncoded(Utilities::TrimCopy(kv[1]));\n            \n            /* don't break; */\n            \n        case 1 :\n            k = UrlDecodeIfEncoded(Utilities::TrimCopy(kv[0]));\n            result.insert(std::make_pair(std::move(k), std::move(v)));\n        }\n    }\n    \n    return result;\n}\n\nstd::map<std::string, std::string> ParsePlainTextFormData(std::string const& body)\n{\n    std::map<std::string, std::string> result;\n    std::vector<std::string> kvparts = Utilities::SplitByLine(body\n                                                              , Utilities::TrimOptions::keep_space);\n    \n    for (std::string kvpart : kvparts)\n    {\n        Utilities::Trim(kvpart);\n        \n        if (kvpart.empty())\n        {\n            continue;\n        }\n        \n        std::vector<std::string> kv = Utilities::Split(kvpart\n                                                       , '='\n                                                       , Utilities::TrimOptions::keep_space);\n        \n        size_t  c = kv.size();\n        std::string k, v;\n        \n        switch (c)\n        {\n        case 2 :\n            v = Utilities::TrimCopy(kv[1]);\n            \n            /* don't break; */\n            \n        case 1 :\n            k = Utilities::TrimCopy(kv[0]);\n            result.insert(std::make_pair(std::move(k), std::move(v)));\n        }\n    }\n    \n    return result;\n}\n\n\n} //Utilities\n} //da4qi4\n"
  },
  {
    "path": "src/utilities/md5_utilities.cpp",
    "content": "#include \"daqi/utilities/md5_utilities.hpp\"\n\n#include <cstring>\n#include <openssl/md5.h>\n\nnamespace da4qi4\n{\nnamespace Utilities\n{\n\nvoid MD5(const std::string& srcStr, std::string& encodedStr, std::string& encodedHexStr)\n{\n    unsigned char mdStr[33] = {0};\n    ::MD5(reinterpret_cast<const unsigned char*>(srcStr.c_str()), srcStr.length(), mdStr);\n\n    encodedStr = std::string(reinterpret_cast<char*>(mdStr));\n\n    char buf[65] = {0};\n    char tmp[3] = {0};\n\n    for (int i = 0; i < 32; i++)\n    {\n        sprintf(tmp, \"%02x\", mdStr[i]);\n        strcat(buf, tmp);\n    }\n\n    buf[32] = '\\0';\n    encodedHexStr = std::string(buf);\n}\n\nstd::string MD5(const std::string& src, MD5ResultEncoding encoding)\n{\n    std::string dst, dst_hex;\n    MD5(src, dst, dst_hex);\n\n    return (MD5ResultEncoding::hex == encoding) ? dst_hex : dst;\n}\n\n} //namespace Utilities\n} //namespace da4qi4\n\n"
  },
  {
    "path": "src/utilities/string_utilities.cpp",
    "content": "#include \"daqi/utilities/string_utilities.hpp\"\n\n#include <iconv.h>\n\n#include <ctime>\n#include <codecvt>\n\n#include <sstream>\n\n#include <boost/algorithm/string/predicate.hpp>\n#include <boost/algorithm/string/replace.hpp>\n#include <boost/algorithm/string/split.hpp>\n#include <boost/algorithm/string/trim.hpp>\n\n#include <boost/uuid/uuid_generators.hpp>\n#include <boost/uuid/uuid_io.hpp>\n\nnamespace da4qi4\n{\nnamespace Utilities\n{\n\nstd::string const theEmptyString;\n\nbool IgnoreCaseCompare::operator()(std::string const& l, std::string const& r) const\n{\n    return iLess(l, r);\n}\n\nbool iStartsWith(std::string const& m, std::string const& s)\n{\n    return boost::algorithm::istarts_with(m, s);\n}\n\nbool StartsWith(std::string const& m, std::string const& s)\n{\n    return boost::algorithm::starts_with(m, s);\n}\n\nbool iEndsWith(std::string const& m, std::string const& s)\n{\n    return boost::algorithm::iends_with(m, s);\n}\n\nbool EndsWith(std::string const& m, std::string const& s)\n{\n    return boost::algorithm::ends_with(m, s);\n}\n\nbool iEquals(std::string const& l, std::string const& r)\n{\n    return boost::algorithm::iequals(l, r);\n}\n\nbool iLess(std::string const& l, std::string const& r)\n{\n    return boost::algorithm::ilexicographical_compare(l, r);\n}\n\nchar const* dt_fmt_gmt = \"%a, %d %b %Y %H:%M:%S %Z\";\nchar const* dt_fmt_yyyy_mm_dd_hh_mm_ss = \"%Y-%m-%d %H:%M:%S\";\nchar const* dt_fmt_yyyy_mm_dd = \"%Y-%m-%d\";\nchar const* dt_fmt_yyyy_mm_dd_hh_mm_ss_CN = \"%Y年%m月%d日 %H时%M分%S秒\";\nchar const* dt_fmt_yyyy_mm_dd_CN = \"%Y年%m月%d日\";\n\nstd::string GMTFormatTime(std::time_t t)\n{\n    struct tm gmt = *std::gmtime(&t);\n    char buff[48] = \"\\0\";\n    strftime(buff, sizeof(buff), dt_fmt_gmt, &gmt);\n\n    return buff;\n}\n\nstd::string FormatDateTime(std::time_t t, char const* fmt)\n{\n    struct tm gmt = *std::localtime(&t);\n    char buff[48] = \"\\0\";\n    strftime(buff, sizeof(buff), fmt, &gmt);\n\n    return buff;\n}\n\nstd::string ReplaceAll(std::string const& m, std::string const& bef, std::string const& aft)\n{\n    return boost::algorithm::replace_all_copy(m, bef, aft);\n}\n\nvoid TrimOnOptions(std::string& m, TrimOptions opt)\n{\n    switch (opt)\n    {\n        case TrimOptions::trim_all :\n            Trim(m);\n            break;\n\n        case TrimOptions::trim_left:\n            TrimLeft(m);\n            break;\n\n        case TrimOptions::trim_right:\n            TrimRight(m);\n            break;\n\n        case TrimOptions::keep_space:\n            break;\n    }\n}\n\nstd::string TrimOnOptionsCopy(std::string const& m, TrimOptions opt)\n{\n    if (opt == TrimOptions::keep_space)\n    {\n        return m;\n    }\n\n    std::string mcopy = m;\n    TrimOnOptions(mcopy, opt);\n    return mcopy;\n}\n\nstd::vector<std::string> Split(std::string const& m, char c, TrimOptions opt)\n{\n    std::vector<std::string> parts;\n    char spe[] = {c, '\\0'};\n    boost::algorithm::split(parts, m, boost::is_any_of(spe));\n\n    if (opt != TrimOptions::keep_space)\n    {\n        for (auto& part : parts)\n        {\n            TrimOnOptions(part, opt);\n        }\n    }\n\n    return parts;\n}\n\nstd::vector<std::string> SplitByLine(std::string const& m, TrimOptions opt)\n{\n    std::stringstream ss(m);\n    std::vector<std::string> parts;\n\n    while (ss)\n    {\n        std::string line;\n        std::getline(ss, line);\n        TrimOnOptions(line, opt);\n        parts.push_back(line);\n    }\n\n    return parts;\n}\n\nvoid Trim(std::string& m)\n{\n    boost::trim(m);\n}\n\nstd::string TrimCopy(std::string const& m)\n{\n    return boost::trim_copy(m);\n}\n\nvoid TrimLeft(std::string& m)\n{\n    boost::trim_left(m);\n}\n\nstd::string TrimLeftCopy(std::string const& m)\n{\n    return boost::trim_copy(m);\n}\n\nvoid TrimRight(std::string& m)\n{\n    boost::trim_right(m);\n}\n\nstd::string TrimRightCopy(std::string const& m)\n{\n    return boost::trim_right_copy(m);\n}\n\nstd::string GetUUID(const std::string& prefix)\n{\n    boost::uuids::random_generator gen; //NOTE: too slow\n\n    boost::uuids::uuid uid = gen();\n    std::stringstream ss;\n    ss << prefix << uid;\n\n    return ss.str();\n}\n\nstd::string DecIntToHexStr(std::size_t num)\n{\n    std::string remainders;\n    size_t quotient = num, remainder;\n\n    do\n    {\n        remainder = quotient % 16;\n        quotient = quotient / 16;\n\n        char c = (remainder < 10) ? static_cast<char>('0' + remainder)\n                 : static_cast<char>('A' + remainder - 10);\n\n        remainders.push_back(c);\n    }\n    while (quotient > 0);\n\n    std::string hex_str;\n    hex_str.reserve(remainders.length());\n\n    for (size_t i = remainders.length(); i > 0; --i)\n    {\n        hex_str.push_back(remainders[i - 1]);\n    }\n\n    return hex_str;\n}\n\n} //namespace Utilities\n} //namespace da4qi4\n\n"
  },
  {
    "path": "src/websocket/connection_websocket.cpp",
    "content": "#include \"daqi/websocket/connection_websocket.hpp\"\n\n#include \"daqi/def/log_def.hpp\"\n\n#include \"daqi/utilities/base64_utilities.hpp\"\n#include \"daqi/utilities/hmac_sha1_utilities.hpp\"\n#include \"daqi/utilities/string_utilities.hpp\"\n\n#include \"daqi/websocket/context_websocket.hpp\"\n\n#include <iostream>\n\nnamespace da4qi4\n{\nnamespace Websocket\n{\n\nnamespace\n{\n\nstd::string make_handshake_http_response(std::string const& key, std::string const& protocol)\n{\n    assert(!key.empty());\n\n    std::string data;\n    data.reserve(512);\n\n    data.append(\"HTTP/1.1 101 Switching Protocols\\r\\n\");\n    data.append(\"Upgrade: websocket\\r\\n\");\n    data.append(\"Connection: Upgrade\\r\\n\");\n    data.append(\"Server: da4qi4\\r\\n\");\n\n    std::string accept_key;\n    accept_key.reserve(128);\n    accept_key.append(key);\n    accept_key.append(\"258EAFA5-E914-47DA-95CA-C5AB0DC85B11\");\n\n    auto digest = Utilities::SHA1(accept_key);\n\n    data.append(\"Sec-WebSocket-Accept: \");\n    data.append(Utilities::Base64Encode(digest.data(), 20));\n    data.append(\"\\r\\n\");\n\n    if (protocol.size())\n    {\n        data.append(\"Sec-WebSocket-Protocol: \");\n        data.append(protocol);\n        data.append(\"\\r\\n\");\n    }\n\n    data.append(\"\\r\\n\");\n    return data;\n}\n\n}\n\nConnection::Connection(size_t ioc_index, net_detail::SocketInterface* socket\n                       , UrlUnderApp&& url, ICHeaders&& headers\n                       , ICCookies&& cookies, EventsHandler* handler)\n    : _socket_ptr(socket)\n    , _url(new UrlUnderApp(std::move(url))), _headers(std::move(headers)), _cookies(std::move(cookies))\n    , _evt_handler(handler)\n    , _last_data_type(0), _error_on_parse(0), _stop_by_self(0)\n    , _ioc_index(ioc_index)\n{\n    _parser.RegistMsgCallback(std::bind(&Connection::on_read_frame, this\n                                        , std::placeholders::_1\n                                        , std::placeholders::_2\n                                        , std::placeholders::_3));\n}\n\nConnection::Ptr Connection::Create(size_t ioc_index, net_detail::SocketInterface* socket\n                                   , UrlUnderApp&& url, ICHeaders&& headers, ICCookies&& cookies\n                                   , EventsHandler* handler)\n{\n    assert(socket != nullptr);\n    return Ptr(new Connection(ioc_index, socket, std::move(url), std::move(headers), std::move(cookies), handler));\n}\n\nstd::string Connection::GetURLPath() const\n{\n    return (!_full_url_path.empty()) ? _full_url_path : (_url ? _url->full : \"\");\n}\n\nvoid Connection::Start(Context ctx, std::string const& key)\n{\n    assert(!key.empty());\n    start_handshake(ctx, key);\n}\n\nFrameType FromWriteDataType(WriteDataType t)\n{\n    switch (t)\n    {\n        case WriteDataType::continuation : return e_continuation;\n\n        case WriteDataType::text : return e_text;\n\n        case WriteDataType::binary : return e_binary;\n    }\n\n    return e_continuation;\n}\n\nvoid Connection::Write(Context ctx, std::string const& data, WriteDataType type, bool finished)\n{\n    auto msg = FrameBuilder().SetFIN(finished).SetFrameType(FromWriteDataType(type)).Build(data);\n    append_write_data(ctx, std::move(msg));\n}\n\nvoid Connection::Stop(Context ctx)\n{\n    _stop_by_self = true;\n    auto msg = FrameBuilder().SetFIN(true).SetFrameType(e_connection_close).Build();\n    append_write_data(ctx, std::move(msg));\n}\n\nvoid Connection::start_handshake(Context ctx, std::string const& key)\n{\n    std::string protocol;\n    auto it = _headers.find(\"Sec-WebSocket-Protocol\");\n\n    if (it != _headers.end())\n    {\n        protocol = it->second;\n    }\n\n    append_write_data(ctx, make_handshake_http_response(key, protocol));\n\n    //duplex operation for read and write:\n    start_read(ctx);\n}\n\nvoid Connection::append_write_data(Context ctx, std::string data)\n{\n    bool lst_is_empty_bef_this_data;\n\n    {\n        std::scoped_lock<std::mutex> lock(_m_4_write);\n        lst_is_empty_bef_this_data = _data_4_write.empty();\n\n        _data_4_write.emplace_back(std::move(data));\n    }\n\n    if (lst_is_empty_bef_this_data)\n    {\n        start_write(ctx);\n    }\n}\n\nvoid Connection::start_write(Context ctx)\n{\n    assert(!_data_4_write.empty());\n\n    _socket_ptr->async_write(*_data_4_write.cbegin(), [ctx, this](errorcode const & ec, std::size_t /*wrote_bytes*/)\n    {\n        if (ec)\n        {\n            if (ec == boost::asio::error::eof)\n            {\n                _evt_handler->OnClose(ctx, EventOn::write_event);\n            }\n            else\n            {\n                log::Server()->error(\"Websocket write error. {}. {}.\", ec.value(), ec.message());\n                _evt_handler->OnError(ctx, EventOn::write_event, ec.value(), ec.message());\n            }\n\n            return;\n        }\n\n        bool have_data_yet;\n\n        {\n            std::scoped_lock<std::mutex> lock(_m_4_write);\n            _data_4_write.pop_front();\n            have_data_yet = !_data_4_write.empty();\n        }\n\n        if (have_data_yet)\n        {\n            this->start_write(ctx);\n        }\n    });\n}\n\nvoid Connection::start_read(Context ctx)\n{\n    _socket_ptr->async_read_some(_buffer_4_read, [ctx, this](errorcode const & ec, std::size_t read_bytes)\n    {\n        if (ec)\n        {\n            if (ec == boost::asio::error::eof)\n            {\n                _evt_handler->OnClose(ctx, EventOn::read_event);\n            }\n            else\n            {\n                log::Server()->error(\"Websocket read error. {}. {}.\", ec.value(), ec.message());\n                _evt_handler->OnError(ctx, EventOn::read_event, ec.value(), ec.message());\n            }\n\n            return;\n        }\n\n        assert(read_bytes <= _buffer_4_read.size());\n\n        if (read_bytes)\n        {\n            _ctx_4_parser_callback = ctx;\n            auto [ok, err] = this->_parser.Parse(_buffer_4_read.data(), static_cast<uint32_t>(read_bytes));\n            _ctx_4_parser_callback.reset();\n\n            if (!ok)\n            {\n                log::Server()->error(\"Parse websocket message fail. {}.\", err);\n                return;\n            }\n        }\n\n        if (!_error_on_parse)\n        {\n            this->start_read(ctx);\n        }\n    });\n\n    return;\n}\n\nvoid Connection::pong(Context ctx)\n{\n    auto response_data = FrameBuilder().SetFrameType(e_pong).SetFIN(true).Build();\n    this->append_write_data(ctx, std::move(response_data));\n}\n\nvoid Connection::on_read_frame(std::string&& data, FrameType ft, bool is_finished_frame)\n{\n    _error_on_parse = 0;\n\n    auto ctx = _ctx_4_parser_callback;\n\n    log::Server()->trace(\"read ws frame-type {}. is-finished {}.\", ft, is_finished_frame);\n\n    switch (ft)\n    {\n        case e_connection_close :\n        {\n            if (!_stop_by_self)\n            {\n                this->Stop(ctx);\n            }\n\n            return;\n        }\n\n        case e_continuation :\n        {\n            break;\n        }\n\n        case e_text :\n        {\n            _last_data_type = e_text;\n            break;\n        }\n\n        case e_binary :\n        {\n            _last_data_type = e_binary;\n            break;\n        }\n\n        case e_ping :\n        {\n            this->pong(ctx);\n            return;\n        }\n\n        default :\n        {\n            _error_on_parse = 1;\n            return;\n        }\n    }\n\n    switch (_last_data_type)\n    {\n        case e_text :\n            _evt_handler->OnText(ctx, std::move(data), is_finished_frame);\n            break;\n\n        case e_binary:\n            _evt_handler->OnBinary(ctx, std::move(data), is_finished_frame);\n            break;\n\n        default:\n            _error_on_parse = 2;\n    }\n}\n\nvoid Connections::Add(Connection::Ptr cnt)\n{\n    assert(_m_ptr != nullptr);\n    assert(!cnt->GetID().empty());\n\n    std::scoped_lock<std::mutex> lock(*_m_ptr);\n    _storage.insert(std::make_pair(cnt->GetID(), cnt));\n}\n\nstd::shared_ptr<Connection> Connections::Get(std::string const& id)\n{\n    assert(_m_ptr != nullptr);\n\n    std::scoped_lock<std::mutex> lock(*_m_ptr);\n    auto it = _storage.find(id);\n\n    if (it == _storage.end())\n    {\n        return nullptr;\n    }\n\n    return it->second.lock();\n}\n\nstd::shared_ptr<Connection> Connections::RandOne()\n{\n    assert(_m_ptr != nullptr);\n\n    std::scoped_lock<std::mutex> lock(*_m_ptr);\n    auto count = _storage.size();\n\n    if (count == 0)\n    {\n        return nullptr;\n    }\n\n    std::map<std::string, std::weak_ptr<Connection>>::iterator it = _storage.begin();\n    auto offset = static_cast<std::size_t>(std::rand()) % count;\n    std::advance(it, offset);\n\n    return it->second.lock();\n}\n\nstd::list<Connection::Ptr> Connections::All()\n{\n    assert(_m_ptr != nullptr);\n\n    std::list<Connection::Ptr> lst;\n\n    {\n        std::scoped_lock<std::mutex> lock(*_m_ptr);\n\n        for (auto it : _storage)\n        {\n            lst.push_back(it.second.lock());\n        }\n    }\n\n    return lst;\n}\n\nstd::list<std::string> Connections::AllID()\n{\n    assert(_m_ptr != nullptr);\n\n    std::list<std::string> lst;\n\n    {\n        std::scoped_lock<std::mutex> lock(*_m_ptr);\n\n        for (auto it : _storage)\n        {\n            lst.push_back(it.first);\n        }\n    }\n\n    return lst;\n}\n\nbool Connections::Remove(std::string const& id)\n{\n    assert(_m_ptr != nullptr);\n    std::scoped_lock<std::mutex> lock(*_m_ptr);\n\n    auto it = _storage.find(id);\n\n    if (it != _storage.end())\n    {\n        _storage.erase(it);\n        return true;\n    }\n\n    return false;\n}\n\nbool Connections::RenameID(std::string const& old_id, std::string const& new_id)\n{\n    assert(_m_ptr != nullptr);\n    std::scoped_lock<std::mutex> lock(*_m_ptr);\n\n    auto it = _storage.find(old_id);\n\n    if (it != _storage.end())\n    {\n        std::shared_ptr<Connection> cnt = it->second.lock();\n        _storage.erase(it);\n\n        if (!cnt)\n        {\n            return false;\n        }\n\n        if (cnt->GetID() != new_id)\n        {\n            cnt->SetID(new_id);\n        }\n\n        _storage[new_id] = cnt;\n        return true;\n    }\n\n    return false;\n}\n\n\n} // namespace Websocket\n} // namespace da4qi4\n"
  },
  {
    "path": "src/websocket/context_websocket.cpp",
    "content": "#include \"daqi/websocket/context_websocket.hpp\"\n\n#include <cstring>\n\n#include \"daqi/application.hpp\"\n\nnamespace da4qi4\n{\nnamespace Websocket\n{\n\nContextIMP::ContextIMP(bool hold_connection_life, Connection::Ptr cnt, ApplicationPtr app)\n    : _hold_connection_life(hold_connection_life), _cnt(cnt), _app(app)\n{\n    assert(_cnt != nullptr);\n    assert(_app != nullptr);\n}\n\nContext ContextIMP::Create(Connection::Ptr cnt, ApplicationPtr app)\n{\n    return Context(new ContextIMP(true, cnt, app));\n}\n\nContext ContextIMP::CreateUnholdConnectionLife(Connection::Ptr cnt, ApplicationPtr app)\n{\n    return Context(new ContextIMP(false, cnt, app));\n}\n\nContextIMP::~ContextIMP()\n{\n    if (_hold_connection_life)\n    {\n        auto fullpath = _cnt->GetURLPath();\n\n        if (!fullpath.empty() && !_cnt->GetID().empty())\n        {\n            _app->RemoveWebSocketConnection(fullpath, UrlFlag::url_full_path, _cnt->GetID());\n        }\n    }\n}\n\nIOC& ContextIMP::IOContext()\n{\n#ifdef HAS_IO_CONTEXT\n    return _cnt->GetSocket().get_executor().context();\n#else\n    return _cnt->GetSocket().get_io_service();\n#endif\n}\n\nsize_t ContextIMP::IOContextIndex() const\n{\n    return _cnt->GetIOContextIndex();\n}\n\nbool operator == (ContextIMP const& o1, ContextIMP const& o2)\n{\n    return (o1._cnt == o2._cnt);\n}\n\nbool operator != (ContextIMP const& o1, ContextIMP const& o2)\n{\n    return !(o1 == o2);\n}\n\nbool ContextIMP::RenameID(std::string const& new_id)\n{\n    return _app->RenameWebSocketConnectionID(_cnt->GetURLPath(), UrlFlag::url_full_path, _cnt->GetID(), new_id);\n}\n\nlog::LoggerPtr ContextIMP::Logger()\n{\n    return _app->GetLogger();\n}\n\nApplication& ContextIMP::App()\n{\n    return *_app;\n}\n\nApplication const& ContextIMP::App() const\n{\n    return *_app;\n}\n\nvoid ContextIMP::SendText(std::string const& str)\n{\n    _cnt->Write(shared_from_this(), str, WriteDataType::text, true);\n}\n\nvoid ContextIMP::SendText(char const* str, std::size_t len)\n{\n    std::size_t sz = (len != static_cast<std::size_t>(-1)) ? len : std::strlen(str);\n    std::string s(str, sz);\n    SendText(s);\n}\n\nvoid ContextIMP::SendFirstText(std::string const& str)\n{\n    _cnt->Write(shared_from_this(), str, WriteDataType::text, false);\n}\nvoid ContextIMP::SendNextText(std::string const& str)\n{\n    _cnt->Write(shared_from_this(), str, WriteDataType::continuation, false);\n}\nvoid ContextIMP::SendLastText(std::string const& str)\n{\n    _cnt->Write(shared_from_this(), str, WriteDataType::continuation, true);\n}\n\nvoid ContextIMP::SendFirstText(char const* str, std::size_t len)\n{\n    std::size_t sz = (len != static_cast<std::size_t>(-1)) ? len : std::strlen(str);\n    std::string s(str, sz);\n    SendFirstText(s);\n}\nvoid ContextIMP::SendNextText(char const* str, std::size_t len)\n{\n    std::size_t sz = (len != static_cast<std::size_t>(-1)) ? len : std::strlen(str);\n    std::string s(str, sz);\n    SendNextText(s);\n}\nvoid ContextIMP::SendLastText(char const* str, std::size_t len)\n{\n    std::size_t sz = (len != static_cast<std::size_t>(-1)) ? len : std::strlen(str);\n    std::string s(str, sz);\n    SendLastText(s);\n}\n\nvoid ContextIMP::SendBinary(std::vector<std::int8_t> const& data)\n{\n    std::string s(data.cbegin(), data.cend());\n    _cnt->Write(shared_from_this(), s, WriteDataType::binary, true);\n}\n\nvoid ContextIMP::SendBinary(char const* data, std::size_t size)\n{\n    std::string s(data, size);\n    _cnt->Write(shared_from_this(), s, WriteDataType::binary, true);\n}\n\nvoid ContextIMP::SendFirstBinary(std::vector<std::int8_t> const& data)\n{\n    std::string s(data.cbegin(), data.cend());\n    _cnt->Write(shared_from_this(), s, WriteDataType::binary, false);\n}\nvoid ContextIMP::SendNextBinary(std::vector<std::int8_t> const& data)\n{\n    std::string s(data.cbegin(), data.cend());\n    _cnt->Write(shared_from_this(), s, WriteDataType::continuation, false);\n}\nvoid ContextIMP::SendLastBinary(std::vector<std::int8_t> const& data)\n{\n    std::string s(data.cbegin(), data.cend());\n    _cnt->Write(shared_from_this(), s, WriteDataType::continuation, true);\n}\n\nvoid ContextIMP::SendFirstBinary(char const* data, std::size_t size)\n{\n    std::string s(data, size);\n    _cnt->Write(shared_from_this(), s, WriteDataType::binary, false);\n}\nvoid ContextIMP::SendNextBinary(char const* data, std::size_t size)\n{\n    std::string s(data, size);\n    _cnt->Write(shared_from_this(), s, WriteDataType::continuation, false);\n}\nvoid ContextIMP::SendLastBinary(char const* data, std::size_t size)\n{\n    std::string s(data, size);\n    _cnt->Write(shared_from_this(), s, WriteDataType::continuation, true);\n}\n\nContext ContextIMP::OtherOne(std::string const& id)\n{\n    if (id == _cnt->GetID())\n    {\n        return this->shared_from_this();\n    }\n\n    auto cnt = _app->WebsocketConnection(_cnt->GetURLPath(), UrlFlag::url_full_path, id);\n    return cnt ? CreateUnholdConnectionLife(cnt, _app) : nullptr;\n}\n\nContext ContextIMP::OtherOne(std::string const& url, UrlFlag url_flag, std::string const& id)\n{\n    if (id == _cnt->GetID() && (MakesureFullUrlPath(url, url_flag, _app->GetUrlRoot()) == _cnt->GetURLPath()))\n    {\n        return this->shared_from_this();\n    }\n\n    auto cnt = _app->WebsocketConnection(url, url_flag, id);\n    return cnt ? CreateUnholdConnectionLife(cnt, _app) : nullptr;\n}\n\nContext ContextIMP::OtherOne(ApplicationPtr other_app, std::string const& url, UrlFlag url_flag, std::string const& id)\n{\n    if ((other_app == _app) && (id == _cnt->GetID())\n        && (MakesureFullUrlPath(url, url_flag, _app->GetUrlRoot()) == _cnt->GetURLPath()))\n    {\n        return this->shared_from_this();\n    }\n\n    auto cnt = other_app->WebsocketConnection(url, url_flag, id);\n    return cnt ? CreateUnholdConnectionLife(cnt, other_app) : nullptr;\n}\n\nContextList::ContextList(ApplicationPtr app, std::string const& url, UrlFlag flag)\n    : _app(app), _cnt_list(_app->AllWebSocketConnections(url, flag))\n{\n}\n\nContextList::ContextList(Context src_ctx, std::string const& url, UrlFlag flag)\n    : _app(src_ctx->AppPtr()), _cnt_list(_app->AllWebSocketConnections(url, flag))\n{\n}\n\nContextList::ContextList(Context src_ctx)\n    : _app(src_ctx->AppPtr()), _cnt_list(_app->AllWebSocketConnections(src_ctx->URLPath(), UrlFlag::url_full_path))\n{\n}\n\nContextList::iterator ContextList::begin()\n{\n    return iterator(_cnt_list.begin(), _app);\n}\n\nContextList::iterator ContextList::end()\n{\n    std::weak_ptr<Application> nullapp;\n    return iterator(_cnt_list.end(), nullapp);\n}\n\nContextList::const_iterator ContextList::cbegin() const\n{\n    return const_iterator(_cnt_list.cbegin(), _app);\n}\n\nContextList::const_iterator ContextList::cend() const\n{\n    std::weak_ptr<Application> nullapp;\n    return const_iterator(_cnt_list.cend(), nullapp);\n}\n\n} // namespace Websocket\n} // namespace da4qi4\n"
  },
  {
    "path": "src/websocket/frame_websocket.cpp",
    "content": "#include \"daqi/websocket/frame_websocket.hpp\"\n\n#include <cstring>\n\nnamespace da4qi4\n{\nnamespace Websocket\n{\n\nstd::string FrameBuilder::Build(char const* data, size_t len)\n{\n    std::string buffer;\n    size_t externded_payload_len = (len <= 125 ? 0 : (len <= 65535 ? 2 : 8));\n    size_t mask_key_len = ((len && _frame_header.MASK) ? 4 : 0);\n\n    auto frame_size = static_cast<size_t>(2 + externded_payload_len + mask_key_len + len);\n    buffer.resize(frame_size);\n\n    uint8_t* ptr = reinterpret_cast<uint8_t*>(buffer.data());\n    uint64_t offset = 0;\n\n    ptr[0] |= _frame_header.FIN;\n    ptr[0] |= _frame_header.OPCODE;\n\n    if (len)\n    {\n        ptr[1] |= _frame_header.MASK;\n    }\n\n    ++offset;\n\n    if (len <= 125)\n    {\n        ptr[offset++] |= static_cast<unsigned char>(len);\n    }\n    else if (len <= 65535)\n    {\n        ptr[offset++] |= 126;\n        ptr[offset++] = static_cast<unsigned char>((len >> 8) & 0xFF);\n        ptr[offset++] = len & 0xFF;\n    }\n    else\n    {\n        ptr[offset++] |= 127;\n        ptr[offset++] = static_cast<unsigned char>(((static_cast<uint64_t>(len) >> 56) & 0xff));\n        ptr[offset++] = static_cast<unsigned char>(((static_cast<uint64_t>(len) >> 48) & 0xff));\n        ptr[offset++] = static_cast<unsigned char>(((static_cast<uint64_t>(len) >> 40) & 0xff));\n        ptr[offset++] = static_cast<unsigned char>(((static_cast<uint64_t>(len) >> 32) & 0xff));\n        ptr[offset++] = static_cast<unsigned char>(((static_cast<uint64_t>(len) >> 24) & 0xff));\n        ptr[offset++] = static_cast<unsigned char>(((static_cast<uint64_t>(len) >> 16) & 0xff));\n        ptr[offset++] = static_cast<unsigned char>(((static_cast<uint64_t>(len) >> 8) & 0xff));\n        ptr[offset++] = static_cast<unsigned char>((static_cast<uint64_t>(len) & 0xff));\n    }\n\n    if (!len || !data)\n    {\n        return buffer;\n    }\n\n    if (_frame_header.MASK)\n    {\n        int mask_key = static_cast<int>(_frame_header.MASKING_KEY);\n\n        ptr[offset++] = static_cast<unsigned char>(((mask_key >> 24) & 0xff));\n        ptr[offset++] = static_cast<unsigned char>(((mask_key >> 16) & 0xff));\n        ptr[offset++] = static_cast<unsigned char>(((mask_key >> 8) & 0xff));\n        ptr[offset++] = static_cast<unsigned char>(((mask_key) & 0xff));\n\n        unsigned char* mask = ptr + offset - 4;\n\n        for (uint32_t i = 0; i < len; ++i)\n        {\n            ptr[offset++] = static_cast<uint8_t>(data[i] ^ mask[i % 4]);\n        }\n    }\n    else\n    {\n        std::copy(data, data + len, reinterpret_cast<char*>(ptr + offset));\n        offset += len;\n    }\n\n    assert(offset == frame_size);\n    return buffer;\n}\n\nvoid FrameParser::reset()\n{\n    _parser_step = e_fixed_header;\n    _masking_key_pos = 0;\n    _payload_len_offset = 0;\n    _payload.clear();\n\n    memset(&_frame_header, 0, sizeof(_frame_header));\n}\n\nvoid FrameParser::move_reset(FrameParser&& parser)\n{\n    if (&parser == this)\n    {\n        return;\n    }\n\n    _parser_step = parser._parser_step;\n    _payload_len_offset = parser._payload_len_offset;\n    _masking_key_pos = parser._masking_key_pos;\n    _payload = std::move(parser._payload);\n    _frame_header = std::move(parser._frame_header);\n    _msb_cb = std::move(parser._msb_cb);\n}\n\nuint32_t FrameParser::parse_fixed_header(const char* data)\n{\n    const uint8_t* ptr = reinterpret_cast<const uint8_t*>(data);\n    memset(&_frame_header, 0, sizeof(_frame_header));\n\n    _payload_len_offset = 0;\n\n    _frame_header.FIN = ptr[0] & 0xf0;\n    _frame_header.RSV1 = ptr[0] & 0x40;\n    _frame_header.RSV2 = ptr[0] & 0x20;\n    _frame_header.RSV3 = ptr[0] & 0x10;\n    _frame_header.OPCODE = static_cast<FrameType>(ptr[0] & 0x0f);\n    _parser_step = e_payload_len;\n\n    return 1U;\n}\n\nuint32_t FrameParser::parse_payload_len(const char* data)\n{\n    const uint8_t* ptr = reinterpret_cast<const uint8_t*>(data);\n\n    _frame_header.MASK = ptr[0] & 0x80;\n    _frame_header.PAYLOAD_LEN = ptr[0] & (0x7f);\n\n    if (_frame_header.PAYLOAD_LEN <= 125)\n    {\n        _frame_header.PAYLOAD_REALY_LEN = _frame_header.PAYLOAD_LEN;\n\n        if (_frame_header.MASK)\n        {\n            _parser_step = e_masking_key;\n        }\n        else\n        {\n            _parser_step = e_payload_data;\n        }\n    }\n    else if (_frame_header.PAYLOAD_LEN > 125)\n    {\n        _parser_step = e_extened_payload_len;\n    }\n\n    if (_frame_header.PAYLOAD_LEN == 0)\n    {\n        assert(_msb_cb);\n        _msb_cb(\"\", _frame_header.OPCODE, !!_frame_header.FIN);\n        reset();\n    }\n\n    return 1U;\n}\n\nuint32_t FrameParser::parse_extened_payload_len(const char* data, uint32_t len)\n{\n    uint32_t offset = 0;\n    const uint8_t* ptr = reinterpret_cast<const uint8_t*>(data);\n\n    if (_frame_header.PAYLOAD_LEN == 126)\n    {\n        //Extended payload length is 16bit!\n        uint32_t min_len = std::min<uint32_t>\n                           (2 - _payload_len_offset, len - offset);\n\n        memcpy(&_frame_header.EXT_PAYLOAD_LEN_16,\n               ptr + offset, min_len);\n        offset += min_len;\n        _payload_len_offset += min_len;\n\n        if (_payload_len_offset == 2)\n        {\n            decode_extened_payload_len();\n        }\n    }\n    else if (_frame_header.PAYLOAD_LEN == 127)\n    {\n        //Extended payload length is 64bit!\n        auto min_len = std::min<uint32_t>(8 - _payload_len_offset, len - offset);\n        memcpy(&_frame_header.EXT_PAYLOAD_LEN_64, ptr + offset, static_cast<size_t>(min_len));\n        offset += min_len;\n        _payload_len_offset += min_len;\n\n        if (_payload_len_offset == 8)\n        {\n            decode_extened_payload_len();\n        }\n    }\n\n    return offset;\n}\n\nvoid FrameParser::decode_extened_payload_len()\n{\n    if (_frame_header.PAYLOAD_LEN == 126)\n    {\n        uint16_t tmp = _frame_header.EXT_PAYLOAD_LEN_16;\n        uint8_t* buffer_ = reinterpret_cast<uint8_t*>(&tmp);\n        _frame_header.PAYLOAD_REALY_LEN =\n                    static_cast<uint64_t>(\n                                (static_cast<uint16_t>(buffer_[0]) << 8) | static_cast<uint16_t>(buffer_[1]));\n\n    }\n    else if (_frame_header.PAYLOAD_LEN == 127)\n    {\n        uint64_t tmp = _frame_header.EXT_PAYLOAD_LEN_64;\n        uint8_t* buffer_ = reinterpret_cast<uint8_t*>(&tmp);\n        _frame_header.PAYLOAD_REALY_LEN =\n                    (static_cast<uint64_t>(buffer_[0]) << 56) |\n                    (static_cast<uint64_t>(buffer_[1]) << 48) |\n                    (static_cast<uint64_t>(buffer_[2]) << 40) |\n                    (static_cast<uint64_t>(buffer_[3]) << 32) |\n                    (static_cast<uint64_t>(buffer_[4]) << 24) |\n                    (static_cast<uint64_t>(buffer_[5]) << 16) |\n                    (static_cast<uint64_t>(buffer_[6]) << 8) |\n                    static_cast<uint64_t>(buffer_[7]);\n    }\n\n    if (_frame_header.MASK)\n    {\n        _parser_step = e_masking_key;\n    }\n    else\n    {\n        _parser_step = e_payload_data;\n    }\n}\n\nuint32_t FrameParser::parse_masking_key(const char* data, uint32_t len)\n{\n    const uint8_t* ptr = reinterpret_cast<const uint8_t*>(data);\n    auto min = std::min<uint32_t>(4 - _masking_key_pos, len);\n\n    if (_parser_step == e_masking_key)\n    {\n        memcpy(&_frame_header.MASKING_KEY, ptr, static_cast<size_t>(min));\n\n        _masking_key_pos += min;\n\n        if (_masking_key_pos == 4)\n        {\n            _parser_step = e_payload_data;\n        }\n    }\n\n    return min;\n}\n\nuint32_t FrameParser::parse_payload(const char* data, uint32_t len)\n{\n    if (_payload.empty() && _frame_header.PAYLOAD_REALY_LEN > 0)\n    {\n        _payload.reserve(static_cast<size_t>(_frame_header.PAYLOAD_REALY_LEN));\n    }\n\n    auto remain = static_cast<uint32_t>(_frame_header.PAYLOAD_REALY_LEN) - static_cast<uint32_t>(_payload.size());\n    auto min_len = std::min<uint32_t>(remain, len);\n\n    if (_frame_header.MASK)\n    {\n        unsigned char* mask = reinterpret_cast<unsigned char*>(&_frame_header.MASKING_KEY);\n\n        for (size_t i = 0; i < min_len; i++)\n        {\n            _payload.push_back(static_cast<char>(data[i] ^ mask[i % 4]));\n        }\n    }\n    else\n    {\n        _payload.append(data, min_len);\n    }\n\n    if (_payload.size() == _frame_header.PAYLOAD_REALY_LEN)\n    {\n        assert(_msb_cb);\n\n        _msb_cb(std::move(_payload), _frame_header.OPCODE, !!_frame_header.FIN);\n\n        reset();\n    }\n\n    return min_len;\n}\n\nstd::pair<bool, std::string> FrameParser::Parse(void const* data, uint32_t len)\n{\n    assert(data != nullptr && len > 0);\n\n    uint32_t offset = 0;\n    uint32_t remain_len = len;\n\n    try\n    {\n        do\n        {\n            if (_parser_step == e_fixed_header && remain_len)\n            {\n                offset += parse_fixed_header(static_cast<char const*>(data) + offset);\n                remain_len = len - offset;\n            }\n\n            if (_parser_step == e_payload_len && remain_len)\n            {\n                offset += parse_payload_len(static_cast<char const*>(data) + offset);\n                remain_len = len - offset;\n            }\n\n            if (_parser_step == e_extened_payload_len && remain_len)\n            {\n                offset += parse_extened_payload_len(static_cast<char const*>(data) + offset, remain_len);\n                remain_len = len - offset;\n            }\n\n            if (_parser_step == e_masking_key && remain_len)\n            {\n                offset += parse_masking_key(static_cast<char const*>(data) + offset, remain_len);\n                remain_len = len - offset;\n            }\n\n            if (_parser_step == e_payload_data && remain_len)\n            {\n                offset += parse_payload(static_cast<char const*>(data) + offset, remain_len);\n                remain_len = len - offset;\n            }\n\n        }\n        while (offset < len);\n    }\n    catch (std::exception const& e)\n    {\n        return {false, e.what()};\n    }\n    catch (...)\n    {\n        return {false, \"unknown exception.\"};\n    }\n\n    return {true, \"\"};\n}\n\n} // namespace Websocket\n} // namespace da4qi4\n"
  },
  {
    "path": "src/websocket/handler_websocket.cpp",
    "content": "#include \"daqi/websocket/handler_websocket.hpp\"\n\nnamespace da4qi4\n{\nnamespace Websocket\n{\n\nbool EventHandleFunctor::OnOpen(Context ctx)\n{\n    return (DoOnOpen) ? DoOnOpen(ctx) : true;\n}\n\nvoid EventHandleFunctor::OnText(Context ctx, std::string&& data, bool is_finished)\n{\n    if (DoOnText)\n    {\n        DoOnText(ctx, std::move(data), is_finished);\n    }\n}\n\nvoid EventHandleFunctor::OnBinary(Context ctx, std::string&& data, bool is_finished)\n{\n    if (DoOnBinary)\n    {\n        DoOnBinary(ctx, std::move(data), is_finished);\n    }\n}\n\nvoid EventHandleFunctor::OnError(Context ctx, EventOn evt, int code, std::string const& msg)\n{\n    if (DoOnError)\n    {\n        DoOnError(ctx, evt, code, msg);\n    }\n}\n\nvoid EventHandleFunctor::OnClose(Context ctx, EventOn evt)\n{\n    if (DoOnClose)\n    {\n        DoOnClose(ctx, evt);\n    }\n}\n\nEventsHandler* EventHandleFunctor::operator()(void)\n{\n    return new EventHandleFunctor(*this);\n}\n} //namespace Websocket\n} //namespace da4qi4\n"
  }
]